blob: 1cf95dd69ce4eac4bb7e356af7963a32c4a3a5cd [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkAutoPixmapStorage.h"
Mike Reed13711eb2020-07-14 17:16:32 -040014#include "src/core/SkMipmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/core/SkUtils.h"
16#include "tools/flags/CommandLineFlags.h"
Joe Gregorio1e735c02017-04-19 14:05:14 -040017
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "tools/fiddle/fiddle_main.h"
halcanarydecb21e2015-12-10 07:52:45 -080019
Mike Klein84836b72019-03-21 11:31:36 -050020static DEFINE_double(duration, 1.0,
21 "The total duration, in seconds, of the animation we are drawing.");
22static DEFINE_double(frame, 1.0,
23 "A double value in [0, 1] that specifies the point in animation to draw.");
Joe Gregorio1e735c02017-04-19 14:05:14 -040024
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "include/gpu/GrBackendSurface.h"
26#include "src/gpu/GrContextPriv.h"
27#include "src/gpu/GrGpu.h"
Brian Salomon201cdbb2019-08-14 17:00:30 -040028#include "src/gpu/GrRenderTarget.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "tools/gpu/gl/GLTestContext.h"
Robert Phillips57e08282017-11-16 14:59:48 -050030
halcanarydecb21e2015-12-10 07:52:45 -080031// Globals externed in fiddle_main.h
Robert Phillips57e08282017-11-16 14:59:48 -050032sk_sp<GrTexture> backingTexture; // not externed
33GrBackendTexture backEndTexture;
34
35sk_sp<GrRenderTarget> backingRenderTarget; // not externed
36GrBackendRenderTarget backEndRenderTarget;
37
38sk_sp<GrTexture> backingTextureRenderTarget; // not externed
39GrBackendTexture backEndTextureRenderTarget;
40
halcanarydecb21e2015-12-10 07:52:45 -080041SkBitmap source;
halcanary7b8b2372016-04-18 08:17:56 -070042sk_sp<SkImage> image;
Joe Gregorio1e735c02017-04-19 14:05:14 -040043double duration; // The total duration of the animation in seconds.
44double frame; // A value in [0, 1] of where we are in the animation.
halcanarydecb21e2015-12-10 07:52:45 -080045
Hal Canary169f37f2017-02-15 10:20:30 -050046// Global used by the local impl of SkDebugf.
47std::ostringstream gTextOutput;
Joe Gregorio1fd18232017-02-13 11:39:43 -050048
Robert Phillipsf4f80112020-07-13 16:13:31 -040049// Global to record the GL driver info via create_direct_context().
Joe Gregorio97b10ac2017-06-01 13:24:11 -040050std::ostringstream gGLDriverInfo;
51
Joe Gregorio1fd18232017-02-13 11:39:43 -050052void SkDebugf(const char * fmt, ...) {
Joe Gregorio1fd18232017-02-13 11:39:43 -050053 va_list args;
54 va_start(args, fmt);
Hal Canary169f37f2017-02-15 10:20:30 -050055 char formatbuffer[1024];
56 int n = vsnprintf(formatbuffer, sizeof(formatbuffer), fmt, args);
Joe Gregorio1fd18232017-02-13 11:39:43 -050057 va_end(args);
58 if (n>=0 && n<=int(sizeof(formatbuffer))) {
Hal Canary169f37f2017-02-15 10:20:30 -050059 gTextOutput.write(formatbuffer, n);
Joe Gregorio1fd18232017-02-13 11:39:43 -050060 }
61}
62
halcanarydecb21e2015-12-10 07:52:45 -080063static void encode_to_base64(const void* data, size_t size, FILE* out) {
64 const uint8_t* input = reinterpret_cast<const uint8_t*>(data);
65 const uint8_t* end = &input[size];
66 static const char codes[] =
67 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
68 "abcdefghijklmnopqrstuvwxyz0123456789+/";
69 while (input != end) {
70 uint8_t b = (*input & 0xFC) >> 2;
71 fputc(codes[b], out);
72 b = (*input & 0x03) << 4;
73 ++input;
74 if (input == end) {
75 fputc(codes[b], out);
76 fputs("==", out);
77 return;
78 }
79 b |= (*input & 0xF0) >> 4;
80 fputc(codes[b], out);
81 b = (*input & 0x0F) << 2;
82 ++input;
83 if (input == end) {
84 fputc(codes[b], out);
85 fputc('=', out);
86 return;
87 }
88 b |= (*input & 0xC0) >> 6;
89 fputc(codes[b], out);
90 b = *input & 0x3F;
91 fputc(codes[b], out);
92 ++input;
93 }
94}
95
Hal Canary169f37f2017-02-15 10:20:30 -050096
97static void dump_output(const void* data, size_t size,
98 const char* name, bool last = true) {
99 printf("\t\"%s\": \"", name);
100 encode_to_base64(data, size, stdout);
101 fputs(last ? "\"\n" : "\",\n", stdout);
102}
103
halcanaryd0964592016-03-25 11:29:34 -0700104static void dump_output(const sk_sp<SkData>& data,
105 const char* name, bool last = true) {
halcanarydecb21e2015-12-10 07:52:45 -0800106 if (data) {
Hal Canary169f37f2017-02-15 10:20:30 -0500107 dump_output(data->data(), data->size(), name, last);
halcanarydecb21e2015-12-10 07:52:45 -0800108 }
109}
110
Mike Reed6409f842017-07-11 16:03:13 -0400111static sk_sp<SkData> encode_snapshot(const sk_sp<SkSurface>& surface) {
halcanary7b8b2372016-04-18 08:17:56 -0700112 sk_sp<SkImage> img(surface->makeImageSnapshot());
Mike Reed6409f842017-07-11 16:03:13 -0400113 return img ? img->encodeToData() : nullptr;
halcanarydecb21e2015-12-10 07:52:45 -0800114}
115
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400116static SkCanvas* prepare_canvas(SkCanvas * canvas) {
117 canvas->clear(SK_ColorWHITE);
118 return canvas;
119}
120
Brian Salomonf4ba4ec2020-03-19 15:54:28 -0400121#ifdef SK_GL
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500122static bool setup_backend_objects(GrContext* context,
123 const SkBitmap& bm,
124 const DrawOptions& options) {
Robert Phillips57e08282017-11-16 14:59:48 -0500125 if (!context) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500126 fputs("Context is null.\n", stderr);
Robert Phillips57e08282017-11-16 14:59:48 -0500127 return false;
128 }
129
Robert Phillips9da87e02019-02-04 13:26:26 -0500130 auto resourceProvider = context->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -0500131
Greg Danielfaa095e2017-12-19 13:15:02 -0500132 // This config must match the SkColorType used in draw.cpp in the SkImage and Surface factories
Brian Salomon4eb38b72019-08-05 12:58:39 -0400133 auto format = resourceProvider->caps()->getDefaultBackendFormat(
134 SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kNo);
135 auto renderableFormat = resourceProvider->caps()->getDefaultBackendFormat(
136 SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kYes);
Robert Phillips57e08282017-11-16 14:59:48 -0500137
138 if (!bm.empty()) {
Brian Osman250e6e82017-12-12 16:24:41 -0500139 SkPixmap originalPixmap;
140 SkPixmap* pixmap = &originalPixmap;
141 if (!bm.peekPixels(&originalPixmap)) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500142 fputs("Unable to peekPixels.\n", stderr);
Brian Osman250e6e82017-12-12 16:24:41 -0500143 return false;
144 }
145
146 SkAutoPixmapStorage rgbaPixmap;
147 if (kN32_SkColorType != kRGBA_8888_SkColorType) {
148 if (!rgbaPixmap.tryAlloc(bm.info().makeColorType(kRGBA_8888_SkColorType))) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500149 fputs("Unable to alloc rgbaPixmap.\n", stderr);
Brian Osman250e6e82017-12-12 16:24:41 -0500150 return false;
151 }
152 if (!bm.readPixels(rgbaPixmap)) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500153 fputs("Unable to read rgbaPixmap.\n", stderr);
Brian Osman250e6e82017-12-12 16:24:41 -0500154 return false;
155 }
156 pixmap = &rgbaPixmap;
157 }
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500158 int mipLevelCount = GrMipMapped::kYes == options.fMipMapping
Mike Reed13711eb2020-07-14 17:16:32 -0400159 ? SkMipmap::ComputeLevelCount(bm.width(), bm.height())
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500160 : 1;
161 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
162
Brian Osman250e6e82017-12-12 16:24:41 -0500163 texels[0].fPixels = pixmap->addr();
164 texels[0].fRowBytes = pixmap->rowBytes();
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500165
166 for (int i = 1; i < mipLevelCount; i++) {
167 texels[i].fPixels = nullptr;
168 texels[i].fRowBytes = 0;
169 }
Robert Phillips57e08282017-11-16 14:59:48 -0500170
Brian Salomona90382f2019-09-17 09:01:56 -0400171 backingTexture = resourceProvider->createTexture(
Brian Salomona56a7462020-02-07 14:17:25 -0500172 bm.dimensions(), format, GrColorType::kRGBA_8888, GrRenderable::kNo, 1,
173 SkBudgeted::kNo, GrProtected::kNo, texels.get(), mipLevelCount);
Robert Phillips57e08282017-11-16 14:59:48 -0500174 if (!backingTexture) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500175 fputs("Failed to create backingTexture.\n", stderr);
Robert Phillips57e08282017-11-16 14:59:48 -0500176 return false;
177 }
178
Robert Phillipsb67821d2017-12-13 15:00:45 -0500179 backEndTexture = backingTexture->getBackendTexture();
Robert Phillips57e08282017-11-16 14:59:48 -0500180 if (!backEndTexture.isValid()) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500181 fputs("BackingTexture is invalid.\n", stderr);
Robert Phillips57e08282017-11-16 14:59:48 -0500182 return false;
183 }
184 }
185
Brian Salomon5dd64f32020-02-10 14:23:10 -0500186 SkISize offscreenDims = {options.fOffScreenWidth, options.fOffScreenHeight};
187 SkAutoTMalloc<uint32_t> data(offscreenDims.area());
188 sk_memset32(data.get(), 0, offscreenDims.area());
Robert Phillips57e08282017-11-16 14:59:48 -0500189
190 {
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500191 // This backend object should be renderable but not textureable. Given the limitations
192 // of how we're creating it though it will wind up being secretly textureable.
193 // We use this fact to initialize it with data but don't allow mipmaps
Brian Salomon5dd64f32020-02-10 14:23:10 -0500194 GrMipLevel level0 = { data.get(), offscreenDims.width()*sizeof(uint32_t) };
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500195
Brian Salomone8a766b2019-07-19 14:24:36 -0400196 sk_sp<GrTexture> tmp = resourceProvider->createTexture(
Brian Salomon5dd64f32020-02-10 14:23:10 -0500197 offscreenDims, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
Brian Salomona90382f2019-09-17 09:01:56 -0400198 options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, &level0, 1);
Robert Phillips57e08282017-11-16 14:59:48 -0500199 if (!tmp || !tmp->asRenderTarget()) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500200 fputs("GrTexture is invalid.\n", stderr);
Robert Phillips57e08282017-11-16 14:59:48 -0500201 return false;
202 }
203
204 backingRenderTarget = sk_ref_sp(tmp->asRenderTarget());
205
Robert Phillipsb67821d2017-12-13 15:00:45 -0500206 backEndRenderTarget = backingRenderTarget->getBackendRenderTarget();
Robert Phillips57e08282017-11-16 14:59:48 -0500207 if (!backEndRenderTarget.isValid()) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500208 fputs("BackEndRenderTarget is invalid.\n", stderr);
Robert Phillips57e08282017-11-16 14:59:48 -0500209 return false;
210 }
211 }
212
213 {
Brian Salomon5dd64f32020-02-10 14:23:10 -0500214 int mipLevelCount =
215 GrMipMapped::kYes == options.fOffScreenMipMapping
Mike Reed13711eb2020-07-14 17:16:32 -0400216 ? SkMipmap::ComputeLevelCount(offscreenDims.width(), offscreenDims.height())
Brian Salomon5dd64f32020-02-10 14:23:10 -0500217 : 1;
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500218 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
219
220 texels[0].fPixels = data.get();
Brian Salomon5dd64f32020-02-10 14:23:10 -0500221 texels[0].fRowBytes = offscreenDims.width()*sizeof(uint32_t);
Robert Phillipsc34aa9d2017-11-17 14:59:43 -0500222
223 for (int i = 1; i < mipLevelCount; i++) {
224 texels[i].fPixels = nullptr;
225 texels[i].fRowBytes = 0;
226 }
227
Brian Salomon4eb38b72019-08-05 12:58:39 -0400228 backingTextureRenderTarget = resourceProvider->createTexture(
Brian Salomon5dd64f32020-02-10 14:23:10 -0500229 offscreenDims, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
Brian Salomona90382f2019-09-17 09:01:56 -0400230 options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, texels.get(),
231 mipLevelCount);
Robert Phillips57e08282017-11-16 14:59:48 -0500232 if (!backingTextureRenderTarget || !backingTextureRenderTarget->asRenderTarget()) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500233 fputs("backingTextureRenderTarget is invalid.\n", stderr);
Robert Phillips57e08282017-11-16 14:59:48 -0500234 return false;
235 }
236
Robert Phillipsb67821d2017-12-13 15:00:45 -0500237 backEndTextureRenderTarget = backingTextureRenderTarget->getBackendTexture();
Robert Phillips57e08282017-11-16 14:59:48 -0500238 if (!backEndTextureRenderTarget.isValid()) {
Joe Gregorio9a37fb62020-02-10 10:41:56 -0500239 fputs("backEndTextureRenderTarget is invalid.\n", stderr);
Robert Phillips57e08282017-11-16 14:59:48 -0500240 return false;
241 }
242 }
243
244
245 return true;
246}
Brian Salomonf4ba4ec2020-03-19 15:54:28 -0400247#endif
Robert Phillips57e08282017-11-16 14:59:48 -0500248
Joe Gregorio1e735c02017-04-19 14:05:14 -0400249int main(int argc, char** argv) {
Mike Klein88544fb2019-03-20 10:50:33 -0500250 CommandLineFlags::Parse(argc, argv);
Joe Gregorio1e735c02017-04-19 14:05:14 -0400251 duration = FLAGS_duration;
252 frame = FLAGS_frame;
Joe Gregorio1fd18232017-02-13 11:39:43 -0500253 DrawOptions options = GetDrawOptions();
254 // If textOnly then only do one type of image, otherwise the text
255 // output is duplicated for each type.
256 if (options.textOnly) {
257 options.raster = true;
258 options.gpu = false;
259 options.pdf = false;
260 options.skp = false;
261 }
halcanarydecb21e2015-12-10 07:52:45 -0800262 if (options.source) {
bungeman38d909e2016-08-02 14:40:46 -0700263 sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
halcanarydecb21e2015-12-10 07:52:45 -0800264 if (!data) {
265 perror(options.source);
266 return 1;
267 } else {
halcanary7b8b2372016-04-18 08:17:56 -0700268 image = SkImage::MakeFromEncoded(std::move(data));
halcanarydecb21e2015-12-10 07:52:45 -0800269 if (!image) {
270 perror("Unable to decode the source image.");
271 return 1;
272 }
Cary Clark4f5a79c2018-02-07 15:51:00 -0500273 SkAssertResult(image->asLegacyBitmap(&source));
halcanarydecb21e2015-12-10 07:52:45 -0800274 }
275 }
halcanaryd0964592016-03-25 11:29:34 -0700276 sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
Matt Saretta2f71262016-11-29 17:14:58 -0500277 SkColorType colorType = kN32_SkColorType;
278 sk_sp<SkColorSpace> colorSpace = nullptr;
279 if (options.f16) {
280 SkASSERT(options.srgb);
281 colorType = kRGBA_F16_SkColorType;
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500282 colorSpace = SkColorSpace::MakeSRGBLinear();
Matt Saretta2f71262016-11-29 17:14:58 -0500283 } else if (options.srgb) {
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500284 colorSpace = SkColorSpace::MakeSRGB();
Matt Saretta2f71262016-11-29 17:14:58 -0500285 }
286 SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
287 kPremul_SkAlphaType, colorSpace);
halcanarydecb21e2015-12-10 07:52:45 -0800288 if (options.raster) {
Matt Saretta2f71262016-11-29 17:14:58 -0500289 auto rasterSurface = SkSurface::MakeRaster(info);
halcanaryf0270c32016-05-23 09:02:38 -0700290 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400291 draw(prepare_canvas(rasterSurface->getCanvas()));
Mike Reed6409f842017-07-11 16:03:13 -0400292 rasterData = encode_snapshot(rasterSurface);
halcanarydecb21e2015-12-10 07:52:45 -0800293 }
Brian Salomonf4ba4ec2020-03-19 15:54:28 -0400294#ifdef SK_GL
halcanarydecb21e2015-12-10 07:52:45 -0800295 if (options.gpu) {
Joe Gregorio8e9810c2018-05-29 13:56:27 -0400296 std::unique_ptr<sk_gpu_test::GLTestContext> glContext;
Robert Phillipsf4f80112020-07-13 16:13:31 -0400297 sk_sp<GrDirectContext> direct = create_direct_context(gGLDriverInfo, &glContext);
298 if (!direct) {
mtklein7d10b9f2016-07-27 11:17:18 -0700299 fputs("Unable to get GrContext.\n", stderr);
halcanarydecb21e2015-12-10 07:52:45 -0800300 } else {
Robert Phillipsf4f80112020-07-13 16:13:31 -0400301 if (!setup_backend_objects(direct.get(), source, options)) {
Robert Phillips57e08282017-11-16 14:59:48 -0500302 fputs("Unable to create backend objects.\n", stderr);
303 exit(1);
304 }
305
Robert Phillipsf4f80112020-07-13 16:13:31 -0400306 auto surface = SkSurface::MakeRenderTarget(direct.get(), SkBudgeted::kNo, info);
halcanarydecb21e2015-12-10 07:52:45 -0800307 if (!surface) {
308 fputs("Unable to get render surface.\n", stderr);
309 exit(1);
310 }
halcanaryf0270c32016-05-23 09:02:38 -0700311 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400312 draw(prepare_canvas(surface->getCanvas()));
Mike Reed6409f842017-07-11 16:03:13 -0400313 gpuData = encode_snapshot(surface);
halcanarydecb21e2015-12-10 07:52:45 -0800314 }
halcanarydecb21e2015-12-10 07:52:45 -0800315 }
Brian Salomonf4ba4ec2020-03-19 15:54:28 -0400316#endif
halcanarydecb21e2015-12-10 07:52:45 -0800317 if (options.pdf) {
318 SkDynamicMemoryWStream pdfStream;
Hal Canary3026d4b2019-01-07 10:00:48 -0500319 auto document = SkPDF::MakeDocument(&pdfStream);
mtkleincd01b032016-08-31 04:58:19 -0700320 if (document) {
321 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400322 draw(prepare_canvas(document->beginPage(options.size.width(), options.size.height())));
mtkleincd01b032016-08-31 04:58:19 -0700323 document->close();
reed42943c82016-09-12 12:01:44 -0700324 pdfData = pdfStream.detachAsData();
mtkleincd01b032016-08-31 04:58:19 -0700325 }
halcanarydecb21e2015-12-10 07:52:45 -0800326 }
327 if (options.skp) {
Brian Salomon4e1066f2019-12-04 10:33:52 -0500328 auto size = SkSize::Make(options.size);
halcanarydecb21e2015-12-10 07:52:45 -0800329 SkPictureRecorder recorder;
halcanaryf0270c32016-05-23 09:02:38 -0700330 srand(0);
Joe Gregorio4f12f1e2017-06-14 15:54:32 -0400331 draw(prepare_canvas(recorder.beginRecording(size.width(), size.height())));
halcanaryd0964592016-03-25 11:29:34 -0700332 auto picture = recorder.finishRecordingAsPicture();
halcanarydecb21e2015-12-10 07:52:45 -0800333 SkDynamicMemoryWStream skpStream;
334 picture->serialize(&skpStream);
reed42943c82016-09-12 12:01:44 -0700335 skpData = skpStream.detachAsData();
halcanarydecb21e2015-12-10 07:52:45 -0800336 }
337
338 printf("{\n");
Joe Gregorio0236cba2017-02-13 13:55:17 -0500339 if (!options.textOnly) {
Joe Gregorio97b10ac2017-06-01 13:24:11 -0400340 dump_output(rasterData, "Raster", false);
341 dump_output(gpuData, "Gpu", false);
342 dump_output(pdfData, "Pdf", false);
343 dump_output(skpData, "Skp", false);
Joe Gregorio0236cba2017-02-13 13:55:17 -0500344 } else {
Hal Canary169f37f2017-02-15 10:20:30 -0500345 std::string textoutput = gTextOutput.str();
Joe Gregorio97b10ac2017-06-01 13:24:11 -0400346 dump_output(textoutput.c_str(), textoutput.length(), "Text", false);
Joe Gregorio0236cba2017-02-13 13:55:17 -0500347 }
Joe Gregorio97b10ac2017-06-01 13:24:11 -0400348 std::string glinfo = gGLDriverInfo.str();
349 dump_output(glinfo.c_str(), glinfo.length(), "GLInfo", true);
halcanarydecb21e2015-12-10 07:52:45 -0800350 printf("}\n");
351
halcanarydecb21e2015-12-10 07:52:45 -0800352 return 0;
353}