blob: 6081c05c74e077cf4489335935d052e6cdae93ca [file] [log] [blame]
joshualitt4dcbe432016-02-25 10:50:28 -08001/*
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 "Request.h"
9
joshualitte0449cf2016-03-09 10:07:02 -080010#include "SkPictureRecorder.h"
brianosman312aa6a2016-04-19 12:47:54 -070011#include "SkPM4fPriv.h"
brianosman78312952016-04-19 10:16:53 -070012#include "picture_utils.h"
Hal Canarydb683012016-11-23 08:55:18 -070013#include "sk_tool_utils.h"
joshualitt4dcbe432016-02-25 10:50:28 -080014
bsalomon3724e572016-03-30 18:56:19 -070015using namespace sk_gpu_test;
16
joshualittae47aee2016-03-10 13:29:36 -080017static int kDefaultWidth = 1920;
18static int kDefaultHeight = 1080;
jcgregorio9a7acdc2016-06-30 07:54:14 -070019static int kMaxWidth = 8192;
20static int kMaxHeight = 8192;
joshualittae47aee2016-03-10 13:29:36 -080021
joshualitt4dcbe432016-02-25 10:50:28 -080022
joshualittee5348b2016-02-26 08:36:25 -080023Request::Request(SkString rootUrl)
24 : fUploadContext(nullptr)
25 , fUrlDataManager(rootUrl)
brianosman78312952016-04-19 10:16:53 -070026 , fGPUEnabled(false)
Ben Wagnerc03e1c52016-10-17 15:20:02 -040027 , fOverdraw(false)
brianosman78312952016-04-19 10:16:53 -070028 , fColorMode(0) {
joshualittee5348b2016-02-26 08:36:25 -080029 // create surface
joshualitt40836102016-03-11 11:45:53 -080030#if SK_SUPPORT_GPU
joshualittee5348b2016-02-26 08:36:25 -080031 GrContextOptions grContextOpts;
joshualitt40836102016-03-11 11:45:53 -080032 fContextFactory = new GrContextFactory(grContextOpts);
33#else
34 fContextFactory = nullptr;
35#endif
36}
37
38Request::~Request() {
39#if SK_SUPPORT_GPU
40 if (fContextFactory) {
41 delete fContextFactory;
42 }
43#endif
joshualittee5348b2016-02-26 08:36:25 -080044}
45
joshualitt4dcbe432016-02-25 10:50:28 -080046SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
47 SkBitmap* bmp = new SkBitmap();
Mike Reed12e946b2017-04-17 10:53:29 -040048 if (!bmp->tryAllocPixels(canvas->imageInfo()) || !canvas->readPixels(*bmp, 0, 0)) {
joshualitt4dcbe432016-02-25 10:50:28 -080049 fprintf(stderr, "Can't read pixels\n");
Mike Reed12e946b2017-04-17 10:53:29 -040050 delete bmp;
joshualitt4dcbe432016-02-25 10:50:28 -080051 return nullptr;
52 }
53 return bmp;
54}
55
bungeman38d909e2016-08-02 14:40:46 -070056sk_sp<SkData> Request::writeCanvasToPng(SkCanvas* canvas) {
joshualitt4dcbe432016-02-25 10:50:28 -080057 // capture pixels
Ben Wagner145dbcd2016-11-03 14:40:50 -040058 std::unique_ptr<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
joshualitt4dcbe432016-02-25 10:50:28 -080059 SkASSERT(bmp);
60
brianosman78312952016-04-19 10:16:53 -070061 // Convert to format suitable for PNG output
62 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
63 SkASSERT(encodedBitmap.get());
64
msaretta5cf4f42016-06-30 10:06:51 -070065 // write to an opaque png (black background)
joshualitt4dcbe432016-02-25 10:50:28 -080066 SkDynamicMemoryWStream buffer;
halcanarya73d76a2016-10-17 13:19:02 -070067 SkDrawCommand::WritePNG(encodedBitmap->bytes(), bmp->width(), bmp->height(),
msaretta5cf4f42016-06-30 10:06:51 -070068 buffer, true);
reed42943c82016-09-12 12:01:44 -070069 return buffer.detachAsData();
joshualitt4dcbe432016-02-25 10:50:28 -080070}
71
72SkCanvas* Request::getCanvas() {
joshualitt40836102016-03-11 11:45:53 -080073#if SK_SUPPORT_GPU
joshualitt4dcbe432016-02-25 10:50:28 -080074 GrContextFactory* factory = fContextFactory;
Brian Salomon6405e712017-03-20 08:54:16 -040075 GLTestContext* gl = factory->getContextInfo(GrContextFactory::kGL_ContextType,
76 GrContextFactory::ContextOverrides::kNone).glContext();
77 if (!gl) {
78 gl = factory->getContextInfo(GrContextFactory::kGLES_ContextType,
79 GrContextFactory::ContextOverrides::kNone).glContext();
80 }
ethannicholas2ec06c92016-06-13 10:20:52 -070081 if (gl) {
82 gl->makeCurrent();
83 }
joshualitt40836102016-03-11 11:45:53 -080084#endif
joshualitt4dcbe432016-02-25 10:50:28 -080085 SkASSERT(fDebugCanvas);
joshualitte0449cf2016-03-09 10:07:02 -080086
87 // create the appropriate surface if necessary
88 if (!fSurface) {
89 this->enableGPU(fGPUEnabled);
90 }
joshualitt4dcbe432016-02-25 10:50:28 -080091 SkCanvas* target = fSurface->getCanvas();
92 return target;
93}
94
joshualitt46b301d2016-03-02 08:32:37 -080095void Request::drawToCanvas(int n, int m) {
joshualitt4dcbe432016-02-25 10:50:28 -080096 SkCanvas* target = this->getCanvas();
joshualitt46b301d2016-03-02 08:32:37 -080097 fDebugCanvas->drawTo(target, n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080098}
99
bungeman38d909e2016-08-02 14:40:46 -0700100sk_sp<SkData> Request::drawToPng(int n, int m) {
Ben Wagnerc03e1c52016-10-17 15:20:02 -0400101 //fDebugCanvas->setOverdrawViz(true);
joshualitt46b301d2016-03-02 08:32:37 -0800102 this->drawToCanvas(n, m);
Ben Wagnerc03e1c52016-10-17 15:20:02 -0400103 //fDebugCanvas->setOverdrawViz(false);
joshualitt4dcbe432016-02-25 10:50:28 -0800104 return writeCanvasToPng(this->getCanvas());
105}
106
bungeman38d909e2016-08-02 14:40:46 -0700107sk_sp<SkData> Request::writeOutSkp() {
joshualitte0449cf2016-03-09 10:07:02 -0800108 // Playback into picture recorder
joshualittae47aee2016-03-10 13:29:36 -0800109 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800110 SkPictureRecorder recorder;
brianosman82996b82016-04-20 10:52:54 -0700111 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bounds.width()),
112 SkIntToScalar(bounds.height()));
joshualitte0449cf2016-03-09 10:07:02 -0800113
114 fDebugCanvas->draw(canvas);
115
Mike Reedef038482017-12-16 08:41:28 -0500116 return recorder.finishRecordingAsPicture()->serialize();
joshualitte0449cf2016-03-09 10:07:02 -0800117}
118
joshualittae47aee2016-03-10 13:29:36 -0800119GrContext* Request::getContext() {
joshualitt40836102016-03-11 11:45:53 -0800120#if SK_SUPPORT_GPU
Brian Salomon6405e712017-03-20 08:54:16 -0400121 GrContext* result = fContextFactory->get(GrContextFactory::kGL_ContextType,
csmartdaltone812d492017-02-21 12:36:05 -0700122 GrContextFactory::ContextOverrides::kNone);
ethannicholas2ec06c92016-06-13 10:20:52 -0700123 if (!result) {
Brian Salomon6405e712017-03-20 08:54:16 -0400124 result = fContextFactory->get(GrContextFactory::kGLES_ContextType,
125 GrContextFactory::ContextOverrides::kNone);
126 }
ethannicholas2ec06c92016-06-13 10:20:52 -0700127 return result;
joshualitt40836102016-03-11 11:45:53 -0800128#else
ethannicholas2ec06c92016-06-13 10:20:52 -0700129 return nullptr;
joshualitt40836102016-03-11 11:45:53 -0800130#endif
joshualittae47aee2016-03-10 13:29:36 -0800131}
132
133SkIRect Request::getBounds() {
134 SkIRect bounds;
135 if (fPicture) {
136 bounds = fPicture->cullRect().roundOut();
137 if (fGPUEnabled) {
joshualitt40836102016-03-11 11:45:53 -0800138#if SK_SUPPORT_GPU
joshualittae47aee2016-03-10 13:29:36 -0800139 int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
140 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
141 SkTMin(bounds.height(), maxRTSize));
joshualitt40836102016-03-11 11:45:53 -0800142#endif
joshualittae47aee2016-03-10 13:29:36 -0800143 }
144 } else {
145 bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
146 }
147
jcgregorio9a7acdc2016-06-30 07:54:14 -0700148 // We clip to kMaxWidth / kMaxHeight for performance reasons.
joshualittae47aee2016-03-10 13:29:36 -0800149 // TODO make this configurable
jcgregorio9a7acdc2016-06-30 07:54:14 -0700150 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kMaxWidth),
151 SkTMin(bounds.height(), kMaxHeight));
joshualittae47aee2016-03-10 13:29:36 -0800152 return bounds;
153}
154
brianosman78312952016-04-19 10:16:53 -0700155namespace {
156
157struct ColorAndProfile {
158 SkColorType fColorType;
brianosmanb109b8c2016-06-16 13:03:24 -0700159 bool fSRGB;
brianosman78312952016-04-19 10:16:53 -0700160};
161
162ColorAndProfile ColorModes[] = {
brianosman3a0dbde2016-07-26 11:36:05 -0700163 { kN32_SkColorType, false },
164 { kN32_SkColorType, true },
165 { kRGBA_F16_SkColorType, true },
brianosman78312952016-04-19 10:16:53 -0700166};
167
168}
169
joshualitt4dcbe432016-02-25 10:50:28 -0800170SkSurface* Request::createCPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800171 SkIRect bounds = this->getBounds();
brianosman78312952016-04-19 10:16:53 -0700172 ColorAndProfile cap = ColorModes[fColorMode];
raftias7c602de2016-10-13 10:45:44 -0700173 auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500174 ? SkColorSpace::MakeSRGBLinear()
175 : SkColorSpace::MakeSRGB();
brianosman78312952016-04-19 10:16:53 -0700176 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
brianosman0e22eb82016-08-30 07:07:59 -0700177 kPremul_SkAlphaType, cap.fSRGB ? colorSpace : nullptr);
brianosman3a0dbde2016-07-26 11:36:05 -0700178 return SkSurface::MakeRaster(info).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800179}
180
181SkSurface* Request::createGPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800182 GrContext* context = this->getContext();
183 SkIRect bounds = this->getBounds();
brianosman78312952016-04-19 10:16:53 -0700184 ColorAndProfile cap = ColorModes[fColorMode];
raftias7c602de2016-10-13 10:45:44 -0700185 auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500186 ? SkColorSpace::MakeSRGBLinear()
187 : SkColorSpace::MakeSRGB();
brianosman78312952016-04-19 10:16:53 -0700188 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
brianosman0e22eb82016-08-30 07:07:59 -0700189 kPremul_SkAlphaType, cap.fSRGB ? colorSpace: nullptr);
brianosman3a0dbde2016-07-26 11:36:05 -0700190 SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800191 return surface;
192}
193
Ben Wagnerc03e1c52016-10-17 15:20:02 -0400194bool Request::setOverdraw(bool enable) {
195 fOverdraw = enable;
196 return true;
197}
198
brianosman78312952016-04-19 10:16:53 -0700199bool Request::setColorMode(int mode) {
200 fColorMode = mode;
201 return enableGPU(fGPUEnabled);
202}
203
halcanary9d524f22016-03-29 09:03:52 -0700204bool Request::enableGPU(bool enable) {
joshualittee5348b2016-02-26 08:36:25 -0800205 if (enable) {
206 SkSurface* surface = this->createGPUSurface();
207 if (surface) {
208 fSurface.reset(surface);
209 fGPUEnabled = true;
joshualitt98bd5b12016-03-11 12:08:15 -0800210
211 // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
212 // draw once to flush the pipe
213 // TODO understand what is actually happening here
brianosman78312952016-04-19 10:16:53 -0700214 if (fDebugCanvas) {
215 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
216 this->getCanvas()->flush();
217 }
joshualitt98bd5b12016-03-11 12:08:15 -0800218
joshualittee5348b2016-02-26 08:36:25 -0800219 return true;
220 }
221 return false;
222 }
223 fSurface.reset(this->createCPUSurface());
224 fGPUEnabled = false;
225 return true;
halcanary9d524f22016-03-29 09:03:52 -0700226}
joshualitt6bc96792016-02-29 05:35:04 -0800227
228bool Request::initPictureFromStream(SkStream* stream) {
229 // parse picture from stream
reedca2622b2016-03-18 07:25:55 -0700230 fPicture = SkPicture::MakeFromStream(stream);
231 if (!fPicture) {
joshualitt6bc96792016-02-29 05:35:04 -0800232 fprintf(stderr, "Could not create picture from stream.\n");
233 return false;
234 }
235
joshualittae47aee2016-03-10 13:29:36 -0800236 // reinitialize canvas with the new picture dimensions
237 this->enableGPU(fGPUEnabled);
238
joshualitt6bc96792016-02-29 05:35:04 -0800239 // pour picture into debug canvas
joshualittae47aee2016-03-10 13:29:36 -0800240 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800241 fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
joshualitt6bc96792016-02-29 05:35:04 -0800242 fDebugCanvas->drawPicture(fPicture);
joshualitt3a9be692016-02-29 11:38:11 -0800243
244 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
245 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
joshualittb0666ad2016-03-08 10:43:41 -0800246 this->getCanvas()->flush();
joshualitt6bc96792016-02-29 05:35:04 -0800247 return true;
joshualittee5348b2016-02-26 08:36:25 -0800248}
249
bungeman38d909e2016-08-02 14:40:46 -0700250sk_sp<SkData> Request::getJsonOps(int n) {
joshualitt1e5884b2016-02-26 08:22:49 -0800251 SkCanvas* canvas = this->getCanvas();
252 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
253 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
Brian Salomonf09492b2016-12-21 15:40:26 -0500254 root["drawGpuOpBounds"] = Json::Value(fDebugCanvas->getDrawGpuOpBounds());
brianosman78312952016-04-19 10:16:53 -0700255 root["colorMode"] = Json::Value(fColorMode);
joshualitt1e5884b2016-02-26 08:22:49 -0800256 SkDynamicMemoryWStream stream;
257 stream.writeText(Json::FastWriter().write(root).c_str());
258
reed42943c82016-09-12 12:01:44 -0700259 return stream.detachAsData();
joshualitt1e5884b2016-02-26 08:22:49 -0800260}
261
Brian Salomon144a5c52016-12-20 16:48:59 -0500262sk_sp<SkData> Request::getJsonOpList(int n) {
joshualitt1e5884b2016-02-26 08:22:49 -0800263 SkCanvas* canvas = this->getCanvas();
264 SkASSERT(fGPUEnabled);
265
Brian Salomon144a5c52016-12-20 16:48:59 -0500266 Json::Value result = fDebugCanvas->toJSONOpList(n, canvas);
joshualitt1e5884b2016-02-26 08:22:49 -0800267
268 SkDynamicMemoryWStream stream;
joshualittae47aee2016-03-10 13:29:36 -0800269 stream.writeText(Json::FastWriter().write(result).c_str());
joshualitt1e5884b2016-02-26 08:22:49 -0800270
reed42943c82016-09-12 12:01:44 -0700271 return stream.detachAsData();
joshualitt1e5884b2016-02-26 08:22:49 -0800272}
joshualittee5348b2016-02-26 08:36:25 -0800273
bungeman38d909e2016-08-02 14:40:46 -0700274sk_sp<SkData> Request::getJsonInfo(int n) {
joshualittee5348b2016-02-26 08:36:25 -0800275 // drawTo
Hal Canary1b612a82016-11-03 16:26:13 -0400276 sk_sp<SkSurface> surface(this->createCPUSurface());
joshualittee5348b2016-02-26 08:36:25 -0800277 SkCanvas* canvas = surface->getCanvas();
278
279 // TODO this is really slow and we should cache the matrix and clip
280 fDebugCanvas->drawTo(canvas, n);
281
282 // make some json
283 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
284 SkIRect clip = fDebugCanvas->getCurrentClip();
285 Json::Value info(Json::objectValue);
joshualittbd724132016-03-03 11:39:38 -0800286 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
287 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
joshualittee5348b2016-02-26 08:36:25 -0800288
289 std::string json = Json::FastWriter().write(info);
290
291 // We don't want the null terminator so strlen is correct
bungeman38d909e2016-08-02 14:40:46 -0700292 return SkData::MakeWithCopy(json.c_str(), strlen(json.c_str()));
joshualittee5348b2016-02-26 08:36:25 -0800293}
joshualitte0449cf2016-03-09 10:07:02 -0800294
295SkColor Request::getPixel(int x, int y) {
296 SkCanvas* canvas = this->getCanvas();
297 canvas->flush();
Ben Wagner145dbcd2016-11-03 14:40:50 -0400298 std::unique_ptr<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
joshualitte0449cf2016-03-09 10:07:02 -0800299 SkASSERT(bitmap);
brianosman78312952016-04-19 10:16:53 -0700300
301 // Convert to format suitable for inspection
302 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
reed42943c82016-09-12 12:01:44 -0700303 SkASSERT(encodedBitmap);
brianosman78312952016-04-19 10:16:53 -0700304
305 const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
joshualitte0449cf2016-03-09 10:07:02 -0800306 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
joshualitte0449cf2016-03-09 10:07:02 -0800307 return result;
308}