blob: f000025e6a119ed2f997d7dc4d162ca00372e609 [file] [log] [blame]
halcanarydecb21e2015-12-10 07:52:45 -08001/*
2 * Copyright 2015 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
Hal Canary169f37f2017-02-15 10:20:30 -05008#include <cstdio>
9#include <cstdlib>
10#include <sstream>
Joe Gregorio1fd18232017-02-13 11:39:43 -050011#include <string>
halcanarydecb21e2015-12-10 07:52:45 -080012
Brian Osman250e6e82017-12-12 16:24:41 -050013#include "SkAutoPixmapStorage.h"
Joe Gregorio1e735c02017-04-19 14:05:14 -040014#include "SkCommandLineFlags.h"
Robert Phillipsc34aa9d2017-11-17 14:59:43 -050015#include "SkMipMap.h"
Robert Phillips57e08282017-11-16 14:59:48 -050016#include "SkUtils.h"
Joe Gregorio1e735c02017-04-19 14:05:14 -040017
halcanarydecb21e2015-12-10 07:52:45 -080018#include "fiddle_main.h"
19
Joe Gregorio1e735c02017-04-19 14:05:14 -040020DEFINE_double(duration, 1.0, "The total duration, in seconds, of the animation we are drawing.");
21DEFINE_double(frame, 1.0, "A double value in [0, 1] that specifies the point in animation to draw.");
22
Robert Phillips57e08282017-11-16 14:59:48 -050023#include "GrBackendSurface.h"
24#include "GrContextPriv.h"
25#include "GrGpu.h"
Robert Phillips57e08282017-11-16 14:59:48 -050026#include "GrTest.h"
Joe Gregorio8e9810c2018-05-29 13:56:27 -040027#include "gl/GLTestContext.h"
Robert Phillips57e08282017-11-16 14:59:48 -050028
halcanarydecb21e2015-12-10 07:52:45 -080029// Globals externed in fiddle_main.h
Robert Phillips57e08282017-11-16 14:59:48 -050030sk_sp<GrTexture> backingTexture; // not externed
31GrBackendTexture backEndTexture;
32
33sk_sp<GrRenderTarget> backingRenderTarget; // not externed
34GrBackendRenderTarget backEndRenderTarget;
35
36sk_sp<GrTexture> backingTextureRenderTarget; // not externed
37GrBackendTexture backEndTextureRenderTarget;
38
halcanarydecb21e2015-12-10 07:52:45 -080039SkBitmap source;
halcanary7b8b2372016-04-18 08:17:56 -070040sk_sp<SkImage> image;
Joe Gregorio1e735c02017-04-19 14:05:14 -040041double duration; // The total duration of the animation in seconds.
42double frame; // A value in [0, 1] of where we are in the animation.
halcanarydecb21e2015-12-10 07:52:45 -080043
Hal Canary169f37f2017-02-15 10:20:30 -050044// Global used by the local impl of SkDebugf.
45std::ostringstream gTextOutput;
Joe Gregorio1fd18232017-02-13 11:39:43 -050046
Joe Gregorio97b10ac2017-06-01 13:24:11 -040047// Global to record the GL driver info via create_grcontext().
48std::ostringstream gGLDriverInfo;
49
Joe Gregorio1fd18232017-02-13 11:39:43 -050050void SkDebugf(const char * fmt, ...) {
Joe Gregorio1fd18232017-02-13 11:39:43 -050051 va_list args;
52 va_start(args, fmt);
Hal Canary169f37f2017-02-15 10:20:30 -050053 char formatbuffer[1024];
54 int n = vsnprintf(formatbuffer, sizeof(formatbuffer), fmt, args);
Joe Gregorio1fd18232017-02-13 11:39:43 -050055 va_end(args);
56 if (n>=0 && n<=int(sizeof(formatbuffer))) {
Hal Canary169f37f2017-02-15 10:20:30 -050057 gTextOutput.write(formatbuffer, n);
Joe Gregorio1fd18232017-02-13 11:39:43 -050058 }
59}
60
halcanarydecb21e2015-12-10 07:52:45 -080061static void encode_to_base64(const void* data, size_t size, FILE* out) {
62 const uint8_t* input = reinterpret_cast<const uint8_t*>(data);
63 const uint8_t* end = &input[size];
64 static const char codes[] =
65 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
66 "abcdefghijklmnopqrstuvwxyz0123456789+/";
67 while (input != end) {
68 uint8_t b = (*input & 0xFC) >> 2;
69 fputc(codes[b], out);
70 b = (*input & 0x03) << 4;
71 ++input;
72 if (input == end) {
73 fputc(codes[b], out);
74 fputs("==", out);
75 return;
76 }
77 b |= (*input & 0xF0) >> 4;
78 fputc(codes[b], out);
79 b = (*input & 0x0F) << 2;
80 ++input;
81 if (input == end) {
82 fputc(codes[b], out);
83 fputc('=', out);
84 return;
85 }
86 b |= (*input & 0xC0) >> 6;
87 fputc(codes[b], out);
88 b = *input & 0x3F;
89 fputc(codes[b], out);
90 ++input;
91 }
92}
93
Hal Canary169f37f2017-02-15 10:20:30 -050094
95static void dump_output(const void* data, size_t size,
96 const char* name, bool last = true) {
97 printf("\t\"%s\": \"", name);
98 encode_to_base64(data, size, stdout);
99 fputs(last ? "\"\n" : "\",\n", stdout);
100}
101
halcanaryd0964592016-03-25 11:29:34 -0700102static void dump_output(const sk_sp<SkData>& data,
103 const char* name, bool last = true) {
halcanarydecb21e2015-12-10 07:52:45 -0800104 if (data) {
Hal Canary169f37f2017-02-15 10:20:30 -0500105 dump_output(data->data(), data->size(), name, last);
halcanarydecb21e2015-12-10 07:52:45 -0800106 }
107}
108
Mike Reed6409f842017-07-11 16:03:13 -0400109static sk_sp<SkData> encode_snapshot(const sk_sp<SkSurface>& surface) {
halcanary7b8b2372016-04-18 08:17:56 -0700110 sk_sp<SkImage> img(surface->makeImageSnapshot());
Mike Reed6409f842017-07-11 16:03:13 -0400111 return img ? img->encodeToData() : nullptr;
halcanarydecb21e2015-12-10 07:52:45 -0800112}
113
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400114static SkCanvas* prepare_canvas(SkCanvas * canvas) {
115 canvas->clear(SK_ColorWHITE);
116 return canvas;
117}
118
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500119static bool setup_backend_objects(GrContext* context,
120 const SkBitmap& bm,
121 const DrawOptions& options) {
Robert Phillips57e08282017-11-16 14:59:48 -0500122 if (!context) {
123 return false;
124 }
125
Robert Phillips6be756b2018-01-16 15:07:54 -0500126 auto resourceProvider = context->contextPriv().resourceProvider();
127
Robert Phillips57e08282017-11-16 14:59:48 -0500128 GrSurfaceDesc backingDesc;
129 backingDesc.fFlags = kNone_GrSurfaceFlags;
Robert Phillips57e08282017-11-16 14:59:48 -0500130 backingDesc.fWidth = bm.width();
131 backingDesc.fHeight = bm.height();
Greg Danielfaa095e2017-12-19 13:15:02 -0500132 // This config must match the SkColorType used in draw.cpp in the SkImage and Surface factories
Robert Phillipsb67821d2017-12-13 15:00:45 -0500133 backingDesc.fConfig = kRGBA_8888_GrPixelConfig;
Brian Salomonbdecacf2018-02-02 20:32:49 -0500134 backingDesc.fSampleCnt = 1;
Robert Phillips57e08282017-11-16 14:59:48 -0500135
136 if (!bm.empty()) {
Brian Osman250e6e82017-12-12 16:24:41 -0500137 SkPixmap originalPixmap;
138 SkPixmap* pixmap = &originalPixmap;
139 if (!bm.peekPixels(&originalPixmap)) {
140 return false;
141 }
142
143 SkAutoPixmapStorage rgbaPixmap;
144 if (kN32_SkColorType != kRGBA_8888_SkColorType) {
145 if (!rgbaPixmap.tryAlloc(bm.info().makeColorType(kRGBA_8888_SkColorType))) {
146 return false;
147 }
148 if (!bm.readPixels(rgbaPixmap)) {
149 return false;
150 }
151 pixmap = &rgbaPixmap;
152 }
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500153 int mipLevelCount = GrMipMapped::kYes == options.fMipMapping
154 ? SkMipMap::ComputeLevelCount(bm.width(), bm.height())
155 : 1;
156 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
157
Brian Osman250e6e82017-12-12 16:24:41 -0500158 texels[0].fPixels = pixmap->addr();
159 texels[0].fRowBytes = pixmap->rowBytes();
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500160
161 for (int i = 1; i < mipLevelCount; i++) {
162 texels[i].fPixels = nullptr;
163 texels[i].fRowBytes = 0;
164 }
Robert Phillips57e08282017-11-16 14:59:48 -0500165
Brian Salomon58389b92018-03-07 13:01:25 -0500166 backingTexture = resourceProvider->createTexture(backingDesc, SkBudgeted::kNo, texels.get(),
167 mipLevelCount,
168 SkDestinationSurfaceColorMode::kLegacy);
Robert Phillips57e08282017-11-16 14:59:48 -0500169 if (!backingTexture) {
170 return false;
171 }
172
Robert Phillipsb67821d2017-12-13 15:00:45 -0500173 backEndTexture = backingTexture->getBackendTexture();
Robert Phillips57e08282017-11-16 14:59:48 -0500174 if (!backEndTexture.isValid()) {
175 return false;
176 }
177 }
178
179 backingDesc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500180 backingDesc.fWidth = options.fOffScreenWidth;
181 backingDesc.fHeight = options.fOffScreenHeight;
182 backingDesc.fSampleCnt = options.fOffScreenSampleCount;
Robert Phillips57e08282017-11-16 14:59:48 -0500183
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500184 SkAutoTMalloc<uint32_t> data(backingDesc.fWidth * backingDesc.fHeight);
185 sk_memset32(data.get(), 0, backingDesc.fWidth * backingDesc.fHeight);
Robert Phillips57e08282017-11-16 14:59:48 -0500186
Robert Phillips57e08282017-11-16 14:59:48 -0500187
188 {
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500189 // This backend object should be renderable but not textureable. Given the limitations
190 // of how we're creating it though it will wind up being secretly textureable.
191 // We use this fact to initialize it with data but don't allow mipmaps
192 GrMipLevel level0 = { data.get(), backingDesc.fWidth*sizeof(uint32_t) };
193
Robert Phillips6be756b2018-01-16 15:07:54 -0500194 sk_sp<GrTexture> tmp = resourceProvider->createTexture(
Brian Salomon58389b92018-03-07 13:01:25 -0500195 backingDesc, SkBudgeted::kNo, &level0, 1, SkDestinationSurfaceColorMode::kLegacy);
Robert Phillips57e08282017-11-16 14:59:48 -0500196 if (!tmp || !tmp->asRenderTarget()) {
197 return false;
198 }
199
200 backingRenderTarget = sk_ref_sp(tmp->asRenderTarget());
201
Robert Phillipsb67821d2017-12-13 15:00:45 -0500202 backEndRenderTarget = backingRenderTarget->getBackendRenderTarget();
Robert Phillips57e08282017-11-16 14:59:48 -0500203 if (!backEndRenderTarget.isValid()) {
204 return false;
205 }
206 }
207
208 {
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500209 int mipLevelCount = GrMipMapped::kYes == options.fOffScreenMipMapping
210 ? SkMipMap::ComputeLevelCount(backingDesc.fWidth, backingDesc.fHeight)
211 : 1;
212 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
213
214 texels[0].fPixels = data.get();
215 texels[0].fRowBytes = backingDesc.fWidth*sizeof(uint32_t);
216
217 for (int i = 1; i < mipLevelCount; i++) {
218 texels[i].fPixels = nullptr;
219 texels[i].fRowBytes = 0;
220 }
221
Robert Phillips6be756b2018-01-16 15:07:54 -0500222 backingTextureRenderTarget = resourceProvider->createTexture(
Brian Salomon58389b92018-03-07 13:01:25 -0500223 backingDesc, SkBudgeted::kNo, texels.get(), mipLevelCount,
Brian Salomon2a4f9832018-03-03 22:43:43 -0500224 SkDestinationSurfaceColorMode::kLegacy);
Robert Phillips57e08282017-11-16 14:59:48 -0500225 if (!backingTextureRenderTarget || !backingTextureRenderTarget->asRenderTarget()) {
226 return false;
227 }
228
Robert Phillipsb67821d2017-12-13 15:00:45 -0500229 backEndTextureRenderTarget = backingTextureRenderTarget->getBackendTexture();
Robert Phillips57e08282017-11-16 14:59:48 -0500230 if (!backEndTextureRenderTarget.isValid()) {
231 return false;
232 }
233 }
234
235
236 return true;
237}
238
Joe Gregorio1e735c02017-04-19 14:05:14 -0400239int main(int argc, char** argv) {
240 SkCommandLineFlags::Parse(argc, argv);
241 duration = FLAGS_duration;
242 frame = FLAGS_frame;
Joe Gregorio1fd18232017-02-13 11:39:43 -0500243 DrawOptions options = GetDrawOptions();
244 // If textOnly then only do one type of image, otherwise the text
245 // output is duplicated for each type.
246 if (options.textOnly) {
247 options.raster = true;
248 options.gpu = false;
249 options.pdf = false;
250 options.skp = false;
251 }
halcanarydecb21e2015-12-10 07:52:45 -0800252 if (options.source) {
bungeman38d909e2016-08-02 14:40:46 -0700253 sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
halcanarydecb21e2015-12-10 07:52:45 -0800254 if (!data) {
255 perror(options.source);
256 return 1;
257 } else {
halcanary7b8b2372016-04-18 08:17:56 -0700258 image = SkImage::MakeFromEncoded(std::move(data));
halcanarydecb21e2015-12-10 07:52:45 -0800259 if (!image) {
260 perror("Unable to decode the source image.");
261 return 1;
262 }
Cary Clark4f5a79c2018-02-07 15:51:00 -0500263 SkAssertResult(image->asLegacyBitmap(&source));
halcanarydecb21e2015-12-10 07:52:45 -0800264 }
265 }
halcanaryd0964592016-03-25 11:29:34 -0700266 sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
Matt Saretta2f71262016-11-29 17:14:58 -0500267 SkColorType colorType = kN32_SkColorType;
268 sk_sp<SkColorSpace> colorSpace = nullptr;
269 if (options.f16) {
270 SkASSERT(options.srgb);
271 colorType = kRGBA_F16_SkColorType;
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500272 colorSpace = SkColorSpace::MakeSRGBLinear();
Matt Saretta2f71262016-11-29 17:14:58 -0500273 } else if (options.srgb) {
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500274 colorSpace = SkColorSpace::MakeSRGB();
Matt Saretta2f71262016-11-29 17:14:58 -0500275 }
276 SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
277 kPremul_SkAlphaType, colorSpace);
halcanarydecb21e2015-12-10 07:52:45 -0800278 if (options.raster) {
Matt Saretta2f71262016-11-29 17:14:58 -0500279 auto rasterSurface = SkSurface::MakeRaster(info);
halcanaryf0270c32016-05-23 09:02:38 -0700280 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400281 draw(prepare_canvas(rasterSurface->getCanvas()));
Mike Reed6409f842017-07-11 16:03:13 -0400282 rasterData = encode_snapshot(rasterSurface);
halcanarydecb21e2015-12-10 07:52:45 -0800283 }
284 if (options.gpu) {
Joe Gregorio8e9810c2018-05-29 13:56:27 -0400285 std::unique_ptr<sk_gpu_test::GLTestContext> glContext;
286 sk_sp<GrContext> grContext = create_grcontext(gGLDriverInfo, &glContext);
halcanarydecb21e2015-12-10 07:52:45 -0800287 if (!grContext) {
mtklein7d10b9f2016-07-27 11:17:18 -0700288 fputs("Unable to get GrContext.\n", stderr);
halcanarydecb21e2015-12-10 07:52:45 -0800289 } else {
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500290 if (!setup_backend_objects(grContext.get(), source, options)) {
Robert Phillips57e08282017-11-16 14:59:48 -0500291 fputs("Unable to create backend objects.\n", stderr);
292 exit(1);
293 }
294
Matt Saretta2f71262016-11-29 17:14:58 -0500295 auto surface = SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kNo, info);
halcanarydecb21e2015-12-10 07:52:45 -0800296 if (!surface) {
297 fputs("Unable to get render surface.\n", stderr);
298 exit(1);
299 }
halcanaryf0270c32016-05-23 09:02:38 -0700300 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400301 draw(prepare_canvas(surface->getCanvas()));
Mike Reed6409f842017-07-11 16:03:13 -0400302 gpuData = encode_snapshot(surface);
halcanarydecb21e2015-12-10 07:52:45 -0800303 }
halcanarydecb21e2015-12-10 07:52:45 -0800304 }
305 if (options.pdf) {
306 SkDynamicMemoryWStream pdfStream;
halcanary676ab682016-05-03 12:10:04 -0700307 sk_sp<SkDocument> document(SkDocument::MakePDF(&pdfStream));
mtkleincd01b032016-08-31 04:58:19 -0700308 if (document) {
309 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400310 draw(prepare_canvas(document->beginPage(options.size.width(), options.size.height())));
mtkleincd01b032016-08-31 04:58:19 -0700311 document->close();
reed42943c82016-09-12 12:01:44 -0700312 pdfData = pdfStream.detachAsData();
mtkleincd01b032016-08-31 04:58:19 -0700313 }
halcanarydecb21e2015-12-10 07:52:45 -0800314 }
315 if (options.skp) {
316 SkSize size;
317 size = options.size;
318 SkPictureRecorder recorder;
halcanaryf0270c32016-05-23 09:02:38 -0700319 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400320 draw(prepare_canvas(recorder.beginRecording(size.width(), size.height())));
halcanaryd0964592016-03-25 11:29:34 -0700321 auto picture = recorder.finishRecordingAsPicture();
halcanarydecb21e2015-12-10 07:52:45 -0800322 SkDynamicMemoryWStream skpStream;
323 picture->serialize(&skpStream);
reed42943c82016-09-12 12:01:44 -0700324 skpData = skpStream.detachAsData();
halcanarydecb21e2015-12-10 07:52:45 -0800325 }
326
327 printf("{\n");
Joe Gregorio0236cba2017-02-13 13:55:17 -0500328 if (!options.textOnly) {
Joe Gregorio97b10ac2017-06-01 13:24:11 -0400329 dump_output(rasterData, "Raster", false);
330 dump_output(gpuData, "Gpu", false);
331 dump_output(pdfData, "Pdf", false);
332 dump_output(skpData, "Skp", false);
Joe Gregorio0236cba2017-02-13 13:55:17 -0500333 } else {
Hal Canary169f37f2017-02-15 10:20:30 -0500334 std::string textoutput = gTextOutput.str();
Joe Gregorio97b10ac2017-06-01 13:24:11 -0400335 dump_output(textoutput.c_str(), textoutput.length(), "Text", false);
Joe Gregorio0236cba2017-02-13 13:55:17 -0500336 }
Joe Gregorio97b10ac2017-06-01 13:24:11 -0400337 std::string glinfo = gGLDriverInfo.str();
338 dump_output(glinfo.c_str(), glinfo.length(), "GLInfo", true);
halcanarydecb21e2015-12-10 07:52:45 -0800339 printf("}\n");
340
halcanarydecb21e2015-12-10 07:52:45 -0800341 return 0;
342}