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