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