1 /*
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
10 #include "SkPictureRecorder.h"
11 #include "SkPixelSerializer.h"
12 #include "SkPM4fPriv.h"
13 #include "picture_utils.h"
14 #include "sk_tool_utils.h"
15
16 using namespace sk_gpu_test;
17
18 static int kDefaultWidth = 1920;
19 static int kDefaultHeight = 1080;
20 static int kMaxWidth = 8192;
21 static int kMaxHeight = 8192;
22
23
Request(SkString rootUrl)24 Request::Request(SkString rootUrl)
25 : fUploadContext(nullptr)
26 , fUrlDataManager(rootUrl)
27 , fGPUEnabled(false)
28 , fOverdraw(false)
29 , fColorMode(0) {
30 // create surface
31 #if SK_SUPPORT_GPU
32 GrContextOptions grContextOpts;
33 fContextFactory = new GrContextFactory(grContextOpts);
34 #else
35 fContextFactory = nullptr;
36 #endif
37 }
38
~Request()39 Request::~Request() {
40 #if SK_SUPPORT_GPU
41 if (fContextFactory) {
42 delete fContextFactory;
43 }
44 #endif
45 }
46
getBitmapFromCanvas(SkCanvas * canvas)47 SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
48 SkBitmap* bmp = new SkBitmap();
49 if (!bmp->tryAllocPixels(canvas->imageInfo()) || !canvas->readPixels(*bmp, 0, 0)) {
50 fprintf(stderr, "Can't read pixels\n");
51 delete bmp;
52 return nullptr;
53 }
54 return bmp;
55 }
56
writeCanvasToPng(SkCanvas * canvas)57 sk_sp<SkData> Request::writeCanvasToPng(SkCanvas* canvas) {
58 // capture pixels
59 std::unique_ptr<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
60 SkASSERT(bmp);
61
62 // Convert to format suitable for PNG output
63 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
64 SkASSERT(encodedBitmap.get());
65
66 // write to an opaque png (black background)
67 SkDynamicMemoryWStream buffer;
68 SkDrawCommand::WritePNG(encodedBitmap->bytes(), bmp->width(), bmp->height(),
69 buffer, true);
70 return buffer.detachAsData();
71 }
72
getCanvas()73 SkCanvas* Request::getCanvas() {
74 #if SK_SUPPORT_GPU
75 GrContextFactory* factory = fContextFactory;
76 GLTestContext* gl = factory->getContextInfo(GrContextFactory::kGL_ContextType,
77 GrContextFactory::ContextOverrides::kNone).glContext();
78 if (!gl) {
79 gl = factory->getContextInfo(GrContextFactory::kGLES_ContextType,
80 GrContextFactory::ContextOverrides::kNone).glContext();
81 }
82 if (!gl) {
83 gl = factory->getContextInfo(GrContextFactory::kMESA_ContextType,
84 GrContextFactory::ContextOverrides::kNone).glContext();
85 }
86 if (gl) {
87 gl->makeCurrent();
88 }
89 #endif
90 SkASSERT(fDebugCanvas);
91
92 // create the appropriate surface if necessary
93 if (!fSurface) {
94 this->enableGPU(fGPUEnabled);
95 }
96 SkCanvas* target = fSurface->getCanvas();
97 return target;
98 }
99
drawToCanvas(int n,int m)100 void Request::drawToCanvas(int n, int m) {
101 SkCanvas* target = this->getCanvas();
102 fDebugCanvas->drawTo(target, n, m);
103 }
104
drawToPng(int n,int m)105 sk_sp<SkData> Request::drawToPng(int n, int m) {
106 //fDebugCanvas->setOverdrawViz(true);
107 this->drawToCanvas(n, m);
108 //fDebugCanvas->setOverdrawViz(false);
109 return writeCanvasToPng(this->getCanvas());
110 }
111
writeOutSkp()112 sk_sp<SkData> Request::writeOutSkp() {
113 // Playback into picture recorder
114 SkIRect bounds = this->getBounds();
115 SkPictureRecorder recorder;
116 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bounds.width()),
117 SkIntToScalar(bounds.height()));
118
119 fDebugCanvas->draw(canvas);
120
121 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
122
123 SkDynamicMemoryWStream outStream;
124
125 sk_sp<SkPixelSerializer> serializer = sk_tool_utils::MakePixelSerializer();
126 picture->serialize(&outStream, serializer.get());
127
128 return outStream.detachAsData();
129 }
130
getContext()131 GrContext* Request::getContext() {
132 #if SK_SUPPORT_GPU
133 GrContext* result = fContextFactory->get(GrContextFactory::kGL_ContextType,
134 GrContextFactory::ContextOverrides::kNone);
135 if (!result) {
136 result = fContextFactory->get(GrContextFactory::kGLES_ContextType,
137 GrContextFactory::ContextOverrides::kNone);
138 }
139 if (!result) {
140 result = fContextFactory->get(GrContextFactory::kMESA_ContextType,
141 GrContextFactory::ContextOverrides::kNone);
142 }
143 return result;
144 #else
145 return nullptr;
146 #endif
147 }
148
getBounds()149 SkIRect Request::getBounds() {
150 SkIRect bounds;
151 if (fPicture) {
152 bounds = fPicture->cullRect().roundOut();
153 if (fGPUEnabled) {
154 #if SK_SUPPORT_GPU
155 int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
156 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
157 SkTMin(bounds.height(), maxRTSize));
158 #endif
159 }
160 } else {
161 bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
162 }
163
164 // We clip to kMaxWidth / kMaxHeight for performance reasons.
165 // TODO make this configurable
166 bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kMaxWidth),
167 SkTMin(bounds.height(), kMaxHeight));
168 return bounds;
169 }
170
171 namespace {
172
173 struct ColorAndProfile {
174 SkColorType fColorType;
175 bool fSRGB;
176 };
177
178 ColorAndProfile ColorModes[] = {
179 { kN32_SkColorType, false },
180 { kN32_SkColorType, true },
181 { kRGBA_F16_SkColorType, true },
182 };
183
184 }
185
createCPUSurface()186 SkSurface* Request::createCPUSurface() {
187 SkIRect bounds = this->getBounds();
188 ColorAndProfile cap = ColorModes[fColorMode];
189 auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
190 ? SkColorSpace::MakeSRGBLinear()
191 : SkColorSpace::MakeSRGB();
192 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
193 kPremul_SkAlphaType, cap.fSRGB ? colorSpace : nullptr);
194 return SkSurface::MakeRaster(info).release();
195 }
196
createGPUSurface()197 SkSurface* Request::createGPUSurface() {
198 GrContext* context = this->getContext();
199 SkIRect bounds = this->getBounds();
200 ColorAndProfile cap = ColorModes[fColorMode];
201 auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
202 ? SkColorSpace::MakeSRGBLinear()
203 : SkColorSpace::MakeSRGB();
204 SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
205 kPremul_SkAlphaType, cap.fSRGB ? colorSpace: nullptr);
206 SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info).release();
207 return surface;
208 }
209
setOverdraw(bool enable)210 bool Request::setOverdraw(bool enable) {
211 fOverdraw = enable;
212 return true;
213 }
214
setColorMode(int mode)215 bool Request::setColorMode(int mode) {
216 fColorMode = mode;
217 return enableGPU(fGPUEnabled);
218 }
219
enableGPU(bool enable)220 bool Request::enableGPU(bool enable) {
221 if (enable) {
222 SkSurface* surface = this->createGPUSurface();
223 if (surface) {
224 fSurface.reset(surface);
225 fGPUEnabled = true;
226
227 // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
228 // draw once to flush the pipe
229 // TODO understand what is actually happening here
230 if (fDebugCanvas) {
231 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
232 this->getCanvas()->flush();
233 }
234
235 return true;
236 }
237 return false;
238 }
239 fSurface.reset(this->createCPUSurface());
240 fGPUEnabled = false;
241 return true;
242 }
243
initPictureFromStream(SkStream * stream)244 bool Request::initPictureFromStream(SkStream* stream) {
245 // parse picture from stream
246 fPicture = SkPicture::MakeFromStream(stream);
247 if (!fPicture) {
248 fprintf(stderr, "Could not create picture from stream.\n");
249 return false;
250 }
251
252 // reinitialize canvas with the new picture dimensions
253 this->enableGPU(fGPUEnabled);
254
255 // pour picture into debug canvas
256 SkIRect bounds = this->getBounds();
257 fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
258 fDebugCanvas->drawPicture(fPicture);
259
260 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
261 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
262 this->getCanvas()->flush();
263 return true;
264 }
265
getJsonOps(int n)266 sk_sp<SkData> Request::getJsonOps(int n) {
267 SkCanvas* canvas = this->getCanvas();
268 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
269 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
270 root["drawGpuOpBounds"] = Json::Value(fDebugCanvas->getDrawGpuOpBounds());
271 root["colorMode"] = Json::Value(fColorMode);
272 SkDynamicMemoryWStream stream;
273 stream.writeText(Json::FastWriter().write(root).c_str());
274
275 return stream.detachAsData();
276 }
277
getJsonOpList(int n)278 sk_sp<SkData> Request::getJsonOpList(int n) {
279 SkCanvas* canvas = this->getCanvas();
280 SkASSERT(fGPUEnabled);
281
282 Json::Value result = fDebugCanvas->toJSONOpList(n, canvas);
283
284 SkDynamicMemoryWStream stream;
285 stream.writeText(Json::FastWriter().write(result).c_str());
286
287 return stream.detachAsData();
288 }
289
getJsonInfo(int n)290 sk_sp<SkData> Request::getJsonInfo(int n) {
291 // drawTo
292 sk_sp<SkSurface> surface(this->createCPUSurface());
293 SkCanvas* canvas = surface->getCanvas();
294
295 // TODO this is really slow and we should cache the matrix and clip
296 fDebugCanvas->drawTo(canvas, n);
297
298 // make some json
299 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
300 SkIRect clip = fDebugCanvas->getCurrentClip();
301 Json::Value info(Json::objectValue);
302 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
303 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
304
305 std::string json = Json::FastWriter().write(info);
306
307 // We don't want the null terminator so strlen is correct
308 return SkData::MakeWithCopy(json.c_str(), strlen(json.c_str()));
309 }
310
getPixel(int x,int y)311 SkColor Request::getPixel(int x, int y) {
312 SkCanvas* canvas = this->getCanvas();
313 canvas->flush();
314 std::unique_ptr<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
315 SkASSERT(bitmap);
316
317 // Convert to format suitable for inspection
318 sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
319 SkASSERT(encodedBitmap);
320
321 const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
322 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
323 return result;
324 }
325