blob: 58aca84b53bbf0dc0f2b8164afdb073b7ef84de5 [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"
11#include "SkPixelSerializer.h"
brianosman78312952016-04-19 10:16:53 -070012#include "picture_utils.h"
joshualitt4dcbe432016-02-25 10:50:28 -080013
bsalomon3724e572016-03-30 18:56:19 -070014using namespace sk_gpu_test;
15
joshualittae47aee2016-03-10 13:29:36 -080016static int kDefaultWidth = 1920;
17static int kDefaultHeight = 1080;
18
joshualitt4dcbe432016-02-25 10:50:28 -080019
joshualittee5348b2016-02-26 08:36:25 -080020Request::Request(SkString rootUrl)
21 : fUploadContext(nullptr)
22 , fUrlDataManager(rootUrl)
brianosman78312952016-04-19 10:16:53 -070023 , fGPUEnabled(false)
24 , fColorMode(0) {
joshualittee5348b2016-02-26 08:36:25 -080025 // create surface
joshualitt40836102016-03-11 11:45:53 -080026#if SK_SUPPORT_GPU
joshualittee5348b2016-02-26 08:36:25 -080027 GrContextOptions grContextOpts;
joshualitt40836102016-03-11 11:45:53 -080028 fContextFactory = new GrContextFactory(grContextOpts);
29#else
30 fContextFactory = nullptr;
31#endif
32}
33
34Request::~Request() {
35#if SK_SUPPORT_GPU
36 if (fContextFactory) {
37 delete fContextFactory;
38 }
39#endif
joshualittee5348b2016-02-26 08:36:25 -080040}
41
joshualitt4dcbe432016-02-25 10:50:28 -080042SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
43 SkBitmap* bmp = new SkBitmap();
brianosman78312952016-04-19 10:16:53 -070044 bmp->setInfo(canvas->imageInfo());
joshualitt4dcbe432016-02-25 10:50:28 -080045 if (!canvas->readPixels(bmp, 0, 0)) {
46 fprintf(stderr, "Can't read pixels\n");
47 return nullptr;
48 }
49 return bmp;
50}
51
52SkData* Request::writeCanvasToPng(SkCanvas* canvas) {
53 // capture pixels
joshualitte0449cf2016-03-09 10:07:02 -080054 SkAutoTDelete<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
joshualitt4dcbe432016-02-25 10:50:28 -080055 SkASSERT(bmp);
56
brianosman78312952016-04-19 10:16:53 -070057 // Convert to format suitable for PNG output
58 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
59 SkASSERT(encodedBitmap.get());
60
joshualitt4dcbe432016-02-25 10:50:28 -080061 // write to png
62 SkDynamicMemoryWStream buffer;
brianosman78312952016-04-19 10:16:53 -070063 SkDrawCommand::WritePNG((const png_bytep) encodedBitmap->writable_data(),
64 bmp->width(), bmp->height(),
ethannicholasf67531f2016-03-21 10:19:39 -070065 buffer);
joshualitt4dcbe432016-02-25 10:50:28 -080066 return buffer.copyToData();
67}
68
69SkCanvas* Request::getCanvas() {
joshualitt40836102016-03-11 11:45:53 -080070#if SK_SUPPORT_GPU
joshualitt4dcbe432016-02-25 10:50:28 -080071 GrContextFactory* factory = fContextFactory;
bsalomon85b4b532016-04-05 11:06:27 -070072 GLTestContext* gl = factory->getContextInfo(GrContextFactory::kNativeGL_ContextType,
73 GrContextFactory::kNone_ContextOptions).fGLContext;
joshualitt4dcbe432016-02-25 10:50:28 -080074 gl->makeCurrent();
joshualitt40836102016-03-11 11:45:53 -080075#endif
joshualitt4dcbe432016-02-25 10:50:28 -080076 SkASSERT(fDebugCanvas);
joshualitte0449cf2016-03-09 10:07:02 -080077
78 // create the appropriate surface if necessary
79 if (!fSurface) {
80 this->enableGPU(fGPUEnabled);
81 }
joshualitt4dcbe432016-02-25 10:50:28 -080082 SkCanvas* target = fSurface->getCanvas();
83 return target;
84}
85
joshualitt46b301d2016-03-02 08:32:37 -080086void Request::drawToCanvas(int n, int m) {
joshualitt4dcbe432016-02-25 10:50:28 -080087 SkCanvas* target = this->getCanvas();
joshualitt46b301d2016-03-02 08:32:37 -080088 fDebugCanvas->drawTo(target, n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080089}
90
joshualitt46b301d2016-03-02 08:32:37 -080091SkData* Request::drawToPng(int n, int m) {
92 this->drawToCanvas(n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080093 return writeCanvasToPng(this->getCanvas());
94}
95
joshualitte0449cf2016-03-09 10:07:02 -080096SkData* Request::writeOutSkp() {
97 // Playback into picture recorder
joshualittae47aee2016-03-10 13:29:36 -080098 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -080099 SkPictureRecorder recorder;
100 SkCanvas* canvas = recorder.beginRecording(bounds.width(), bounds.height());
101
102 fDebugCanvas->draw(canvas);
103
reedca2622b2016-03-18 07:25:55 -0700104 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
joshualitte0449cf2016-03-09 10:07:02 -0800105
106 SkDynamicMemoryWStream outStream;
107
108 SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer());
109 picture->serialize(&outStream, serializer);
110
111 return outStream.copyToData();
112}
113
joshualittae47aee2016-03-10 13:29:36 -0800114GrContext* Request::getContext() {
joshualitt40836102016-03-11 11:45:53 -0800115#if SK_SUPPORT_GPU
bsalomon85b4b532016-04-05 11:06:27 -0700116 return fContextFactory->get(GrContextFactory::kNativeGL_ContextType,
117 GrContextFactory::kNone_ContextOptions);
joshualitt40836102016-03-11 11:45:53 -0800118#else
119 return nullptr;
120#endif
joshualittae47aee2016-03-10 13:29:36 -0800121}
122
123SkIRect Request::getBounds() {
124 SkIRect bounds;
125 if (fPicture) {
126 bounds = fPicture->cullRect().roundOut();
127 if (fGPUEnabled) {
joshualitt40836102016-03-11 11:45:53 -0800128#if SK_SUPPORT_GPU
joshualittae47aee2016-03-10 13:29:36 -0800129 int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
130 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
131 SkTMin(bounds.height(), maxRTSize));
joshualitt40836102016-03-11 11:45:53 -0800132#endif
joshualittae47aee2016-03-10 13:29:36 -0800133 }
134 } else {
135 bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
136 }
137
138 // We clip to kDefaultWidth / kDefaultHeight for performance reasons
139 // TODO make this configurable
140 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kDefaultWidth),
141 SkTMin(bounds.height(), kDefaultHeight));
142 return bounds;
143}
144
brianosman78312952016-04-19 10:16:53 -0700145namespace {
146
147struct ColorAndProfile {
148 SkColorType fColorType;
149 SkColorProfileType fProfileType;
150 bool fGammaCorrect;
151};
152
153ColorAndProfile ColorModes[] = {
154 { kN32_SkColorType, kLinear_SkColorProfileType, false },
155 { kN32_SkColorType, kSRGB_SkColorProfileType, true },
156 { kRGBA_F16_SkColorType, kLinear_SkColorProfileType, true },
157};
158
159}
160
joshualitt4dcbe432016-02-25 10:50:28 -0800161SkSurface* Request::createCPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800162 SkIRect bounds = this->getBounds();
brianosman78312952016-04-19 10:16:53 -0700163 ColorAndProfile cap = ColorModes[fColorMode];
164 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
165 kPremul_SkAlphaType, cap.fProfileType);
166 uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
167 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
168 return SkSurface::MakeRaster(info, &props).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800169}
170
171SkSurface* Request::createGPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800172 GrContext* context = this->getContext();
173 SkIRect bounds = this->getBounds();
brianosman78312952016-04-19 10:16:53 -0700174 ColorAndProfile cap = ColorModes[fColorMode];
175 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
176 kPremul_SkAlphaType, cap.fProfileType);
177 uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
joshualitt4dcbe432016-02-25 10:50:28 -0800178 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
reede8f30622016-03-23 18:59:25 -0700179 SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
180 &props).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800181 return surface;
182}
183
brianosman78312952016-04-19 10:16:53 -0700184bool Request::setColorMode(int mode) {
185 fColorMode = mode;
186 return enableGPU(fGPUEnabled);
187}
188
halcanary9d524f22016-03-29 09:03:52 -0700189bool Request::enableGPU(bool enable) {
joshualittee5348b2016-02-26 08:36:25 -0800190 if (enable) {
191 SkSurface* surface = this->createGPUSurface();
192 if (surface) {
193 fSurface.reset(surface);
194 fGPUEnabled = true;
joshualitt98bd5b12016-03-11 12:08:15 -0800195
196 // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
197 // draw once to flush the pipe
198 // TODO understand what is actually happening here
brianosman78312952016-04-19 10:16:53 -0700199 if (fDebugCanvas) {
200 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
201 this->getCanvas()->flush();
202 }
joshualitt98bd5b12016-03-11 12:08:15 -0800203
joshualittee5348b2016-02-26 08:36:25 -0800204 return true;
205 }
206 return false;
207 }
208 fSurface.reset(this->createCPUSurface());
209 fGPUEnabled = false;
210 return true;
halcanary9d524f22016-03-29 09:03:52 -0700211}
joshualitt6bc96792016-02-29 05:35:04 -0800212
213bool Request::initPictureFromStream(SkStream* stream) {
214 // parse picture from stream
reedca2622b2016-03-18 07:25:55 -0700215 fPicture = SkPicture::MakeFromStream(stream);
216 if (!fPicture) {
joshualitt6bc96792016-02-29 05:35:04 -0800217 fprintf(stderr, "Could not create picture from stream.\n");
218 return false;
219 }
220
joshualittae47aee2016-03-10 13:29:36 -0800221 // reinitialize canvas with the new picture dimensions
222 this->enableGPU(fGPUEnabled);
223
joshualitt6bc96792016-02-29 05:35:04 -0800224 // pour picture into debug canvas
joshualittae47aee2016-03-10 13:29:36 -0800225 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800226 fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
joshualitt6bc96792016-02-29 05:35:04 -0800227 fDebugCanvas->drawPicture(fPicture);
joshualitt3a9be692016-02-29 11:38:11 -0800228
229 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
230 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
joshualittb0666ad2016-03-08 10:43:41 -0800231 this->getCanvas()->flush();
joshualitt6bc96792016-02-29 05:35:04 -0800232 return true;
joshualittee5348b2016-02-26 08:36:25 -0800233}
234
joshualitt1e5884b2016-02-26 08:22:49 -0800235SkData* Request::getJsonOps(int n) {
236 SkCanvas* canvas = this->getCanvas();
237 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
238 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
joshualitt5d5207a2016-02-29 12:46:04 -0800239 root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
brianosman78312952016-04-19 10:16:53 -0700240 root["colorMode"] = Json::Value(fColorMode);
joshualitt1e5884b2016-02-26 08:22:49 -0800241 SkDynamicMemoryWStream stream;
242 stream.writeText(Json::FastWriter().write(root).c_str());
243
244 return stream.copyToData();
245}
246
247SkData* Request::getJsonBatchList(int n) {
248 SkCanvas* canvas = this->getCanvas();
249 SkASSERT(fGPUEnabled);
250
joshualittae47aee2016-03-10 13:29:36 -0800251 Json::Value result = fDebugCanvas->toJSONBatchList(n, canvas);
joshualitt1e5884b2016-02-26 08:22:49 -0800252
253 SkDynamicMemoryWStream stream;
joshualittae47aee2016-03-10 13:29:36 -0800254 stream.writeText(Json::FastWriter().write(result).c_str());
joshualitt1e5884b2016-02-26 08:22:49 -0800255
256 return stream.copyToData();
257}
joshualittee5348b2016-02-26 08:36:25 -0800258
259SkData* Request::getJsonInfo(int n) {
260 // drawTo
261 SkAutoTUnref<SkSurface> surface(this->createCPUSurface());
262 SkCanvas* canvas = surface->getCanvas();
263
264 // TODO this is really slow and we should cache the matrix and clip
265 fDebugCanvas->drawTo(canvas, n);
266
267 // make some json
268 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
269 SkIRect clip = fDebugCanvas->getCurrentClip();
270 Json::Value info(Json::objectValue);
joshualittbd724132016-03-03 11:39:38 -0800271 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
272 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
joshualittee5348b2016-02-26 08:36:25 -0800273
274 std::string json = Json::FastWriter().write(info);
275
276 // We don't want the null terminator so strlen is correct
277 return SkData::NewWithCopy(json.c_str(), strlen(json.c_str()));
278}
joshualitte0449cf2016-03-09 10:07:02 -0800279
280SkColor Request::getPixel(int x, int y) {
281 SkCanvas* canvas = this->getCanvas();
282 canvas->flush();
283 SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
284 SkASSERT(bitmap);
brianosman78312952016-04-19 10:16:53 -0700285
286 // Convert to format suitable for inspection
287 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
288 SkASSERT(encodedBitmap.get());
289
290 const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
joshualitte0449cf2016-03-09 10:07:02 -0800291 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
joshualitte0449cf2016-03-09 10:07:02 -0800292 return result;
293}