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