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