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