blob: 90c98f2bafecc2caf89e77e4fcd0bb03dff5965b [file] [log] [blame]
Mike Klein735c7ba2019-03-25 12:57:58 -05001// Copyright 2019 Google LLC.
2// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3
4#include "CommandLineFlags.h"
5#include "CommonFlags.h"
6#include "EventTracingPriv.h"
7#include "GrContextFactory.h"
8#include "GrContextOptions.h"
9#include "GrContextPriv.h"
10#include "GrGpu.h"
11#include "HashAndEncode.h"
12#include "SkCodec.h"
13#include "SkColorSpace.h"
14#include "SkColorSpacePriv.h"
15#include "SkGraphics.h"
16#include "SkMD5.h"
17#include "SkOSFile.h"
18#include "SkOSPath.h"
Mike Kleinc245bd92019-03-27 14:31:09 -050019#include "SkPDFDocument.h"
Mike Klein735c7ba2019-03-25 12:57:58 -050020#include "SkPicture.h"
Mike Klein9b462092019-03-27 13:52:35 -050021#include "SkPictureRecorder.h"
Mike Klein6253d902019-03-27 15:09:12 -050022#include "SkSVGDOM.h"
Mike Kleincbe93ee2019-04-02 17:00:54 -040023#include "SkTHash.h"
Mike Klein22924262019-04-02 14:14:56 -040024#include "Skottie.h"
25#include "SkottieUtils.h"
Mike Klein735c7ba2019-03-25 12:57:58 -050026#include "ToolUtils.h"
27#include "gm.h"
28#include <chrono>
29#include <functional>
30#include <stdio.h>
31#include <stdlib.h>
32
33using sk_gpu_test::GrContextFactory;
34
35static DEFINE_string2(sources, s, "", "Which GMs, .skps, or images to draw.");
36static DEFINE_string2(backend, b, "", "Backend used to create a canvas to draw into.");
37
38static DEFINE_string(ct , "8888", "The color type for any raster backend.");
39static DEFINE_string(at , "premul", "The alpha type for any raster backend.");
40static DEFINE_string(gamut, "srgb", "The color gamut for any raster backend.");
41static DEFINE_string(tf , "srgb", "The transfer function for any raster backend.");
42
43static DEFINE_int (samples , 0, "Samples per pixel in GPU backends.");
44static DEFINE_bool (nvpr , false, "Use NV_path_rendering in GPU backends?");
45static DEFINE_bool (stencils, true, "If false, avoid stencil buffers in GPU backends.");
46static DEFINE_bool (dit , false, "Use device-independent text in GPU backends.");
47static DEFINE_string(surf , "default", "Backing store for GPU backend surfaces.");
48
49static DEFINE_bool( preAbandonGpuContext, false, "Abandon the GrContext before drawing.");
50static DEFINE_bool( abandonGpuContext, false, "Abandon the GrContext after drawing.");
51static DEFINE_bool(releaseAndAbandonGpuContext, false,
52 "Release all GPU resources and abandon the GrContext after drawing.");
53
54static DEFINE_bool(decodeToDst, false,
55 "Decode images to destination format rather than suggested natural format.");
56
Mike Kleinc245bd92019-03-27 14:31:09 -050057static DEFINE_double(rasterDPI, SK_ScalarDefaultRasterDPI,
58 "DPI for rasterized content in vector backends like --backend pdf.");
59static DEFINE_bool(PDFA, false, "Create PDF/A with --backend pdf?");
60
Mike Klein735c7ba2019-03-25 12:57:58 -050061static DEFINE_bool (cpuDetect, true, "Detect CPU features for runtime optimizations?");
62static DEFINE_string2(writePath, w, "", "Write .pngs to this directory if set.");
Mike Klein735c7ba2019-03-25 12:57:58 -050063
64static DEFINE_string(key, "", "Metadata passed through to .png encoder and .json output.");
65static DEFINE_string(parameters, "", "Metadata passed through to .png encoder and .json output.");
66
67template <typename T>
68struct FlagOption {
69 const char* label;
70 T value;
71};
72
73template <typename T, int N>
74static bool parse_flag(const CommandLineFlags::StringArray& flag,
75 const char* flag_name,
76 const FlagOption<T> (&array)[N],
77 T* value) {
78 for (auto entry : array) {
79 if (flag.contains(entry.label)) {
80 *value = entry.value;
81 return true;
82 }
83 }
84 fprintf(stderr, "Known values for --%s:\n", flag_name);
85 for (auto entry : array) {
86 fprintf(stderr, " --%s %s\n", flag_name, entry.label);
87 }
88 return false;
89}
90
91static void exit_with_failure() {
92 // TODO: dump stack trace, debug trap, print currently running job, etc?
93 exit(1);
94}
95
96struct Source {
97 SkString name;
98 SkISize size;
Mike Klein735c7ba2019-03-25 12:57:58 -050099 std::function<void(GrContextOptions*)> tweak;
Mike Klein22924262019-04-02 14:14:56 -0400100 std::function<bool(SkCanvas*)> draw; // true -> ok, false -> skip;
101 // failures should exit_with_failure()
Mike Klein735c7ba2019-03-25 12:57:58 -0500102};
103
104static Source gm_source(std::shared_ptr<skiagm::GM> gm) {
105 return {
106 SkString{gm->getName()},
107 gm->getISize(),
Mike Klein22924262019-04-02 14:14:56 -0400108 [gm](GrContextOptions* options) { gm->modifyGrContextOptions(options); },
Mike Klein735c7ba2019-03-25 12:57:58 -0500109 [gm](SkCanvas* canvas) {
110 SkString err;
Mike Kleina5c27172019-04-02 10:26:48 -0400111 switch (gm->draw(canvas, &err)) {
112 case skiagm::DrawResult::kOk: return true;
113 case skiagm::DrawResult::kSkip: break;
114 case skiagm::DrawResult::kFail:
115 fprintf(stderr, "Drawing GM %s failed: %s\n", gm->getName(), err.c_str());
116 exit_with_failure();
Mike Klein735c7ba2019-03-25 12:57:58 -0500117 }
Mike Kleina5c27172019-04-02 10:26:48 -0400118 return false;
Mike Klein735c7ba2019-03-25 12:57:58 -0500119 },
Mike Klein735c7ba2019-03-25 12:57:58 -0500120 };
121}
122
123static Source picture_source(SkString name, sk_sp<SkPicture> pic) {
124 return {
125 name,
126 pic->cullRect().roundOut().size(),
Mike Klein22924262019-04-02 14:14:56 -0400127 [](GrContextOptions*) {},
Mike Klein735c7ba2019-03-25 12:57:58 -0500128 [pic](SkCanvas* canvas) {
129 canvas->drawPicture(pic);
Mike Kleina5c27172019-04-02 10:26:48 -0400130 return true;
Mike Klein735c7ba2019-03-25 12:57:58 -0500131 },
Mike Klein735c7ba2019-03-25 12:57:58 -0500132 };
133}
134
135static Source codec_source(SkString name, std::shared_ptr<SkCodec> codec) {
136 return {
137 name,
138 codec->dimensions(),
Mike Klein22924262019-04-02 14:14:56 -0400139 [](GrContextOptions*) {},
Mike Klein735c7ba2019-03-25 12:57:58 -0500140 [codec](SkCanvas* canvas) {
141 SkImageInfo info = codec->getInfo();
142 if (FLAGS_decodeToDst) {
143 info = canvas->imageInfo().makeWH(info.width(),
144 info.height());
145 }
146
147 SkBitmap bm;
148 bm.allocPixels(info);
149
150 switch (auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes())) {
151 case SkCodec::kSuccess:
152 case SkCodec::kErrorInInput:
153 case SkCodec::kIncompleteInput:
154 canvas->drawBitmap(bm, 0,0);
Mike Kleina5c27172019-04-02 10:26:48 -0400155 return true;
Mike Klein735c7ba2019-03-25 12:57:58 -0500156 default:
157 fprintf(stderr, "SkCodec::getPixels failed: %d.", result);
158 exit_with_failure();
159 }
Mike Kleina5c27172019-04-02 10:26:48 -0400160 return false;
Mike Klein735c7ba2019-03-25 12:57:58 -0500161 },
Mike Klein735c7ba2019-03-25 12:57:58 -0500162 };
163}
164
Mike Klein6253d902019-03-27 15:09:12 -0500165static Source svg_source(SkString name, sk_sp<SkSVGDOM> svg) {
166 return {
167 name,
168 svg->containerSize().isEmpty() ? SkISize{1000,1000}
169 : svg->containerSize().toCeil(),
Mike Klein22924262019-04-02 14:14:56 -0400170 [](GrContextOptions*) {},
Mike Kleina5c27172019-04-02 10:26:48 -0400171 [svg](SkCanvas* canvas) {
172 svg->render(canvas);
173 return true;
174 },
Mike Klein22924262019-04-02 14:14:56 -0400175 };
176}
177
178static Source skottie_source(SkString name, sk_sp<skottie::Animation> animation) {
179 return {
180 name,
181 {1000,1000},
Mike Klein6253d902019-03-27 15:09:12 -0500182 [](GrContextOptions*) {},
Mike Klein22924262019-04-02 14:14:56 -0400183 [animation](SkCanvas* canvas) {
184 canvas->clear(SK_ColorWHITE);
185
186 // Draw frames in a shuffled order to exercise nonlinear frame progression.
187 // The film strip will still be in time order, just drawn out of order.
188 const int order[] = { 4, 0, 3, 1, 2 };
189 const int tiles = SK_ARRAY_COUNT(order);
190 const float dim = 1000.0f / tiles;
191
192 const float dt = 1.0f / (tiles*tiles - 1);
193
194 for (int y : order)
195 for (int x : order) {
196 SkRect dst = {x*dim, y*dim, (x+1)*dim, (y+1)*dim};
197
198 SkAutoCanvasRestore _(canvas, true/*save now*/);
199 canvas->clipRect(dst, /*aa=*/true);
200 canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(animation->size()),
201 dst,
202 SkMatrix::kCenter_ScaleToFit));
203 float t = (y*tiles + x) * dt;
204 animation->seek(t);
205 animation->render(canvas);
206 }
207 return true;
208 },
Mike Klein6253d902019-03-27 15:09:12 -0500209 };
210}
211
212
Mike Kleina5c27172019-04-02 10:26:48 -0400213static sk_sp<SkImage> draw_with_cpu(std::function<bool(SkCanvas*)> draw,
Mike Klein735c7ba2019-03-25 12:57:58 -0500214 SkImageInfo info) {
215 if (sk_sp<SkSurface> surface = SkSurface::MakeRaster(info)) {
Mike Kleina5c27172019-04-02 10:26:48 -0400216 if (draw(surface->getCanvas())) {
217 return surface->makeImageSnapshot();
218 }
Mike Klein735c7ba2019-03-25 12:57:58 -0500219 }
220 return nullptr;
221}
222
Mike Kleina5c27172019-04-02 10:26:48 -0400223static sk_sp<SkData> draw_as_skp(std::function<bool(SkCanvas*)> draw,
Mike Klein9b462092019-03-27 13:52:35 -0500224 SkImageInfo info) {
225 SkPictureRecorder recorder;
Mike Kleina5c27172019-04-02 10:26:48 -0400226 if (draw(recorder.beginRecording(info.width(), info.height()))) {
227 return recorder.finishRecordingAsPicture()->serialize();
228 }
229 return nullptr;
Mike Klein9b462092019-03-27 13:52:35 -0500230}
231
Mike Kleina5c27172019-04-02 10:26:48 -0400232static sk_sp<SkData> draw_as_pdf(std::function<bool(SkCanvas*)> draw,
Mike Kleinc245bd92019-03-27 14:31:09 -0500233 SkImageInfo info,
234 SkString name) {
235 SkPDF::Metadata metadata;
236 metadata.fTitle = name;
237 metadata.fCreator = "Skia/FM";
238 metadata.fRasterDPI = FLAGS_rasterDPI;
239 metadata.fPDFA = FLAGS_PDFA;
240
241 SkDynamicMemoryWStream stream;
242 if (sk_sp<SkDocument> doc = SkPDF::MakeDocument(&stream, metadata)) {
Mike Kleina5c27172019-04-02 10:26:48 -0400243 if (draw(doc->beginPage(info.width(), info.height()))) {
244 doc->endPage();
245 doc->close();
246 return stream.detachAsData();
247 }
Mike Kleinc245bd92019-03-27 14:31:09 -0500248 }
249 return nullptr;
250}
251
Mike Kleina5c27172019-04-02 10:26:48 -0400252static sk_sp<SkImage> draw_with_gpu(std::function<bool(SkCanvas*)> draw,
Mike Klein735c7ba2019-03-25 12:57:58 -0500253 SkImageInfo info,
254 GrContextFactory::ContextType api,
255 GrContextFactory* factory) {
256 enum class SurfaceType { kDefault, kBackendTexture, kBackendRenderTarget };
257 const FlagOption<SurfaceType> kSurfaceTypes[] = {
258 { "default", SurfaceType::kDefault },
259 { "betex" , SurfaceType::kBackendTexture },
260 { "bert" , SurfaceType::kBackendRenderTarget },
261 };
262 SurfaceType surfaceType;
263 if (!parse_flag(FLAGS_surf, "surf", kSurfaceTypes, &surfaceType)) {
264 return nullptr;
265 }
266
267 auto overrides = FLAGS_nvpr ? GrContextFactory::ContextOverrides::kRequireNVPRSupport
268 : GrContextFactory::ContextOverrides::kDisableNVPR;
269 if (!FLAGS_stencils) { overrides |= GrContextFactory::ContextOverrides::kAvoidStencilBuffers; }
270
271 GrContext* context = factory->getContextInfo(api, overrides)
272 .grContext();
273
274 uint32_t flags = FLAGS_dit ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag
275 : 0;
276 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
277
278 sk_sp<SkSurface> surface;
279 GrBackendTexture backendTexture;
280 GrBackendRenderTarget backendRT;
281
282 switch (surfaceType) {
283 case SurfaceType::kDefault:
284 surface = SkSurface::MakeRenderTarget(context,
285 SkBudgeted::kNo,
286 info,
287 FLAGS_samples,
288 &props);
289 break;
290
291 case SurfaceType::kBackendTexture:
292 backendTexture = context->priv().getGpu()
293 ->createTestingOnlyBackendTexture(nullptr,
294 info.width(),
295 info.height(),
296 info.colorType(),
297 true,
298 GrMipMapped::kNo);
299 surface = SkSurface::MakeFromBackendTexture(context,
300 backendTexture,
301 kTopLeft_GrSurfaceOrigin,
302 FLAGS_samples,
303 info.colorType(),
304 info.refColorSpace(),
305 &props);
306 break;
307
308 case SurfaceType::kBackendRenderTarget:
309 backendRT = context->priv().getGpu()
310 ->createTestingOnlyBackendRenderTarget(info.width(),
311 info.height(),
312 SkColorTypeToGrColorType(info.colorType()));
313 surface = SkSurface::MakeFromBackendRenderTarget(context,
314 backendRT,
315 kBottomLeft_GrSurfaceOrigin,
316 info.colorType(),
317 info.refColorSpace(),
318 &props);
319 break;
320 }
321
322 if (!surface) {
323 fprintf(stderr, "Could not create GPU surface.\n");
324 return nullptr;
325 }
326
327 if (FLAGS_preAbandonGpuContext) {
328 factory->abandonContexts();
329 }
330
Mike Kleina5c27172019-04-02 10:26:48 -0400331 sk_sp<SkImage> image;
332 if (draw(surface->getCanvas())) {
333 image = surface->makeImageSnapshot();
334 }
Mike Klein735c7ba2019-03-25 12:57:58 -0500335
336 if (FLAGS_abandonGpuContext) {
337 factory->abandonContexts();
338 } else if (FLAGS_releaseAndAbandonGpuContext) {
339 factory->releaseResourcesAndAbandonContexts();
340 }
341
342 if (!context->abandoned()) {
343 surface.reset();
344 if (backendTexture.isValid()) {
345 context->priv().getGpu()->deleteTestingOnlyBackendTexture(backendTexture);
346 }
347 if (backendRT.isValid()) {
348 context->priv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
349 }
350 }
351
352 return image;
353}
354
355int main(int argc, char** argv) {
356 CommandLineFlags::Parse(argc, argv);
357
358 if (FLAGS_cpuDetect) {
359 SkGraphics::Init();
360 }
361 initializeEventTracingForTools();
362 ToolUtils::SetDefaultFontMgr();
363 SetAnalyticAAFromCommonFlags();
364
365 GrContextOptions baseOptions;
366 SetCtxOptionsFromCommonFlags(&baseOptions);
367
Mike Kleincbe93ee2019-04-02 17:00:54 -0400368 SkTHashMap<SkString, skiagm::GMFactory> gm_factories;
Mike Klein735c7ba2019-03-25 12:57:58 -0500369 for (skiagm::GMFactory factory : skiagm::GMRegistry::Range()) {
Mike Kleincbe93ee2019-04-02 17:00:54 -0400370 std::unique_ptr<skiagm::GM> gm{factory(nullptr)};
Mike Klein735c7ba2019-03-25 12:57:58 -0500371 if (FLAGS_sources.isEmpty()) {
372 fprintf(stdout, "%s\n", gm->getName());
Mike Kleincbe93ee2019-04-02 17:00:54 -0400373 } else {
374 gm_factories.set(SkString{gm->getName()}, factory);
Mike Klein735c7ba2019-03-25 12:57:58 -0500375 }
376 }
Mike Kleincbe93ee2019-04-02 17:00:54 -0400377 if (FLAGS_sources.isEmpty()) {
378 return 0;
379 }
380
381 SkTArray<Source> sources;
Mike Klein735c7ba2019-03-25 12:57:58 -0500382 for (const SkString& source : FLAGS_sources) {
Mike Kleincbe93ee2019-04-02 17:00:54 -0400383 if (skiagm::GMFactory* factory = gm_factories.find(source)) {
384 std::shared_ptr<skiagm::GM> gm{(*factory)(nullptr)};
385 sources.push_back(gm_source(gm));
386 continue;
387 }
388
Mike Klein735c7ba2019-03-25 12:57:58 -0500389 if (sk_sp<SkData> blob = SkData::MakeFromFileName(source.c_str())) {
Mike Klein22924262019-04-02 14:14:56 -0400390 const SkString dir = SkOSPath::Dirname (source.c_str()),
391 name = SkOSPath::Basename(source.c_str());
Mike Klein735c7ba2019-03-25 12:57:58 -0500392
Mike Kleince90d6f2019-03-29 11:14:14 -0500393 if (name.endsWith(".skp")) {
394 if (sk_sp<SkPicture> pic = SkPicture::MakeFromData(blob.get())) {
395 sources.push_back(picture_source(name, pic));
Mike Kleincbe93ee2019-04-02 17:00:54 -0400396 continue;
Mike Kleince90d6f2019-03-29 11:14:14 -0500397 }
398 } else if (name.endsWith(".svg")) {
399 SkMemoryStream stream{blob};
400 if (sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(stream)) {
401 sources.push_back(svg_source(name, svg));
Mike Kleincbe93ee2019-04-02 17:00:54 -0400402 continue;
Mike Kleince90d6f2019-03-29 11:14:14 -0500403 }
Mike Klein22924262019-04-02 14:14:56 -0400404 } else if (name.endsWith(".json")) {
405 if (sk_sp<skottie::Animation> animation = skottie::Animation::Builder()
406 .setResourceProvider(skottie_utils::FileResourceProvider::Make(dir))
407 .makeFromFile(source.c_str())) {
408 sources.push_back(skottie_source(name, animation));
Mike Kleincbe93ee2019-04-02 17:00:54 -0400409 continue;
Mike Klein22924262019-04-02 14:14:56 -0400410 }
Mike Kleince90d6f2019-03-29 11:14:14 -0500411 } else if (std::shared_ptr<SkCodec> codec = SkCodec::MakeFromData(blob)) {
Mike Klein735c7ba2019-03-25 12:57:58 -0500412 sources.push_back(codec_source(name, codec));
Mike Kleincbe93ee2019-04-02 17:00:54 -0400413 continue;
Mike Klein735c7ba2019-03-25 12:57:58 -0500414 }
415 }
Mike Kleincbe93ee2019-04-02 17:00:54 -0400416
417 fprintf(stderr, "Don't understand --source %s... bailing out.\n", source.c_str());
418 return 1;
Mike Klein735c7ba2019-03-25 12:57:58 -0500419 }
420
Mike Klein9b462092019-03-27 13:52:35 -0500421 enum NonGpuBackends {
422 kCPU_Backend = -1,
423 kSKP_Backend = -2,
Mike Kleinc245bd92019-03-27 14:31:09 -0500424 kPDF_Backend = -3,
Mike Klein9b462092019-03-27 13:52:35 -0500425 };
426 const FlagOption<int> kBackends[] = {
427 { "cpu" , kCPU_Backend },
428 { "skp" , kSKP_Backend },
Mike Kleinc245bd92019-03-27 14:31:09 -0500429 { "pdf" , kPDF_Backend },
Mike Klein9b462092019-03-27 13:52:35 -0500430 { "gl" , GrContextFactory::kGL_ContextType },
431 { "gles" , GrContextFactory::kGLES_ContextType },
432 { "angle_d3d9_es2" , GrContextFactory::kANGLE_D3D9_ES2_ContextType },
433 { "angle_d3d11_es2", GrContextFactory::kANGLE_D3D11_ES2_ContextType },
434 { "angle_d3d11_es3", GrContextFactory::kANGLE_D3D11_ES3_ContextType },
435 { "angle_gl_es2" , GrContextFactory::kANGLE_GL_ES2_ContextType },
436 { "angle_gl_es3" , GrContextFactory::kANGLE_GL_ES3_ContextType },
437 { "commandbuffer" , GrContextFactory::kCommandBuffer_ContextType },
438 { "vk" , GrContextFactory::kVulkan_ContextType },
439 { "mtl" , GrContextFactory::kMetal_ContextType },
440 { "mock" , GrContextFactory::kMock_ContextType },
441 };
Mike Klein735c7ba2019-03-25 12:57:58 -0500442 const FlagOption<SkColorType> kColorTypes[] = {
443 { "a8", kAlpha_8_SkColorType },
444 { "g8", kGray_8_SkColorType },
445 { "565", kRGB_565_SkColorType },
446 { "4444", kARGB_4444_SkColorType },
447 { "8888", kN32_SkColorType },
448 { "888x", kRGB_888x_SkColorType },
449 { "1010102", kRGBA_1010102_SkColorType },
450 { "101010x", kRGB_101010x_SkColorType },
451 { "f16norm", kRGBA_F16Norm_SkColorType },
452 { "f16", kRGBA_F16_SkColorType },
453 { "f32", kRGBA_F32_SkColorType },
454 { "rgba", kRGBA_8888_SkColorType },
455 { "bgra", kBGRA_8888_SkColorType },
456 };
457 const FlagOption<SkAlphaType> kAlphaTypes[] = {
458 { "premul", kPremul_SkAlphaType },
459 { "unpremul", kUnpremul_SkAlphaType },
460 };
461 const FlagOption<skcms_Matrix3x3> kGamuts[] = {
462 { "srgb", SkNamedGamut::kSRGB },
463 { "p3", SkNamedGamut::kDCIP3 },
464 { "rec2020", SkNamedGamut::kRec2020 },
465 { "adobe", SkNamedGamut::kAdobeRGB },
466 { "narrow", gNarrow_toXYZD50},
467 };
468 const FlagOption<skcms_TransferFunction> kTransferFunctions[] = {
469 { "srgb" , SkNamedTransferFn::kSRGB },
470 { "rec2020", {2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0} },
471 { "2.2" , SkNamedTransferFn::k2Dot2 },
472 { "linear" , SkNamedTransferFn::kLinear },
473 };
474
Mike Klein735c7ba2019-03-25 12:57:58 -0500475
Mike Klein9b462092019-03-27 13:52:35 -0500476 int backend;
Mike Klein735c7ba2019-03-25 12:57:58 -0500477 SkColorType ct;
478 SkAlphaType at;
479 skcms_Matrix3x3 gamut;
480 skcms_TransferFunction tf;
Mike Klein735c7ba2019-03-25 12:57:58 -0500481
Mike Klein9b462092019-03-27 13:52:35 -0500482 if (!parse_flag(FLAGS_backend, "backend", kBackends , &backend) ||
483 !parse_flag(FLAGS_ct , "ct" , kColorTypes , &ct) ||
Mike Klein735c7ba2019-03-25 12:57:58 -0500484 !parse_flag(FLAGS_at , "at" , kAlphaTypes , &at) ||
485 !parse_flag(FLAGS_gamut , "gamut" , kGamuts , &gamut) ||
Mike Klein9b462092019-03-27 13:52:35 -0500486 !parse_flag(FLAGS_tf , "tf" , kTransferFunctions, &tf)) {
Mike Klein735c7ba2019-03-25 12:57:58 -0500487 return 1;
488 }
489
490 const SkImageInfo unsized_info = SkImageInfo::Make(0,0, ct,at, SkColorSpace::MakeRGB(tf,gamut));
491
492 for (auto source : sources) {
493 const auto start = std::chrono::steady_clock::now();
Mike Klein832d3c52019-04-02 15:23:46 -0400494 fprintf(stdout, "%50s", source.name.c_str());
Mike Klein735c7ba2019-03-25 12:57:58 -0500495
496 const SkImageInfo info = unsized_info.makeWH(source.size.width(),
497 source.size.height());
498
499 GrContextOptions options = baseOptions;
500 source.tweak(&options);
501 GrContextFactory factory(options); // N.B. factory must outlive image
502
503 sk_sp<SkImage> image;
Mike Klein9b462092019-03-27 13:52:35 -0500504 sk_sp<SkData> blob;
505 const char* ext = ".png";
Mike Klein735c7ba2019-03-25 12:57:58 -0500506 switch (backend) {
507 case kCPU_Backend:
508 image = draw_with_cpu(source.draw, info);
509 break;
Mike Klein9b462092019-03-27 13:52:35 -0500510 case kSKP_Backend:
511 blob = draw_as_skp(source.draw, info);
512 ext = ".skp";
513 break;
Mike Kleinc245bd92019-03-27 14:31:09 -0500514 case kPDF_Backend:
515 blob = draw_as_pdf(source.draw, info, source.name);
516 ext = ".pdf";
517 break;
Mike Klein735c7ba2019-03-25 12:57:58 -0500518 default:
519 image = draw_with_gpu(source.draw, info,
520 (GrContextFactory::ContextType)backend, &factory);
521 break;
522 }
523
Mike Klein9b462092019-03-27 13:52:35 -0500524 if (!image && !blob) {
Mike Klein832d3c52019-04-02 15:23:46 -0400525 fprintf(stdout, "\tskipped\n");
Mike Kleina5c27172019-04-02 10:26:48 -0400526 continue;
Mike Klein735c7ba2019-03-25 12:57:58 -0500527 }
528
529 SkBitmap bitmap;
Mike Klein9b462092019-03-27 13:52:35 -0500530 if (image && !image->asLegacyBitmap(&bitmap)) {
Mike Klein735c7ba2019-03-25 12:57:58 -0500531 fprintf(stderr, "SkImage::asLegacyBitmap() failed.\n");
532 exit_with_failure();
533 }
534
535 HashAndEncode hashAndEncode{bitmap};
536 SkString md5;
537 {
538 SkMD5 hash;
Mike Klein9b462092019-03-27 13:52:35 -0500539 if (image) {
540 hashAndEncode.write(&hash);
541 } else {
542 hash.write(blob->data(), blob->size());
543 }
Mike Klein735c7ba2019-03-25 12:57:58 -0500544
545 SkMD5::Digest digest;
546 hash.finish(digest);
547 for (int i = 0; i < 16; i++) {
548 md5.appendf("%02x", digest.data[i]);
549 }
550 }
551
552 if (!FLAGS_writePath.isEmpty()) {
553 sk_mkdir(FLAGS_writePath[0]);
Mike Klein9b462092019-03-27 13:52:35 -0500554 SkString path = SkStringPrintf("%s/%s%s", FLAGS_writePath[0], source.name.c_str(), ext);
Mike Klein735c7ba2019-03-25 12:57:58 -0500555
Mike Klein9b462092019-03-27 13:52:35 -0500556 if (image) {
557 if (!hashAndEncode.writePngTo(path.c_str(), md5.c_str(),
558 FLAGS_key, FLAGS_parameters)) {
559 fprintf(stderr, "Could not write to %s.\n", path.c_str());
560 exit_with_failure();
561 }
562 } else {
563 SkFILEWStream file(path.c_str());
564 file.write(blob->data(), blob->size());
Mike Klein735c7ba2019-03-25 12:57:58 -0500565 }
Mike Klein735c7ba2019-03-25 12:57:58 -0500566 }
567
Mike Klein832d3c52019-04-02 15:23:46 -0400568 const auto elapsed = std::chrono::steady_clock::now() - start;
569 fprintf(stdout, "\t%s\t%7dms\n",
570 md5.c_str(),
571 (int)std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count());
Mike Klein735c7ba2019-03-25 12:57:58 -0500572 }
573
574 return 0;
575}