blob: 7534b1df98e985b0ba4b0fedd806d96c9c96c816 [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"
joshualitt4dcbe432016-02-25 10:50:28 -080012
bsalomon3724e572016-03-30 18:56:19 -070013using namespace sk_gpu_test;
14
joshualittae47aee2016-03-10 13:29:36 -080015static int kDefaultWidth = 1920;
16static int kDefaultHeight = 1080;
17
joshualitt4dcbe432016-02-25 10:50:28 -080018
joshualittee5348b2016-02-26 08:36:25 -080019Request::Request(SkString rootUrl)
20 : fUploadContext(nullptr)
21 , fUrlDataManager(rootUrl)
22 , fGPUEnabled(false) {
23 // create surface
joshualitt40836102016-03-11 11:45:53 -080024#if SK_SUPPORT_GPU
joshualittee5348b2016-02-26 08:36:25 -080025 GrContextOptions grContextOpts;
joshualitt40836102016-03-11 11:45:53 -080026 fContextFactory = new GrContextFactory(grContextOpts);
27#else
28 fContextFactory = nullptr;
29#endif
30}
31
32Request::~Request() {
33#if SK_SUPPORT_GPU
34 if (fContextFactory) {
35 delete fContextFactory;
36 }
37#endif
joshualittee5348b2016-02-26 08:36:25 -080038}
39
joshualitt4dcbe432016-02-25 10:50:28 -080040SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
41 SkBitmap* bmp = new SkBitmap();
joshualittae47aee2016-03-10 13:29:36 -080042 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -080043 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
44 kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
joshualitt4dcbe432016-02-25 10:50:28 -080045 bmp->setInfo(info);
46 if (!canvas->readPixels(bmp, 0, 0)) {
47 fprintf(stderr, "Can't read pixels\n");
48 return nullptr;
49 }
50 return bmp;
51}
52
53SkData* Request::writeCanvasToPng(SkCanvas* canvas) {
54 // capture pixels
joshualitte0449cf2016-03-09 10:07:02 -080055 SkAutoTDelete<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
joshualitt4dcbe432016-02-25 10:50:28 -080056 SkASSERT(bmp);
57
58 // write to png
59 SkDynamicMemoryWStream buffer;
halcanary9d524f22016-03-29 09:03:52 -070060 SkDrawCommand::WritePNG((const png_bytep) bmp->getPixels(), bmp->width(), bmp->height(),
ethannicholasf67531f2016-03-21 10:19:39 -070061 buffer);
joshualitt4dcbe432016-02-25 10:50:28 -080062 return buffer.copyToData();
63}
64
65SkCanvas* Request::getCanvas() {
joshualitt40836102016-03-11 11:45:53 -080066#if SK_SUPPORT_GPU
joshualitt4dcbe432016-02-25 10:50:28 -080067 GrContextFactory* factory = fContextFactory;
bsalomon85b4b532016-04-05 11:06:27 -070068 GLTestContext* gl = factory->getContextInfo(GrContextFactory::kNativeGL_ContextType,
69 GrContextFactory::kNone_ContextOptions).fGLContext;
joshualitt4dcbe432016-02-25 10:50:28 -080070 gl->makeCurrent();
joshualitt40836102016-03-11 11:45:53 -080071#endif
joshualitt4dcbe432016-02-25 10:50:28 -080072 SkASSERT(fDebugCanvas);
joshualitte0449cf2016-03-09 10:07:02 -080073
74 // create the appropriate surface if necessary
75 if (!fSurface) {
76 this->enableGPU(fGPUEnabled);
77 }
joshualitt4dcbe432016-02-25 10:50:28 -080078 SkCanvas* target = fSurface->getCanvas();
79 return target;
80}
81
joshualitt46b301d2016-03-02 08:32:37 -080082void Request::drawToCanvas(int n, int m) {
joshualitt4dcbe432016-02-25 10:50:28 -080083 SkCanvas* target = this->getCanvas();
joshualitt46b301d2016-03-02 08:32:37 -080084 fDebugCanvas->drawTo(target, n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080085}
86
joshualitt46b301d2016-03-02 08:32:37 -080087SkData* Request::drawToPng(int n, int m) {
88 this->drawToCanvas(n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080089 return writeCanvasToPng(this->getCanvas());
90}
91
joshualitte0449cf2016-03-09 10:07:02 -080092SkData* Request::writeOutSkp() {
93 // Playback into picture recorder
joshualittae47aee2016-03-10 13:29:36 -080094 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -080095 SkPictureRecorder recorder;
96 SkCanvas* canvas = recorder.beginRecording(bounds.width(), bounds.height());
97
98 fDebugCanvas->draw(canvas);
99
reedca2622b2016-03-18 07:25:55 -0700100 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
joshualitte0449cf2016-03-09 10:07:02 -0800101
102 SkDynamicMemoryWStream outStream;
103
104 SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer());
105 picture->serialize(&outStream, serializer);
106
107 return outStream.copyToData();
108}
109
joshualittae47aee2016-03-10 13:29:36 -0800110GrContext* Request::getContext() {
joshualitt40836102016-03-11 11:45:53 -0800111#if SK_SUPPORT_GPU
bsalomon85b4b532016-04-05 11:06:27 -0700112 return fContextFactory->get(GrContextFactory::kNativeGL_ContextType,
113 GrContextFactory::kNone_ContextOptions);
joshualitt40836102016-03-11 11:45:53 -0800114#else
115 return nullptr;
116#endif
joshualittae47aee2016-03-10 13:29:36 -0800117}
118
119SkIRect Request::getBounds() {
120 SkIRect bounds;
121 if (fPicture) {
122 bounds = fPicture->cullRect().roundOut();
123 if (fGPUEnabled) {
joshualitt40836102016-03-11 11:45:53 -0800124#if SK_SUPPORT_GPU
joshualittae47aee2016-03-10 13:29:36 -0800125 int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
126 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
127 SkTMin(bounds.height(), maxRTSize));
joshualitt40836102016-03-11 11:45:53 -0800128#endif
joshualittae47aee2016-03-10 13:29:36 -0800129 }
130 } else {
131 bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
132 }
133
134 // We clip to kDefaultWidth / kDefaultHeight for performance reasons
135 // TODO make this configurable
136 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kDefaultWidth),
137 SkTMin(bounds.height(), kDefaultHeight));
138 return bounds;
139}
140
joshualitt4dcbe432016-02-25 10:50:28 -0800141SkSurface* Request::createCPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800142 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800143 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), kN32_SkColorType,
joshualitt4dcbe432016-02-25 10:50:28 -0800144 kPremul_SkAlphaType);
reede8f30622016-03-23 18:59:25 -0700145 return SkSurface::MakeRaster(info).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800146}
147
148SkSurface* Request::createGPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800149 GrContext* context = this->getContext();
150 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800151 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
joshualitt4dcbe432016-02-25 10:50:28 -0800152 kN32_SkColorType, kPremul_SkAlphaType);
153 uint32_t flags = 0;
154 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
reede8f30622016-03-23 18:59:25 -0700155 SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
156 &props).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800157 return surface;
158}
159
halcanary9d524f22016-03-29 09:03:52 -0700160bool Request::enableGPU(bool enable) {
joshualittee5348b2016-02-26 08:36:25 -0800161 if (enable) {
162 SkSurface* surface = this->createGPUSurface();
163 if (surface) {
164 fSurface.reset(surface);
165 fGPUEnabled = true;
joshualitt98bd5b12016-03-11 12:08:15 -0800166
167 // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
168 // draw once to flush the pipe
169 // TODO understand what is actually happening here
170 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
171 this->getCanvas()->flush();
172
joshualittee5348b2016-02-26 08:36:25 -0800173 return true;
174 }
175 return false;
176 }
177 fSurface.reset(this->createCPUSurface());
178 fGPUEnabled = false;
179 return true;
halcanary9d524f22016-03-29 09:03:52 -0700180}
joshualitt6bc96792016-02-29 05:35:04 -0800181
182bool Request::initPictureFromStream(SkStream* stream) {
183 // parse picture from stream
reedca2622b2016-03-18 07:25:55 -0700184 fPicture = SkPicture::MakeFromStream(stream);
185 if (!fPicture) {
joshualitt6bc96792016-02-29 05:35:04 -0800186 fprintf(stderr, "Could not create picture from stream.\n");
187 return false;
188 }
189
joshualittae47aee2016-03-10 13:29:36 -0800190 // reinitialize canvas with the new picture dimensions
191 this->enableGPU(fGPUEnabled);
192
joshualitt6bc96792016-02-29 05:35:04 -0800193 // pour picture into debug canvas
joshualittae47aee2016-03-10 13:29:36 -0800194 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800195 fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
joshualitt6bc96792016-02-29 05:35:04 -0800196 fDebugCanvas->drawPicture(fPicture);
joshualitt3a9be692016-02-29 11:38:11 -0800197
198 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
199 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
joshualittb0666ad2016-03-08 10:43:41 -0800200 this->getCanvas()->flush();
joshualitt6bc96792016-02-29 05:35:04 -0800201 return true;
joshualittee5348b2016-02-26 08:36:25 -0800202}
203
joshualitt1e5884b2016-02-26 08:22:49 -0800204SkData* Request::getJsonOps(int n) {
205 SkCanvas* canvas = this->getCanvas();
206 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
207 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
joshualitt5d5207a2016-02-29 12:46:04 -0800208 root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
joshualitt1e5884b2016-02-26 08:22:49 -0800209 SkDynamicMemoryWStream stream;
210 stream.writeText(Json::FastWriter().write(root).c_str());
211
212 return stream.copyToData();
213}
214
215SkData* Request::getJsonBatchList(int n) {
216 SkCanvas* canvas = this->getCanvas();
217 SkASSERT(fGPUEnabled);
218
joshualittae47aee2016-03-10 13:29:36 -0800219 Json::Value result = fDebugCanvas->toJSONBatchList(n, canvas);
joshualitt1e5884b2016-02-26 08:22:49 -0800220
221 SkDynamicMemoryWStream stream;
joshualittae47aee2016-03-10 13:29:36 -0800222 stream.writeText(Json::FastWriter().write(result).c_str());
joshualitt1e5884b2016-02-26 08:22:49 -0800223
224 return stream.copyToData();
225}
joshualittee5348b2016-02-26 08:36:25 -0800226
227SkData* Request::getJsonInfo(int n) {
228 // drawTo
229 SkAutoTUnref<SkSurface> surface(this->createCPUSurface());
230 SkCanvas* canvas = surface->getCanvas();
231
232 // TODO this is really slow and we should cache the matrix and clip
233 fDebugCanvas->drawTo(canvas, n);
234
235 // make some json
236 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
237 SkIRect clip = fDebugCanvas->getCurrentClip();
238 Json::Value info(Json::objectValue);
joshualittbd724132016-03-03 11:39:38 -0800239 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
240 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
joshualittee5348b2016-02-26 08:36:25 -0800241
242 std::string json = Json::FastWriter().write(info);
243
244 // We don't want the null terminator so strlen is correct
245 return SkData::NewWithCopy(json.c_str(), strlen(json.c_str()));
246}
joshualitte0449cf2016-03-09 10:07:02 -0800247
248SkColor Request::getPixel(int x, int y) {
249 SkCanvas* canvas = this->getCanvas();
250 canvas->flush();
251 SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
252 SkASSERT(bitmap);
253 bitmap->lockPixels();
254 uint8_t* start = ((uint8_t*) bitmap->getPixels()) + (y * bitmap->width() + x) * 4;
255 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
256 bitmap->unlockPixels();
257 return result;
258}