blob: 46e3039aad95acfddf651f13d1eb701d1769adfd [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
10#include "png.h"
11
12const int Request::kImageWidth = 1920;
13const int Request::kImageHeight = 1080;
14
15static void write_png_callback(png_structp png_ptr, png_bytep data, png_size_t length) {
16 SkWStream* out = (SkWStream*) png_get_io_ptr(png_ptr);
17 out->write(data, length);
18}
19
20static void write_png(const png_bytep rgba, png_uint_32 width, png_uint_32 height, SkWStream& out) {
21 png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
22 SkASSERT(png != nullptr);
23 png_infop info_ptr = png_create_info_struct(png);
24 SkASSERT(info_ptr != nullptr);
25 if (setjmp(png_jmpbuf(png))) {
26 SkFAIL("png encode error");
27 }
28 png_set_IHDR(png, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
29 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
30 png_set_compression_level(png, 1);
31 png_bytepp rows = (png_bytepp) sk_malloc_throw(height * sizeof(png_byte*));
32 png_bytep pixels = (png_bytep) sk_malloc_throw(width * height * 3);
33 for (png_size_t y = 0; y < height; ++y) {
34 const png_bytep src = rgba + y * width * 4;
35 rows[y] = pixels + y * width * 3;
36 // convert from RGBA to RGB
37 for (png_size_t x = 0; x < width; ++x) {
38 rows[y][x * 3] = src[x * 4];
39 rows[y][x * 3 + 1] = src[x * 4 + 1];
40 rows[y][x * 3 + 2] = src[x * 4 + 2];
41 }
42 }
43 png_set_filter(png, 0, PNG_NO_FILTERS);
44 png_set_rows(png, info_ptr, &rows[0]);
45 png_set_write_fn(png, &out, write_png_callback, NULL);
46 png_write_png(png, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
47 png_destroy_write_struct(&png, NULL);
48 sk_free(rows);
49}
50
joshualittee5348b2016-02-26 08:36:25 -080051Request::Request(SkString rootUrl)
52 : fUploadContext(nullptr)
53 , fUrlDataManager(rootUrl)
54 , fGPUEnabled(false) {
55 // create surface
56 GrContextOptions grContextOpts;
57 fContextFactory.reset(new GrContextFactory(grContextOpts));
58 fSurface.reset(this->createCPUSurface());
59}
60
joshualitt4dcbe432016-02-25 10:50:28 -080061SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
62 SkBitmap* bmp = new SkBitmap();
63 SkImageInfo info = SkImageInfo::Make(kImageWidth, kImageHeight, kRGBA_8888_SkColorType,
64 kOpaque_SkAlphaType);
65 bmp->setInfo(info);
66 if (!canvas->readPixels(bmp, 0, 0)) {
67 fprintf(stderr, "Can't read pixels\n");
68 return nullptr;
69 }
70 return bmp;
71}
72
73SkData* Request::writeCanvasToPng(SkCanvas* canvas) {
74 // capture pixels
75 SkAutoTDelete<SkBitmap> bmp(getBitmapFromCanvas(canvas));
76 SkASSERT(bmp);
77
78 // write to png
79 SkDynamicMemoryWStream buffer;
80 write_png((const png_bytep) bmp->getPixels(), bmp->width(), bmp->height(), buffer);
81 return buffer.copyToData();
82}
83
84SkCanvas* Request::getCanvas() {
85 GrContextFactory* factory = fContextFactory;
86 SkGLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContextType,
87 GrContextFactory::kNone_GLContextOptions).fGLContext;
88 gl->makeCurrent();
89 SkASSERT(fDebugCanvas);
90 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
joshualitt46b301d2016-03-02 08:32:37 -080099SkData* Request::drawToPng(int n, int m) {
100 this->drawToCanvas(n, m);
joshualitt4dcbe432016-02-25 10:50:28 -0800101 return writeCanvasToPng(this->getCanvas());
102}
103
104SkSurface* Request::createCPUSurface() {
105 SkImageInfo info = SkImageInfo::Make(kImageWidth, kImageHeight, kN32_SkColorType,
106 kPremul_SkAlphaType);
107 return SkSurface::NewRaster(info);
108}
109
110SkSurface* Request::createGPUSurface() {
111 GrContext* context = fContextFactory->get(GrContextFactory::kNative_GLContextType,
112 GrContextFactory::kNone_GLContextOptions);
113 int maxRTSize = context->caps()->maxRenderTargetSize();
114 SkImageInfo info = SkImageInfo::Make(SkTMin(kImageWidth, maxRTSize),
115 SkTMin(kImageHeight, maxRTSize),
116 kN32_SkColorType, kPremul_SkAlphaType);
117 uint32_t flags = 0;
118 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
119 SkSurface* surface = SkSurface::NewRenderTarget(context, SkBudgeted::kNo, info, 0,
120 &props);
121 return surface;
122}
123
joshualittee5348b2016-02-26 08:36:25 -0800124bool Request::enableGPU(bool enable) {
125 if (enable) {
126 SkSurface* surface = this->createGPUSurface();
127 if (surface) {
128 fSurface.reset(surface);
129 fGPUEnabled = true;
130 return true;
131 }
132 return false;
133 }
134 fSurface.reset(this->createCPUSurface());
135 fGPUEnabled = false;
136 return true;
joshualitt6bc96792016-02-29 05:35:04 -0800137}
138
139bool Request::initPictureFromStream(SkStream* stream) {
140 // parse picture from stream
141 fPicture.reset(SkPicture::CreateFromStream(stream));
142 if (!fPicture.get()) {
143 fprintf(stderr, "Could not create picture from stream.\n");
144 return false;
145 }
146
147 // pour picture into debug canvas
148 fDebugCanvas.reset(new SkDebugCanvas(kImageWidth, Request::kImageHeight));
149 fDebugCanvas->drawPicture(fPicture);
joshualitt3a9be692016-02-29 11:38:11 -0800150
151 // for some reason we need to 'flush' the debug canvas by drawing all of the ops
152 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
joshualitt6bc96792016-02-29 05:35:04 -0800153 return true;
joshualittee5348b2016-02-26 08:36:25 -0800154}
155
joshualittb95c7722016-02-29 07:44:02 -0800156GrAuditTrail* Request::getAuditTrail(SkCanvas* canvas) {
157 GrAuditTrail* at = nullptr;
158#if SK_SUPPORT_GPU
159 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
160 if (rt) {
161 GrContext* ctx = rt->getContext();
162 if (ctx) {
163 at = ctx->getAuditTrail();
164 }
165 }
166#endif
167 return at;
168}
169
170void Request::cleanupAuditTrail(SkCanvas* canvas) {
171 GrAuditTrail* at = this->getAuditTrail(canvas);
172 if (at) {
173 GrAuditTrail::AutoEnable ae(at);
174 at->fullReset();
175 }
176}
177
joshualitt1e5884b2016-02-26 08:22:49 -0800178SkData* Request::getJsonOps(int n) {
179 SkCanvas* canvas = this->getCanvas();
180 Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
181 root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
joshualitt5d5207a2016-02-29 12:46:04 -0800182 root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
joshualitt1e5884b2016-02-26 08:22:49 -0800183 SkDynamicMemoryWStream stream;
184 stream.writeText(Json::FastWriter().write(root).c_str());
185
joshualittb95c7722016-02-29 07:44:02 -0800186 this->cleanupAuditTrail(canvas);
187
joshualitt1e5884b2016-02-26 08:22:49 -0800188 return stream.copyToData();
189}
190
191SkData* Request::getJsonBatchList(int n) {
192 SkCanvas* canvas = this->getCanvas();
193 SkASSERT(fGPUEnabled);
194
195 // TODO if this is inefficient we could add a method to GrAuditTrail which takes
196 // a Json::Value and is only compiled in this file
197 Json::Value parsedFromString;
198#if SK_SUPPORT_GPU
joshualitt3a9be692016-02-29 11:38:11 -0800199 // we use the toJSON method on debug canvas, but then just ignore the results and pull
200 // the information we care about from the audit trail
201 fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
202
joshualittb95c7722016-02-29 07:44:02 -0800203 GrAuditTrail* at = this->getAuditTrail(canvas);
joshualitt1e5884b2016-02-26 08:22:49 -0800204 GrAuditTrail::AutoManageBatchList enable(at);
joshualitt1e5884b2016-02-26 08:22:49 -0800205 Json::Reader reader;
joshualitt3a9be692016-02-29 11:38:11 -0800206 SkDEBUGCODE(bool parsingSuccessful = )reader.parse(at->toJson().c_str(),
joshualitt1e5884b2016-02-26 08:22:49 -0800207 parsedFromString);
208 SkASSERT(parsingSuccessful);
209#endif
210
211 SkDynamicMemoryWStream stream;
212 stream.writeText(Json::FastWriter().write(parsedFromString).c_str());
213
214 return stream.copyToData();
215}
joshualittee5348b2016-02-26 08:36:25 -0800216
217SkData* Request::getJsonInfo(int n) {
218 // drawTo
219 SkAutoTUnref<SkSurface> surface(this->createCPUSurface());
220 SkCanvas* canvas = surface->getCanvas();
221
222 // TODO this is really slow and we should cache the matrix and clip
223 fDebugCanvas->drawTo(canvas, n);
224
225 // make some json
226 SkMatrix vm = fDebugCanvas->getCurrentMatrix();
227 SkIRect clip = fDebugCanvas->getCurrentClip();
228 Json::Value info(Json::objectValue);
joshualittbd724132016-03-03 11:39:38 -0800229 info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
230 info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
joshualittee5348b2016-02-26 08:36:25 -0800231
232 std::string json = Json::FastWriter().write(info);
233
234 // We don't want the null terminator so strlen is correct
235 return SkData::NewWithCopy(json.c_str(), strlen(json.c_str()));
236}