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