blob: 1d946abaa03ebe8af912a9115d1bb5c0de0815a2 [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
joshualittae47aee2016-03-10 13:29:36 -080013static int kDefaultWidth = 1920;
14static int kDefaultHeight = 1080;
15
joshualitt4dcbe432016-02-25 10:50:28 -080016
joshualittee5348b2016-02-26 08:36:25 -080017Request::Request(SkString rootUrl)
18 : fUploadContext(nullptr)
19 , fUrlDataManager(rootUrl)
20 , fGPUEnabled(false) {
21 // create surface
joshualitt40836102016-03-11 11:45:53 -080022#if SK_SUPPORT_GPU
joshualittee5348b2016-02-26 08:36:25 -080023 GrContextOptions grContextOpts;
joshualitt40836102016-03-11 11:45:53 -080024 fContextFactory = new GrContextFactory(grContextOpts);
25#else
26 fContextFactory = nullptr;
27#endif
28}
29
30Request::~Request() {
31#if SK_SUPPORT_GPU
32 if (fContextFactory) {
33 delete fContextFactory;
34 }
35#endif
joshualittee5348b2016-02-26 08:36:25 -080036}
37
joshualitt4dcbe432016-02-25 10:50:28 -080038SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
39 SkBitmap* bmp = new SkBitmap();
joshualittae47aee2016-03-10 13:29:36 -080040 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -080041 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
42 kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
joshualitt4dcbe432016-02-25 10:50:28 -080043 bmp->setInfo(info);
44 if (!canvas->readPixels(bmp, 0, 0)) {
45 fprintf(stderr, "Can't read pixels\n");
46 return nullptr;
47 }
48 return bmp;
49}
50
51SkData* Request::writeCanvasToPng(SkCanvas* canvas) {
52 // capture pixels
joshualitte0449cf2016-03-09 10:07:02 -080053 SkAutoTDelete<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
joshualitt4dcbe432016-02-25 10:50:28 -080054 SkASSERT(bmp);
55
56 // write to png
57 SkDynamicMemoryWStream buffer;
halcanary9d524f22016-03-29 09:03:52 -070058 SkDrawCommand::WritePNG((const png_bytep) bmp->getPixels(), bmp->width(), bmp->height(),
ethannicholasf67531f2016-03-21 10:19:39 -070059 buffer);
joshualitt4dcbe432016-02-25 10:50:28 -080060 return buffer.copyToData();
61}
62
63SkCanvas* Request::getCanvas() {
joshualitt40836102016-03-11 11:45:53 -080064#if SK_SUPPORT_GPU
joshualitt4dcbe432016-02-25 10:50:28 -080065 GrContextFactory* factory = fContextFactory;
66 SkGLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContextType,
67 GrContextFactory::kNone_GLContextOptions).fGLContext;
68 gl->makeCurrent();
joshualitt40836102016-03-11 11:45:53 -080069#endif
joshualitt4dcbe432016-02-25 10:50:28 -080070 SkASSERT(fDebugCanvas);
joshualitte0449cf2016-03-09 10:07:02 -080071
72 // create the appropriate surface if necessary
73 if (!fSurface) {
74 this->enableGPU(fGPUEnabled);
75 }
joshualitt4dcbe432016-02-25 10:50:28 -080076 SkCanvas* target = fSurface->getCanvas();
77 return target;
78}
79
joshualitt46b301d2016-03-02 08:32:37 -080080void Request::drawToCanvas(int n, int m) {
joshualitt4dcbe432016-02-25 10:50:28 -080081 SkCanvas* target = this->getCanvas();
joshualitt46b301d2016-03-02 08:32:37 -080082 fDebugCanvas->drawTo(target, n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080083}
84
joshualitt46b301d2016-03-02 08:32:37 -080085SkData* Request::drawToPng(int n, int m) {
86 this->drawToCanvas(n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080087 return writeCanvasToPng(this->getCanvas());
88}
89
joshualitte0449cf2016-03-09 10:07:02 -080090SkData* Request::writeOutSkp() {
91 // Playback into picture recorder
joshualittae47aee2016-03-10 13:29:36 -080092 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -080093 SkPictureRecorder recorder;
94 SkCanvas* canvas = recorder.beginRecording(bounds.width(), bounds.height());
95
96 fDebugCanvas->draw(canvas);
97
reedca2622b2016-03-18 07:25:55 -070098 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
joshualitte0449cf2016-03-09 10:07:02 -080099
100 SkDynamicMemoryWStream outStream;
101
102 SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer());
103 picture->serialize(&outStream, serializer);
104
105 return outStream.copyToData();
106}
107
joshualittae47aee2016-03-10 13:29:36 -0800108GrContext* Request::getContext() {
joshualitt40836102016-03-11 11:45:53 -0800109#if SK_SUPPORT_GPU
joshualittae47aee2016-03-10 13:29:36 -0800110 return fContextFactory->get(GrContextFactory::kNative_GLContextType,
111 GrContextFactory::kNone_GLContextOptions);
joshualitt40836102016-03-11 11:45:53 -0800112#else
113 return nullptr;
114#endif
joshualittae47aee2016-03-10 13:29:36 -0800115}
116
117SkIRect Request::getBounds() {
118 SkIRect bounds;
119 if (fPicture) {
120 bounds = fPicture->cullRect().roundOut();
121 if (fGPUEnabled) {
joshualitt40836102016-03-11 11:45:53 -0800122#if SK_SUPPORT_GPU
joshualittae47aee2016-03-10 13:29:36 -0800123 int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
124 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
125 SkTMin(bounds.height(), maxRTSize));
joshualitt40836102016-03-11 11:45:53 -0800126#endif
joshualittae47aee2016-03-10 13:29:36 -0800127 }
128 } else {
129 bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
130 }
131
132 // We clip to kDefaultWidth / kDefaultHeight for performance reasons
133 // TODO make this configurable
134 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kDefaultWidth),
135 SkTMin(bounds.height(), kDefaultHeight));
136 return bounds;
137}
138
joshualitt4dcbe432016-02-25 10:50:28 -0800139SkSurface* Request::createCPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800140 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800141 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), kN32_SkColorType,
joshualitt4dcbe432016-02-25 10:50:28 -0800142 kPremul_SkAlphaType);
reede8f30622016-03-23 18:59:25 -0700143 return SkSurface::MakeRaster(info).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800144}
145
146SkSurface* Request::createGPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800147 GrContext* context = this->getContext();
148 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800149 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
joshualitt4dcbe432016-02-25 10:50:28 -0800150 kN32_SkColorType, kPremul_SkAlphaType);
151 uint32_t flags = 0;
152 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
reede8f30622016-03-23 18:59:25 -0700153 SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
154 &props).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800155 return surface;
156}
157
halcanary9d524f22016-03-29 09:03:52 -0700158bool Request::enableGPU(bool enable) {
joshualittee5348b2016-02-26 08:36:25 -0800159 if (enable) {
160 SkSurface* surface = this->createGPUSurface();
161 if (surface) {
162 fSurface.reset(surface);
163 fGPUEnabled = true;
joshualitt98bd5b12016-03-11 12:08:15 -0800164
165 // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
166 // draw once to flush the pipe
167 // TODO understand what is actually happening here
168 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
169 this->getCanvas()->flush();
170
joshualittee5348b2016-02-26 08:36:25 -0800171 return true;
172 }
173 return false;
174 }
175 fSurface.reset(this->createCPUSurface());
176 fGPUEnabled = false;
177 return true;
halcanary9d524f22016-03-29 09:03:52 -0700178}
joshualitt6bc96792016-02-29 05:35:04 -0800179
180bool Request::initPictureFromStream(SkStream* stream) {
181 // parse picture from stream
reedca2622b2016-03-18 07:25:55 -0700182 fPicture = SkPicture::MakeFromStream(stream);
183 if (!fPicture) {
joshualitt6bc96792016-02-29 05:35:04 -0800184 fprintf(stderr, "Could not create picture from stream.\n");
185 return false;
186 }
187
joshualittae47aee2016-03-10 13:29:36 -0800188 // reinitialize canvas with the new picture dimensions
189 this->enableGPU(fGPUEnabled);
190
joshualitt6bc96792016-02-29 05:35:04 -0800191 // pour picture into debug canvas
joshualittae47aee2016-03-10 13:29:36 -0800192 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800193 fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
joshualitt6bc96792016-02-29 05:35:04 -0800194 fDebugCanvas->drawPicture(fPicture);
joshualitt3a9be692016-02-29 11:38:11 -0800195
196 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
197 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
joshualittb0666ad2016-03-08 10:43:41 -0800198 this->getCanvas()->flush();
joshualitt6bc96792016-02-29 05:35:04 -0800199 return true;
joshualittee5348b2016-02-26 08:36:25 -0800200}
201
joshualitt1e5884b2016-02-26 08:22:49 -0800202SkData* Request::getJsonOps(int n) {
203 SkCanvas* canvas = this->getCanvas();
204 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
205 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
joshualitt5d5207a2016-02-29 12:46:04 -0800206 root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
joshualitt1e5884b2016-02-26 08:22:49 -0800207 SkDynamicMemoryWStream stream;
208 stream.writeText(Json::FastWriter().write(root).c_str());
209
210 return stream.copyToData();
211}
212
213SkData* Request::getJsonBatchList(int n) {
214 SkCanvas* canvas = this->getCanvas();
215 SkASSERT(fGPUEnabled);
216
joshualittae47aee2016-03-10 13:29:36 -0800217 Json::Value result = fDebugCanvas->toJSONBatchList(n, canvas);
joshualitt1e5884b2016-02-26 08:22:49 -0800218
219 SkDynamicMemoryWStream stream;
joshualittae47aee2016-03-10 13:29:36 -0800220 stream.writeText(Json::FastWriter().write(result).c_str());
joshualitt1e5884b2016-02-26 08:22:49 -0800221
222 return stream.copyToData();
223}
joshualittee5348b2016-02-26 08:36:25 -0800224
225SkData* Request::getJsonInfo(int n) {
226 // drawTo
227 SkAutoTUnref<SkSurface> surface(this->createCPUSurface());
228 SkCanvas* canvas = surface->getCanvas();
229
230 // TODO this is really slow and we should cache the matrix and clip
231 fDebugCanvas->drawTo(canvas, n);
232
233 // make some json
234 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
235 SkIRect clip = fDebugCanvas->getCurrentClip();
236 Json::Value info(Json::objectValue);
joshualittbd724132016-03-03 11:39:38 -0800237 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
238 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
joshualittee5348b2016-02-26 08:36:25 -0800239
240 std::string json = Json::FastWriter().write(info);
241
242 // We don't want the null terminator so strlen is correct
243 return SkData::NewWithCopy(json.c_str(), strlen(json.c_str()));
244}
joshualitte0449cf2016-03-09 10:07:02 -0800245
246SkColor Request::getPixel(int x, int y) {
247 SkCanvas* canvas = this->getCanvas();
248 canvas->flush();
249 SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
250 SkASSERT(bitmap);
251 bitmap->lockPixels();
252 uint8_t* start = ((uint8_t*) bitmap->getPixels()) + (y * bitmap->width() + x) * 4;
253 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
254 bitmap->unlockPixels();
255 return result;
256}