blob: d27f2c07926f3a7b639d3400331e2d5c308e83c9 [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;
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)
27 , fColorMode(0) {
joshualittee5348b2016-02-26 08:36:25 -080028 // create surface
joshualitt40836102016-03-11 11:45:53 -080029#if SK_SUPPORT_GPU
joshualittee5348b2016-02-26 08:36:25 -080030 GrContextOptions grContextOpts;
joshualitt40836102016-03-11 11:45:53 -080031 fContextFactory = new GrContextFactory(grContextOpts);
32#else
33 fContextFactory = nullptr;
34#endif
35}
36
37Request::~Request() {
38#if SK_SUPPORT_GPU
39 if (fContextFactory) {
40 delete fContextFactory;
41 }
42#endif
joshualittee5348b2016-02-26 08:36:25 -080043}
44
joshualitt4dcbe432016-02-25 10:50:28 -080045SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
46 SkBitmap* bmp = new SkBitmap();
brianosman78312952016-04-19 10:16:53 -070047 bmp->setInfo(canvas->imageInfo());
joshualitt4dcbe432016-02-25 10:50:28 -080048 if (!canvas->readPixels(bmp, 0, 0)) {
49 fprintf(stderr, "Can't read pixels\n");
50 return nullptr;
51 }
52 return bmp;
53}
54
bungeman38d909e2016-08-02 14:40:46 -070055sk_sp<SkData> Request::writeCanvasToPng(SkCanvas* canvas) {
joshualitt4dcbe432016-02-25 10:50:28 -080056 // capture pixels
joshualitte0449cf2016-03-09 10:07:02 -080057 SkAutoTDelete<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
joshualitt4dcbe432016-02-25 10:50:28 -080058 SkASSERT(bmp);
59
brianosman78312952016-04-19 10:16:53 -070060 // Convert to format suitable for PNG output
61 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
62 SkASSERT(encodedBitmap.get());
63
msaretta5cf4f42016-06-30 10:06:51 -070064 // write to an opaque png (black background)
joshualitt4dcbe432016-02-25 10:50:28 -080065 SkDynamicMemoryWStream buffer;
msaretta5cf4f42016-06-30 10:06:51 -070066 SkDrawCommand::WritePNG((const png_bytep) encodedBitmap->bytes(), bmp->width(), bmp->height(),
67 buffer, true);
reed42943c82016-09-12 12:01:44 -070068 return buffer.detachAsData();
joshualitt4dcbe432016-02-25 10:50:28 -080069}
70
71SkCanvas* Request::getCanvas() {
joshualitt40836102016-03-11 11:45:53 -080072#if SK_SUPPORT_GPU
joshualitt4dcbe432016-02-25 10:50:28 -080073 GrContextFactory* factory = fContextFactory;
bsalomon85b4b532016-04-05 11:06:27 -070074 GLTestContext* gl = factory->getContextInfo(GrContextFactory::kNativeGL_ContextType,
csmartdalton6270e552016-09-13 10:41:49 -070075 GrContextFactory::ContextOptions::kNone).glContext();
ethannicholas2ec06c92016-06-13 10:20:52 -070076 if (!gl) {
77 gl = factory->getContextInfo(GrContextFactory::kMESA_ContextType,
csmartdalton6270e552016-09-13 10:41:49 -070078 GrContextFactory::ContextOptions::kNone).glContext();
ethannicholas2ec06c92016-06-13 10:20:52 -070079 }
80 if (gl) {
81 gl->makeCurrent();
82 }
joshualitt40836102016-03-11 11:45:53 -080083#endif
joshualitt4dcbe432016-02-25 10:50:28 -080084 SkASSERT(fDebugCanvas);
joshualitte0449cf2016-03-09 10:07:02 -080085
86 // create the appropriate surface if necessary
87 if (!fSurface) {
88 this->enableGPU(fGPUEnabled);
89 }
joshualitt4dcbe432016-02-25 10:50:28 -080090 SkCanvas* target = fSurface->getCanvas();
91 return target;
92}
93
joshualitt46b301d2016-03-02 08:32:37 -080094void Request::drawToCanvas(int n, int m) {
joshualitt4dcbe432016-02-25 10:50:28 -080095 SkCanvas* target = this->getCanvas();
joshualitt46b301d2016-03-02 08:32:37 -080096 fDebugCanvas->drawTo(target, n, m);
joshualitt4dcbe432016-02-25 10:50:28 -080097}
98
bungeman38d909e2016-08-02 14:40:46 -070099sk_sp<SkData> Request::drawToPng(int n, int m) {
joshualitt46b301d2016-03-02 08:32:37 -0800100 this->drawToCanvas(n, m);
joshualitt4dcbe432016-02-25 10:50:28 -0800101 return writeCanvasToPng(this->getCanvas());
102}
103
bungeman38d909e2016-08-02 14:40:46 -0700104sk_sp<SkData> Request::writeOutSkp() {
joshualitte0449cf2016-03-09 10:07:02 -0800105 // Playback into picture recorder
joshualittae47aee2016-03-10 13:29:36 -0800106 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800107 SkPictureRecorder recorder;
brianosman82996b82016-04-20 10:52:54 -0700108 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bounds.width()),
109 SkIntToScalar(bounds.height()));
joshualitte0449cf2016-03-09 10:07:02 -0800110
111 fDebugCanvas->draw(canvas);
112
reedca2622b2016-03-18 07:25:55 -0700113 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
joshualitte0449cf2016-03-09 10:07:02 -0800114
115 SkDynamicMemoryWStream outStream;
116
117 SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer());
118 picture->serialize(&outStream, serializer);
119
reed42943c82016-09-12 12:01:44 -0700120 return outStream.detachAsData();
joshualitte0449cf2016-03-09 10:07:02 -0800121}
122
joshualittae47aee2016-03-10 13:29:36 -0800123GrContext* Request::getContext() {
joshualitt40836102016-03-11 11:45:53 -0800124#if SK_SUPPORT_GPU
ethannicholas2ec06c92016-06-13 10:20:52 -0700125 GrContext* result = fContextFactory->get(GrContextFactory::kNativeGL_ContextType,
csmartdalton6270e552016-09-13 10:41:49 -0700126 GrContextFactory::ContextOptions::kNone);
ethannicholas2ec06c92016-06-13 10:20:52 -0700127 if (!result) {
128 result = fContextFactory->get(GrContextFactory::kMESA_ContextType,
csmartdalton6270e552016-09-13 10:41:49 -0700129 GrContextFactory::ContextOptions::kNone);
jcgregorio9a7acdc2016-06-30 07:54:14 -0700130 }
ethannicholas2ec06c92016-06-13 10:20:52 -0700131 return result;
joshualitt40836102016-03-11 11:45:53 -0800132#else
ethannicholas2ec06c92016-06-13 10:20:52 -0700133 return nullptr;
joshualitt40836102016-03-11 11:45:53 -0800134#endif
joshualittae47aee2016-03-10 13:29:36 -0800135}
136
137SkIRect Request::getBounds() {
138 SkIRect bounds;
139 if (fPicture) {
140 bounds = fPicture->cullRect().roundOut();
141 if (fGPUEnabled) {
joshualitt40836102016-03-11 11:45:53 -0800142#if SK_SUPPORT_GPU
joshualittae47aee2016-03-10 13:29:36 -0800143 int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
144 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
145 SkTMin(bounds.height(), maxRTSize));
joshualitt40836102016-03-11 11:45:53 -0800146#endif
joshualittae47aee2016-03-10 13:29:36 -0800147 }
148 } else {
149 bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
150 }
151
jcgregorio9a7acdc2016-06-30 07:54:14 -0700152 // We clip to kMaxWidth / kMaxHeight for performance reasons.
joshualittae47aee2016-03-10 13:29:36 -0800153 // TODO make this configurable
jcgregorio9a7acdc2016-06-30 07:54:14 -0700154 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kMaxWidth),
155 SkTMin(bounds.height(), kMaxHeight));
joshualittae47aee2016-03-10 13:29:36 -0800156 return bounds;
157}
158
brianosman78312952016-04-19 10:16:53 -0700159namespace {
160
161struct ColorAndProfile {
162 SkColorType fColorType;
brianosmanb109b8c2016-06-16 13:03:24 -0700163 bool fSRGB;
brianosman78312952016-04-19 10:16:53 -0700164};
165
166ColorAndProfile ColorModes[] = {
brianosman3a0dbde2016-07-26 11:36:05 -0700167 { kN32_SkColorType, false },
168 { kN32_SkColorType, true },
169 { kRGBA_F16_SkColorType, 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];
raftias7c602de2016-10-13 10:45:44 -0700177 auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
178 ? SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named)
179 : SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
brianosman78312952016-04-19 10:16:53 -0700180 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
brianosman0e22eb82016-08-30 07:07:59 -0700181 kPremul_SkAlphaType, cap.fSRGB ? colorSpace : nullptr);
brianosman3a0dbde2016-07-26 11:36:05 -0700182 return SkSurface::MakeRaster(info).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];
raftias7c602de2016-10-13 10:45:44 -0700189 auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
190 ? SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named)
191 : SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
brianosman78312952016-04-19 10:16:53 -0700192 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
brianosman0e22eb82016-08-30 07:07:59 -0700193 kPremul_SkAlphaType, cap.fSRGB ? colorSpace: nullptr);
brianosman3a0dbde2016-07-26 11:36:05 -0700194 SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info).release();
joshualitt4dcbe432016-02-25 10:50:28 -0800195 return surface;
196}
197
brianosman78312952016-04-19 10:16:53 -0700198bool Request::setColorMode(int mode) {
199 fColorMode = mode;
200 return enableGPU(fGPUEnabled);
201}
202
halcanary9d524f22016-03-29 09:03:52 -0700203bool Request::enableGPU(bool enable) {
joshualittee5348b2016-02-26 08:36:25 -0800204 if (enable) {
205 SkSurface* surface = this->createGPUSurface();
206 if (surface) {
207 fSurface.reset(surface);
208 fGPUEnabled = true;
joshualitt98bd5b12016-03-11 12:08:15 -0800209
210 // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
211 // draw once to flush the pipe
212 // TODO understand what is actually happening here
brianosman78312952016-04-19 10:16:53 -0700213 if (fDebugCanvas) {
214 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
215 this->getCanvas()->flush();
216 }
joshualitt98bd5b12016-03-11 12:08:15 -0800217
joshualittee5348b2016-02-26 08:36:25 -0800218 return true;
219 }
220 return false;
221 }
222 fSurface.reset(this->createCPUSurface());
223 fGPUEnabled = false;
224 return true;
halcanary9d524f22016-03-29 09:03:52 -0700225}
joshualitt6bc96792016-02-29 05:35:04 -0800226
227bool Request::initPictureFromStream(SkStream* stream) {
228 // parse picture from stream
reedca2622b2016-03-18 07:25:55 -0700229 fPicture = SkPicture::MakeFromStream(stream);
230 if (!fPicture) {
joshualitt6bc96792016-02-29 05:35:04 -0800231 fprintf(stderr, "Could not create picture from stream.\n");
232 return false;
233 }
234
joshualittae47aee2016-03-10 13:29:36 -0800235 // reinitialize canvas with the new picture dimensions
236 this->enableGPU(fGPUEnabled);
237
joshualitt6bc96792016-02-29 05:35:04 -0800238 // pour picture into debug canvas
joshualittae47aee2016-03-10 13:29:36 -0800239 SkIRect bounds = this->getBounds();
joshualitte0449cf2016-03-09 10:07:02 -0800240 fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
joshualitt6bc96792016-02-29 05:35:04 -0800241 fDebugCanvas->drawPicture(fPicture);
joshualitt3a9be692016-02-29 11:38:11 -0800242
243 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
244 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
joshualittb0666ad2016-03-08 10:43:41 -0800245 this->getCanvas()->flush();
joshualitt6bc96792016-02-29 05:35:04 -0800246 return true;
joshualittee5348b2016-02-26 08:36:25 -0800247}
248
bungeman38d909e2016-08-02 14:40:46 -0700249sk_sp<SkData> Request::getJsonOps(int n) {
joshualitt1e5884b2016-02-26 08:22:49 -0800250 SkCanvas* canvas = this->getCanvas();
251 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
252 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
joshualitt5d5207a2016-02-29 12:46:04 -0800253 root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
brianosman78312952016-04-19 10:16:53 -0700254 root["colorMode"] = Json::Value(fColorMode);
joshualitt1e5884b2016-02-26 08:22:49 -0800255 SkDynamicMemoryWStream stream;
256 stream.writeText(Json::FastWriter().write(root).c_str());
257
reed42943c82016-09-12 12:01:44 -0700258 return stream.detachAsData();
joshualitt1e5884b2016-02-26 08:22:49 -0800259}
260
bungeman38d909e2016-08-02 14:40:46 -0700261sk_sp<SkData> Request::getJsonBatchList(int n) {
joshualitt1e5884b2016-02-26 08:22:49 -0800262 SkCanvas* canvas = this->getCanvas();
263 SkASSERT(fGPUEnabled);
264
joshualittae47aee2016-03-10 13:29:36 -0800265 Json::Value result = fDebugCanvas->toJSONBatchList(n, canvas);
joshualitt1e5884b2016-02-26 08:22:49 -0800266
267 SkDynamicMemoryWStream stream;
joshualittae47aee2016-03-10 13:29:36 -0800268 stream.writeText(Json::FastWriter().write(result).c_str());
joshualitt1e5884b2016-02-26 08:22:49 -0800269
reed42943c82016-09-12 12:01:44 -0700270 return stream.detachAsData();
joshualitt1e5884b2016-02-26 08:22:49 -0800271}
joshualittee5348b2016-02-26 08:36:25 -0800272
bungeman38d909e2016-08-02 14:40:46 -0700273sk_sp<SkData> Request::getJsonInfo(int n) {
joshualittee5348b2016-02-26 08:36:25 -0800274 // drawTo
275 SkAutoTUnref<SkSurface> surface(this->createCPUSurface());
276 SkCanvas* canvas = surface->getCanvas();
277
278 // TODO this is really slow and we should cache the matrix and clip
279 fDebugCanvas->drawTo(canvas, n);
280
281 // make some json
282 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
283 SkIRect clip = fDebugCanvas->getCurrentClip();
284 Json::Value info(Json::objectValue);
joshualittbd724132016-03-03 11:39:38 -0800285 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
286 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
joshualittee5348b2016-02-26 08:36:25 -0800287
288 std::string json = Json::FastWriter().write(info);
289
290 // We don't want the null terminator so strlen is correct
bungeman38d909e2016-08-02 14:40:46 -0700291 return SkData::MakeWithCopy(json.c_str(), strlen(json.c_str()));
joshualittee5348b2016-02-26 08:36:25 -0800292}
joshualitte0449cf2016-03-09 10:07:02 -0800293
294SkColor Request::getPixel(int x, int y) {
295 SkCanvas* canvas = this->getCanvas();
296 canvas->flush();
297 SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
298 SkASSERT(bitmap);
brianosman78312952016-04-19 10:16:53 -0700299
300 // Convert to format suitable for inspection
301 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
reed42943c82016-09-12 12:01:44 -0700302 SkASSERT(encodedBitmap);
brianosman78312952016-04-19 10:16:53 -0700303
304 const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
joshualitte0449cf2016-03-09 10:07:02 -0800305 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
joshualitte0449cf2016-03-09 10:07:02 -0800306 return result;
307}