• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "Request.h"
9 
10 #include "SkPictureRecorder.h"
11 #include "SkPM4fPriv.h"
12 #include "picture_utils.h"
13 #include "sk_tool_utils.h"
14 
15 using namespace sk_gpu_test;
16 
17 static int kDefaultWidth = 1920;
18 static int kDefaultHeight = 1080;
19 static int kMaxWidth = 8192;
20 static int kMaxHeight = 8192;
21 
22 
Request(SkString rootUrl)23 Request::Request(SkString rootUrl)
24     : fUploadContext(nullptr)
25     , fUrlDataManager(rootUrl)
26     , fGPUEnabled(false)
27     , fOverdraw(false)
28     , fColorMode(0) {
29     // create surface
30 #if SK_SUPPORT_GPU
31     GrContextOptions grContextOpts;
32     fContextFactory = new GrContextFactory(grContextOpts);
33 #else
34     fContextFactory = nullptr;
35 #endif
36 }
37 
~Request()38 Request::~Request() {
39 #if SK_SUPPORT_GPU
40     if (fContextFactory) {
41         delete fContextFactory;
42     }
43 #endif
44 }
45 
getBitmapFromCanvas(SkCanvas * canvas)46 SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
47     SkBitmap* bmp = new SkBitmap();
48     if (!bmp->tryAllocPixels(canvas->imageInfo()) || !canvas->readPixels(*bmp, 0, 0)) {
49         fprintf(stderr, "Can't read pixels\n");
50         delete bmp;
51         return nullptr;
52     }
53     return bmp;
54 }
55 
writeCanvasToPng(SkCanvas * canvas)56 sk_sp<SkData> Request::writeCanvasToPng(SkCanvas* canvas) {
57     // capture pixels
58     std::unique_ptr<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
59     SkASSERT(bmp);
60 
61     // Convert to format suitable for PNG output
62     sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
63     SkASSERT(encodedBitmap.get());
64 
65     // write to an opaque png (black background)
66     SkDynamicMemoryWStream buffer;
67     SkDrawCommand::WritePNG(encodedBitmap->bytes(), bmp->width(), bmp->height(),
68                             buffer, true);
69     return buffer.detachAsData();
70 }
71 
getCanvas()72 SkCanvas* Request::getCanvas() {
73 #if SK_SUPPORT_GPU
74     GrContextFactory* factory = fContextFactory;
75     GLTestContext* gl = factory->getContextInfo(GrContextFactory::kGL_ContextType,
76             GrContextFactory::ContextOverrides::kNone).glContext();
77     if (!gl) {
78         gl = factory->getContextInfo(GrContextFactory::kGLES_ContextType,
79                                      GrContextFactory::ContextOverrides::kNone).glContext();
80     }
81     if (gl) {
82         gl->makeCurrent();
83     }
84 #endif
85     SkASSERT(fDebugCanvas);
86 
87     // create the appropriate surface if necessary
88     if (!fSurface) {
89         this->enableGPU(fGPUEnabled);
90     }
91     SkCanvas* target = fSurface->getCanvas();
92     return target;
93 }
94 
drawToCanvas(int n,int m)95 void Request::drawToCanvas(int n, int m) {
96     SkCanvas* target = this->getCanvas();
97     fDebugCanvas->drawTo(target, n, m);
98 }
99 
drawToPng(int n,int m)100 sk_sp<SkData> Request::drawToPng(int n, int m) {
101     //fDebugCanvas->setOverdrawViz(true);
102     this->drawToCanvas(n, m);
103     //fDebugCanvas->setOverdrawViz(false);
104     return writeCanvasToPng(this->getCanvas());
105 }
106 
writeOutSkp()107 sk_sp<SkData> Request::writeOutSkp() {
108     // Playback into picture recorder
109     SkIRect bounds = this->getBounds();
110     SkPictureRecorder recorder;
111     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bounds.width()),
112                                                SkIntToScalar(bounds.height()));
113 
114     fDebugCanvas->draw(canvas);
115 
116     return recorder.finishRecordingAsPicture()->serialize();
117 }
118 
getContext()119 GrContext* Request::getContext() {
120 #if SK_SUPPORT_GPU
121     GrContext* result = fContextFactory->get(GrContextFactory::kGL_ContextType,
122                                              GrContextFactory::ContextOverrides::kNone);
123     if (!result) {
124         result = fContextFactory->get(GrContextFactory::kGLES_ContextType,
125                                       GrContextFactory::ContextOverrides::kNone);
126     }
127     return result;
128 #else
129     return nullptr;
130 #endif
131 }
132 
getBounds()133 SkIRect Request::getBounds() {
134     SkIRect bounds;
135     if (fPicture) {
136         bounds = fPicture->cullRect().roundOut();
137         if (fGPUEnabled) {
138 #if SK_SUPPORT_GPU
139             int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
140             bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
141                                      SkTMin(bounds.height(), maxRTSize));
142 #endif
143         }
144     } else {
145         bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
146     }
147 
148     // We clip to kMaxWidth / kMaxHeight for performance reasons.
149     // TODO make this configurable
150     bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kMaxWidth),
151                              SkTMin(bounds.height(), kMaxHeight));
152     return bounds;
153 }
154 
155 namespace {
156 
157 struct ColorAndProfile {
158     SkColorType fColorType;
159     bool fSRGB;
160 };
161 
162 ColorAndProfile ColorModes[] = {
163     { kN32_SkColorType,      false },
164     { kN32_SkColorType,       true },
165     { kRGBA_F16_SkColorType,  true },
166 };
167 
168 }
169 
createCPUSurface()170 SkSurface* Request::createCPUSurface() {
171     SkIRect bounds = this->getBounds();
172     ColorAndProfile cap = ColorModes[fColorMode];
173     auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
174                     ? SkColorSpace::MakeSRGBLinear()
175                     : SkColorSpace::MakeSRGB();
176     SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
177                                          kPremul_SkAlphaType, cap.fSRGB ? colorSpace : nullptr);
178     return SkSurface::MakeRaster(info).release();
179 }
180 
createGPUSurface()181 SkSurface* Request::createGPUSurface() {
182     GrContext* context = this->getContext();
183     SkIRect bounds = this->getBounds();
184     ColorAndProfile cap = ColorModes[fColorMode];
185     auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
186                     ? SkColorSpace::MakeSRGBLinear()
187                     : SkColorSpace::MakeSRGB();
188     SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
189                                          kPremul_SkAlphaType, cap.fSRGB ? colorSpace: nullptr);
190     SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info).release();
191     return surface;
192 }
193 
setOverdraw(bool enable)194 bool Request::setOverdraw(bool enable) {
195     fOverdraw = enable;
196     return true;
197 }
198 
setColorMode(int mode)199 bool Request::setColorMode(int mode) {
200     fColorMode = mode;
201     return enableGPU(fGPUEnabled);
202 }
203 
enableGPU(bool enable)204 bool Request::enableGPU(bool enable) {
205     if (enable) {
206         SkSurface* surface = this->createGPUSurface();
207         if (surface) {
208             fSurface.reset(surface);
209             fGPUEnabled = true;
210 
211             // When we switch to GPU, there seems to be some mystery draws in the canvas.  So we
212             // draw once to flush the pipe
213             // TODO understand what is actually happening here
214             if (fDebugCanvas) {
215                 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
216                 this->getCanvas()->flush();
217             }
218 
219             return true;
220         }
221         return false;
222     }
223     fSurface.reset(this->createCPUSurface());
224     fGPUEnabled = false;
225     return true;
226 }
227 
initPictureFromStream(SkStream * stream)228 bool Request::initPictureFromStream(SkStream* stream) {
229     // parse picture from stream
230     fPicture = SkPicture::MakeFromStream(stream);
231     if (!fPicture) {
232         fprintf(stderr, "Could not create picture from stream.\n");
233         return false;
234     }
235 
236     // reinitialize canvas with the new picture dimensions
237     this->enableGPU(fGPUEnabled);
238 
239     // pour picture into debug canvas
240     SkIRect bounds = this->getBounds();
241     fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
242     fDebugCanvas->drawPicture(fPicture);
243 
244     // for some reason we need to 'flush' the debug canvas by drawing all of the ops
245     fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
246     this->getCanvas()->flush();
247     return true;
248 }
249 
getJsonOps(int n)250 sk_sp<SkData> Request::getJsonOps(int n) {
251     SkCanvas* canvas = this->getCanvas();
252     Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
253     root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
254     root["drawGpuOpBounds"] = Json::Value(fDebugCanvas->getDrawGpuOpBounds());
255     root["colorMode"] = Json::Value(fColorMode);
256     SkDynamicMemoryWStream stream;
257     stream.writeText(Json::FastWriter().write(root).c_str());
258 
259     return stream.detachAsData();
260 }
261 
getJsonOpList(int n)262 sk_sp<SkData> Request::getJsonOpList(int n) {
263     SkCanvas* canvas = this->getCanvas();
264     SkASSERT(fGPUEnabled);
265 
266     Json::Value result = fDebugCanvas->toJSONOpList(n, canvas);
267 
268     SkDynamicMemoryWStream stream;
269     stream.writeText(Json::FastWriter().write(result).c_str());
270 
271     return stream.detachAsData();
272 }
273 
getJsonInfo(int n)274 sk_sp<SkData> Request::getJsonInfo(int n) {
275     // drawTo
276     sk_sp<SkSurface> surface(this->createCPUSurface());
277     SkCanvas* canvas = surface->getCanvas();
278 
279     // TODO this is really slow and we should cache the matrix and clip
280     fDebugCanvas->drawTo(canvas, n);
281 
282     // make some json
283     SkMatrix vm = fDebugCanvas->getCurrentMatrix();
284     SkIRect clip = fDebugCanvas->getCurrentClip();
285     Json::Value info(Json::objectValue);
286     info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
287     info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
288 
289     std::string json = Json::FastWriter().write(info);
290 
291     // We don't want the null terminator so strlen is correct
292     return SkData::MakeWithCopy(json.c_str(), strlen(json.c_str()));
293 }
294 
getPixel(int x,int y)295 SkColor Request::getPixel(int x, int y) {
296     SkCanvas* canvas = this->getCanvas();
297     canvas->flush();
298     std::unique_ptr<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
299     SkASSERT(bitmap);
300 
301     // Convert to format suitable for inspection
302     sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
303     SkASSERT(encodedBitmap);
304 
305     const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
306     SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
307     return result;
308 }
309