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