blob: 756f70e24d97640d53a8139c5ebad3684a8cf705 [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"
brianosman312aa6a2016-04-19 12:47:54 -070012#include "SkPM4fPriv.h"
brianosman78312952016-04-19 10:16:53 -070013#include "picture_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;
19
joshualitt4dcbe432016-02-25 10:50:28 -080020
joshualittee5348b2016-02-26 08:36:25 -080021Request::Request(SkString rootUrl)
22 : fUploadContext(nullptr)
23 , fUrlDataManager(rootUrl)
brianosman78312952016-04-19 10:16:53 -070024 , fGPUEnabled(false)
25 , fColorMode(0) {
joshualittee5348b2016-02-26 08:36:25 -080026 // create surface
joshualitt40836102016-03-11 11:45:53 -080027#if SK_SUPPORT_GPU
joshualittee5348b2016-02-26 08:36:25 -080028 GrContextOptions grContextOpts;
joshualitt40836102016-03-11 11:45:53 -080029 fContextFactory = new GrContextFactory(grContextOpts);
30#else
31 fContextFactory = nullptr;
32#endif
33}
34
35Request::~Request() {
36#if SK_SUPPORT_GPU
37 if (fContextFactory) {
38 delete fContextFactory;
39 }
40#endif
joshualittee5348b2016-02-26 08:36:25 -080041}
42
joshualitt4dcbe432016-02-25 10:50:28 -080043SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
44 SkBitmap* bmp = new SkBitmap();
brianosman78312952016-04-19 10:16:53 -070045 bmp->setInfo(canvas->imageInfo());
joshualitt4dcbe432016-02-25 10:50:28 -080046 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
brianosman78312952016-04-19 10:16:53 -070058 // Convert to format suitable for PNG output
59 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
60 SkASSERT(encodedBitmap.get());
61
joshualitt4dcbe432016-02-25 10:50:28 -080062 // write to png
63 SkDynamicMemoryWStream buffer;
brianosman78312952016-04-19 10:16:53 -070064 SkDrawCommand::WritePNG((const png_bytep) encodedBitmap->writable_data(),
65 bmp->width(), bmp->height(),
ethannicholasf67531f2016-03-21 10:19:39 -070066 buffer);
joshualitt4dcbe432016-02-25 10:50:28 -080067 return buffer.copyToData();
68}
69
70SkCanvas* Request::getCanvas() {
joshualitt40836102016-03-11 11:45:53 -080071#if SK_SUPPORT_GPU
joshualitt4dcbe432016-02-25 10:50:28 -080072 GrContextFactory* factory = fContextFactory;
bsalomon85b4b532016-04-05 11:06:27 -070073 GLTestContext* gl = factory->getContextInfo(GrContextFactory::kNativeGL_ContextType,
ethannicholas2ec06c92016-06-13 10:20:52 -070074 GrContextFactory::kNone_ContextOptions).glContext();
75 if (!gl) {
76 gl = factory->getContextInfo(GrContextFactory::kMESA_ContextType,
77 GrContextFactory::kNone_ContextOptions).glContext();
78 }
79 if (gl) {
80 gl->makeCurrent();
81 }
joshualitt40836102016-03-11 11:45:53 -080082#endif
joshualitt4dcbe432016-02-25 10:50:28 -080083 SkASSERT(fDebugCanvas);
joshualitte0449cf2016-03-09 10:07:02 -080084
85 // create the appropriate surface if necessary
86 if (!fSurface) {
87 this->enableGPU(fGPUEnabled);
88 }
joshualitt4dcbe432016-02-25 10:50:28 -080089 SkCanvas* target = fSurface->getCanvas();
90 return target;
91}
92
joshualitt46b301d2016-03-02 08:32:37 -080093void Request::drawToCanvas(int n, int m) {
joshualitt4dcbe432016-02-25 10:50:28 -080094 SkCanvas* target = this->getCanvas();
joshualitt46b301d2016-03-02 08:32:37 -080095 fDebugCanvas->drawTo(target, n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080096}
97
joshualitt46b301d2016-03-02 08:32:37 -080098SkData* Request::drawToPng(int n, int m) {
99 this->drawToCanvas(n, m);
joshualitt4dcbe432016-02-25 10:50:28 -0800100 return writeCanvasToPng(this->getCanvas());
101}
102
joshualitte0449cf2016-03-09 10:07:02 -0800103SkData* Request::writeOutSkp() {
104 // Playback into picture recorder
joshualittae47aee2016-03-10 13:29:36 -0800105 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800106 SkPictureRecorder recorder;
brianosman82996b82016-04-20 10:52:54 -0700107 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bounds.width()),
108 SkIntToScalar(bounds.height()));
joshualitte0449cf2016-03-09 10:07:02 -0800109
110 fDebugCanvas->draw(canvas);
111
reedca2622b2016-03-18 07:25:55 -0700112 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
joshualitte0449cf2016-03-09 10:07:02 -0800113
114 SkDynamicMemoryWStream outStream;
115
116 SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer());
117 picture->serialize(&outStream, serializer);
118
119 return outStream.copyToData();
120}
121
joshualittae47aee2016-03-10 13:29:36 -0800122GrContext* Request::getContext() {
joshualitt40836102016-03-11 11:45:53 -0800123#if SK_SUPPORT_GPU
ethannicholas2ec06c92016-06-13 10:20:52 -0700124 GrContext* result = fContextFactory->get(GrContextFactory::kNativeGL_ContextType,
125 GrContextFactory::kNone_ContextOptions);
126 if (!result) {
127 result = fContextFactory->get(GrContextFactory::kMESA_ContextType,
128 GrContextFactory::kNone_ContextOptions);
129 }
130 return result;
joshualitt40836102016-03-11 11:45:53 -0800131#else
ethannicholas2ec06c92016-06-13 10:20:52 -0700132 return nullptr;
joshualitt40836102016-03-11 11:45:53 -0800133#endif
joshualittae47aee2016-03-10 13:29:36 -0800134}
135
136SkIRect Request::getBounds() {
137 SkIRect bounds;
138 if (fPicture) {
139 bounds = fPicture->cullRect().roundOut();
140 if (fGPUEnabled) {
joshualitt40836102016-03-11 11:45:53 -0800141#if SK_SUPPORT_GPU
joshualittae47aee2016-03-10 13:29:36 -0800142 int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
143 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
144 SkTMin(bounds.height(), maxRTSize));
joshualitt40836102016-03-11 11:45:53 -0800145#endif
joshualittae47aee2016-03-10 13:29:36 -0800146 }
147 } else {
148 bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
149 }
150
151 // We clip to kDefaultWidth / kDefaultHeight for performance reasons
152 // TODO make this configurable
153 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kDefaultWidth),
154 SkTMin(bounds.height(), kDefaultHeight));
155 return bounds;
156}
157
brianosman78312952016-04-19 10:16:53 -0700158namespace {
159
160struct ColorAndProfile {
161 SkColorType fColorType;
brianosmanb109b8c2016-06-16 13:03:24 -0700162 bool fSRGB;
brianosman78312952016-04-19 10:16:53 -0700163 bool fGammaCorrect;
164};
165
166ColorAndProfile ColorModes[] = {
brianosmanb109b8c2016-06-16 13:03:24 -0700167 { kN32_SkColorType, false, false },
168 { kN32_SkColorType, true, true },
169 { kRGBA_F16_SkColorType, false, true },
brianosman78312952016-04-19 10:16:53 -0700170};
171
172}
173
joshualitt4dcbe432016-02-25 10:50:28 -0800174SkSurface* Request::createCPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800175 SkIRect bounds = this->getBounds();
brianosman78312952016-04-19 10:16:53 -0700176 ColorAndProfile cap = ColorModes[fColorMode];
brianosmanb109b8c2016-06-16 13:03:24 -0700177 auto srgbColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
brianosman78312952016-04-19 10:16:53 -0700178 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
brianosmanb109b8c2016-06-16 13:03:24 -0700179 kPremul_SkAlphaType, cap.fSRGB ? srgbColorSpace : nullptr);
brianosman78312952016-04-19 10:16:53 -0700180 uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
181 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
182 return SkSurface::MakeRaster(info, &props).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800183}
184
185SkSurface* Request::createGPUSurface() {
joshualittae47aee2016-03-10 13:29:36 -0800186 GrContext* context = this->getContext();
187 SkIRect bounds = this->getBounds();
brianosman78312952016-04-19 10:16:53 -0700188 ColorAndProfile cap = ColorModes[fColorMode];
brianosmanb109b8c2016-06-16 13:03:24 -0700189 auto srgbColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
brianosman78312952016-04-19 10:16:53 -0700190 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
brianosmanb109b8c2016-06-16 13:03:24 -0700191 kPremul_SkAlphaType, cap.fSRGB ? srgbColorSpace : nullptr);
brianosman78312952016-04-19 10:16:53 -0700192 uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
joshualitt4dcbe432016-02-25 10:50:28 -0800193 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
reede8f30622016-03-23 18:59:25 -0700194 SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
195 &props).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800196 return surface;
197}
198
brianosman78312952016-04-19 10:16:53 -0700199bool Request::setColorMode(int mode) {
200 fColorMode = mode;
201 return enableGPU(fGPUEnabled);
202}
203
brianosman312aa6a2016-04-19 12:47:54 -0700204bool Request::setSRGBMode(bool enable) {
205 gTreatSkColorAsSRGB = enable;
206 return true;
207}
208
halcanary9d524f22016-03-29 09:03:52 -0700209bool Request::enableGPU(bool enable) {
joshualittee5348b2016-02-26 08:36:25 -0800210 if (enable) {
211 SkSurface* surface = this->createGPUSurface();
212 if (surface) {
213 fSurface.reset(surface);
214 fGPUEnabled = true;
joshualitt98bd5b12016-03-11 12:08:15 -0800215
216 // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
217 // draw once to flush the pipe
218 // TODO understand what is actually happening here
brianosman78312952016-04-19 10:16:53 -0700219 if (fDebugCanvas) {
220 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
221 this->getCanvas()->flush();
222 }
joshualitt98bd5b12016-03-11 12:08:15 -0800223
joshualittee5348b2016-02-26 08:36:25 -0800224 return true;
225 }
226 return false;
227 }
228 fSurface.reset(this->createCPUSurface());
229 fGPUEnabled = false;
230 return true;
halcanary9d524f22016-03-29 09:03:52 -0700231}
joshualitt6bc96792016-02-29 05:35:04 -0800232
233bool Request::initPictureFromStream(SkStream* stream) {
234 // parse picture from stream
reedca2622b2016-03-18 07:25:55 -0700235 fPicture = SkPicture::MakeFromStream(stream);
236 if (!fPicture) {
joshualitt6bc96792016-02-29 05:35:04 -0800237 fprintf(stderr, "Could not create picture from stream.\n");
238 return false;
239 }
240
joshualittae47aee2016-03-10 13:29:36 -0800241 // reinitialize canvas with the new picture dimensions
242 this->enableGPU(fGPUEnabled);
243
joshualitt6bc96792016-02-29 05:35:04 -0800244 // pour picture into debug canvas
joshualittae47aee2016-03-10 13:29:36 -0800245 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800246 fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
joshualitt6bc96792016-02-29 05:35:04 -0800247 fDebugCanvas->drawPicture(fPicture);
joshualitt3a9be692016-02-29 11:38:11 -0800248
249 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
250 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
joshualittb0666ad2016-03-08 10:43:41 -0800251 this->getCanvas()->flush();
joshualitt6bc96792016-02-29 05:35:04 -0800252 return true;
joshualittee5348b2016-02-26 08:36:25 -0800253}
254
joshualitt1e5884b2016-02-26 08:22:49 -0800255SkData* Request::getJsonOps(int n) {
256 SkCanvas* canvas = this->getCanvas();
257 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
258 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
joshualitt5d5207a2016-02-29 12:46:04 -0800259 root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
brianosman78312952016-04-19 10:16:53 -0700260 root["colorMode"] = Json::Value(fColorMode);
brianosman312aa6a2016-04-19 12:47:54 -0700261 root["srgbMode"] = Json::Value(gTreatSkColorAsSRGB);
joshualitt1e5884b2016-02-26 08:22:49 -0800262 SkDynamicMemoryWStream stream;
263 stream.writeText(Json::FastWriter().write(root).c_str());
264
265 return stream.copyToData();
266}
267
268SkData* Request::getJsonBatchList(int n) {
269 SkCanvas* canvas = this->getCanvas();
270 SkASSERT(fGPUEnabled);
271
joshualittae47aee2016-03-10 13:29:36 -0800272 Json::Value result = fDebugCanvas->toJSONBatchList(n, canvas);
joshualitt1e5884b2016-02-26 08:22:49 -0800273
274 SkDynamicMemoryWStream stream;
joshualittae47aee2016-03-10 13:29:36 -0800275 stream.writeText(Json::FastWriter().write(result).c_str());
joshualitt1e5884b2016-02-26 08:22:49 -0800276
277 return stream.copyToData();
278}
joshualittee5348b2016-02-26 08:36:25 -0800279
280SkData* Request::getJsonInfo(int n) {
281 // drawTo
282 SkAutoTUnref<SkSurface> surface(this->createCPUSurface());
283 SkCanvas* canvas = surface->getCanvas();
284
285 // TODO this is really slow and we should cache the matrix and clip
286 fDebugCanvas->drawTo(canvas, n);
287
288 // make some json
289 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
290 SkIRect clip = fDebugCanvas->getCurrentClip();
291 Json::Value info(Json::objectValue);
joshualittbd724132016-03-03 11:39:38 -0800292 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
293 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
joshualittee5348b2016-02-26 08:36:25 -0800294
295 std::string json = Json::FastWriter().write(info);
296
297 // We don't want the null terminator so strlen is correct
298 return SkData::NewWithCopy(json.c_str(), strlen(json.c_str()));
299}
joshualitte0449cf2016-03-09 10:07:02 -0800300
301SkColor Request::getPixel(int x, int y) {
302 SkCanvas* canvas = this->getCanvas();
303 canvas->flush();
304 SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
305 SkASSERT(bitmap);
brianosman78312952016-04-19 10:16:53 -0700306
307 // Convert to format suitable for inspection
308 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
309 SkASSERT(encodedBitmap.get());
310
311 const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
joshualitte0449cf2016-03-09 10:07:02 -0800312 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
joshualitte0449cf2016-03-09 10:07:02 -0800313 return result;
314}