Flutter Engine
The Flutter Engine
DM.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 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 "dm/DMJsonWriter.h"
9#include "dm/DMSrcSink.h"
15#include "include/core/SkData.h"
18#include "src/base/SkHalf.h"
21#include "src/base/SkSpinlock.h"
22#include "src/base/SkTime.h"
23#include "src/base/SkVx.h"
24#include "src/core/SkChecksum.h"
26#include "src/core/SkMD5.h"
27#include "src/core/SkOSFile.h"
29#include "src/core/SkTHash.h"
31#include "src/utils/SkOSPath.h"
32#include "tests/Test.h"
33#include "tests/TestHarness.h"
35#include "tools/CodecUtils.h"
36#include "tools/HashAndEncode.h"
37#include "tools/ProcStats.h"
38#include "tools/Resources.h"
40#include "tools/ToolUtils.h"
44#include "tools/ios_utils.h"
48
49#include <memory>
50#include <vector>
51
52#include <stdlib.h>
53
54#ifndef SK_BUILD_FOR_WIN
55 #include <unistd.h>
56#endif
57
58#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_HAS_HEIF_LIBRARY)
59 #include <binder/IPCThreadState.h>
60#endif
61
62#if defined(SK_BUILD_FOR_MAC)
65#endif
66
67#if defined(SK_ENABLE_SVG)
69#endif
70
71using namespace skia_private;
72
75extern bool gCreateProtectedContext;
76
77static DEFINE_string(src, "tests gm skp mskp lottie rive svg image colorImage",
78 "Source types to test.");
79static DEFINE_bool(nameByHash, false,
80 "If true, write to FLAGS_writePath[0]/<hash>.png instead of "
81 "to FLAGS_writePath[0]/<config>/<sourceType>/<sourceOptions>/<name>.png");
82static DEFINE_bool2(pathOpsExtended, x, false, "Run extended pathOps tests.");
83static DEFINE_string(matrix, "1 0 0 1",
84 "2x2 scale+skew matrix to apply or upright when using "
85 "'matrix' or 'upright' in config.");
86
88 "Space-separated config/src/srcOptions/name quadruples to skip. "
89 "'_' matches anything. '~' negates the match. E.g. \n"
90 "'--skip gpu skp _ _' will skip all SKPs drawn into the gpu config.\n"
91 "'--skip gpu skp _ _ 8888 gm _ aarects' will also skip the aarects GM on 8888.\n"
92 "'--skip ~8888 svg _ svgparse_' blocks non-8888 SVGs that contain \"svgparse_\" in "
93 "the name.");
94
95static DEFINE_string2(readPath, r, "",
96 "If set check for equality with golden results in this directory.");
97DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
98
99
100static DEFINE_string(uninterestingHashesFile, "",
101 "File containing a list of uninteresting hashes. If a result hashes to something in "
102 "this list, no image is written for that result.");
103
104static DEFINE_int(shards, 1, "We're splitting source data into this many shards.");
105static DEFINE_int(shard, 0, "Which shard do I run?");
106
107static DEFINE_string(mskps, "", "Directory to read mskps from, or a single mskp file.");
108static DEFINE_bool(forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter");
109static DEFINE_bool(forceRasterPipelineHP, false, "sets gSkForceRasterPipelineBlitter and gForceHighPrecisionRasterPipeline");
110static DEFINE_bool(createProtected, false, "attempts to create a protected backend context");
111
112static DEFINE_string(bisect, "",
113 "Pair of: SKP file to bisect, followed by an l/r bisect trail string (e.g., 'lrll'). The "
114 "l/r trail specifies which half to keep at each step of a binary search through the SKP's "
115 "paths. An empty string performs no bisect. Only the SkPaths are bisected; all other draws "
116 "are thrown out. This is useful for finding a reduced repo case for path drawing bugs.");
117
118static DEFINE_bool(ignoreSigInt, false, "ignore SIGINT signals during test execution");
119
120static DEFINE_bool(checkF16, false, "Ensure that F16Norm pixels are clamped.");
121
122static DEFINE_string(colorImages, "",
123 "List of images and/or directories to decode with color correction. "
124 "A directory with no images is treated as a fatal error.");
125
126static DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
127
128static DEFINE_bool(cpu, true, "Run CPU-bound work?");
129static DEFINE_bool(gpu, true, "Run GPU-bound work?");
130static DEFINE_bool(graphite, true, "Run Graphite work?");
131static DEFINE_bool(neverYieldToWebGPU, false, "Run Graphite with never-yield context option.");
132
133static DEFINE_bool(dryRun, false,
134 "just print the tests that would be run, without actually running them.");
135
137 "List of images and/or directories to decode. A directory with no images"
138 " is treated as a fatal error.");
139
140static DEFINE_bool(simpleCodec, false,
141 "Runs of a subset of the codec tests, "
142 "with no scaling or subsetting, always using the canvas color type.");
143
144static DEFINE_string2(match, m, nullptr,
145 "[~][^]substring[$] [...] of name to run.\n"
146 "Multiple matches may be separated by spaces.\n"
147 "~ causes a matching name to always be skipped\n"
148 "^ requires the start of the name to match\n"
149 "$ requires the end of the name to match\n"
150 "^ and $ requires an exact match\n"
151 "If a name does not match any list entry,\n"
152 "it is skipped unless some list entry starts with ~");
153
154static DEFINE_bool2(quiet, q, false, "if true, don't print status updates.");
155static DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
156
157static DEFINE_string(skps, "skps", "Directory to read skps from.");
158static DEFINE_string(lotties, "lotties", "Directory to read (Bodymovin) jsons from.");
159static DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
160
161static DEFINE_int_2(threads, j, -1,
162 "Run threadsafe tests on a threadpool with this many extra threads, "
163 "defaulting to one extra thread per core.");
164
166 "Space-separated key/value pairs to add to JSON identifying this builder.");
167static DEFINE_string(properties, "",
168 "Space-separated key/value pairs to add to JSON identifying this run.");
169
170static DEFINE_bool(rasterize_pdf, false, "Rasterize PDFs when possible.");
171
172#if defined(__MSVC_RUNTIME_CHECKS)
173#include <rtcapi.h>
174int RuntimeCheckErrorFunc(int errorType, const char* filename, int linenumber,
175 const char* moduleName, const char* fmt, ...) {
176 va_list args;
177 va_start(args, fmt);
178 vfprintf(stderr, fmt, args);
179 va_end(args);
180
181 SkDebugf("Line #%d\nFile: %s\nModule: %s\n",
182 linenumber, filename ? filename : "Unknown", moduleName ? moduleName : "Unknwon");
183 return 1;
184}
185#endif
186
187using namespace DM;
191#ifdef SK_GL
193#endif
194
195/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
196
197static FILE* gVLog;
198
199static void vlog(const char* fmt, ...) SK_PRINTF_LIKE(1, 2);
200
201static void vlog(const char* fmt, ...) {
202 if (gVLog) {
203 va_list args;
204 va_start(args, fmt);
205 vfprintf(gVLog, fmt, args);
206 fflush(gVLog);
207 va_end(args);
208 }
209}
210
211static void info(const char* fmt, ...) SK_PRINTF_LIKE(1, 2);
212
213static void info(const char* fmt, ...) {
214 va_list args;
215 va_start(args, fmt);
216
217 if (gVLog) {
218 va_list vlogArgs;
219 va_copy(vlogArgs, args);
220 vfprintf(gVLog, fmt, vlogArgs);
221 fflush(gVLog);
222 va_end(vlogArgs);
223 }
224
225 if (!FLAGS_quiet) {
226 vprintf(fmt, args);
227 }
228
229 va_end(args);
230}
231
233
234static void fail(const SkString& err) {
235 static SkSpinlock mutex;
236 SkAutoSpinlock lock(mutex);
237 SkDebugf("\n\nFAILURE: %s\n\n", err.c_str());
238 gFailures->push_back(err);
239}
240
241struct Running {
244
245 void dump() const {
246 info("\t%s\n", id.c_str());
247 }
248};
249
250static void dump_json() {
251 if (!FLAGS_writePath.isEmpty()) {
252 JsonWriter::DumpJson(FLAGS_writePath[0], FLAGS_key, FLAGS_properties);
253 }
254}
255
256// We use a spinlock to make locking this in a signal handler _somewhat_ safe.
257static SkSpinlock gMutex;
258static int gPending;
259static int gTotalCounts;
260static double gLastUpdate;
262
263static void done(const char* config, const char* src, const char* srcOptions, const char* name) {
264 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name);
265 bool updateDueToProgress;
266 double lastUpdate;
267 int totalCounts;
268 int pending;
269 {
271 for (int i = 0; i < gRunning->size(); i++) {
272 if (gRunning->at(i).id == id) {
273 gRunning->removeShuffle(i);
274 break;
275 }
276 }
277 --gPending;
278 updateDueToProgress = gPending % 500 == 0;
279 lastUpdate = gLastUpdate;
280 totalCounts = gTotalCounts;
281 pending = gPending;
282 }
283 vlog("[%d/%d] %s done\n", totalCounts - pending, totalCounts, id.c_str());
284
285 // We write out dm.json file and print out a progress update every once in a while.
286 // Notice this also handles the final dm.json and progress update when pending == 0.
287 double now = SkTime::GetNSecs();
288 bool updateDueToTime = now - lastUpdate > 4e9;
289 if (updateDueToProgress || updateDueToTime) {
290 dump_json();
291
294
296
297 // Since multiple threads can call `done`, it's possible that another thread has raced with
298 // this one and printed an update since we did our progress check above. We detect this case
299 // by checking to see if `gLastUpdate` has changed; if so, we don't need to print anything.
300 if (lastUpdate == gLastUpdate) {
301 info("\n[%d/%d] %dMB RAM, %dMB peak, %d queued, %d threads:\n\t%s done\n",
303 curr, peak, gPending - gRunning->size(), gRunning->size() + 1, id.c_str());
304 for (auto& task : *gRunning) {
305 task.dump();
306 }
307 gLastUpdate = now;
308 }
309 }
310}
311
312static void start(const char* config, const char* src, const char* srcOptions, const char* name) {
313 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name);
314 vlog("\tstart %s\n", id.c_str());
316 gRunning->push_back({id,SkGetThreadID()});
317}
318
319static void find_culprit() {
320 // Assumes gMutex is locked.
321 SkThreadID thisThread = SkGetThreadID();
322 for (auto& task : *gRunning) {
323 if (task.thread == thisThread) {
324 info("Likely culprit:\n");
325 task.dump();
326 }
327 }
328}
329
330#if defined(SK_BUILD_FOR_WIN)
331 static LONG WINAPI crash_handler(EXCEPTION_POINTERS* e) {
332 static const struct {
333 const char* name;
334 DWORD code;
335 } kExceptions[] = {
336 #define _(E) {#E, E}
337 _(EXCEPTION_ACCESS_VIOLATION),
338 _(EXCEPTION_BREAKPOINT),
339 _(EXCEPTION_INT_DIVIDE_BY_ZERO),
340 _(EXCEPTION_STACK_OVERFLOW),
341 // TODO: more?
342 #undef _
343 };
344
346
347 const DWORD code = e->ExceptionRecord->ExceptionCode;
348 info("\nCaught exception %lu", code);
349 for (const auto& exception : kExceptions) {
350 if (exception.code == code) {
351 info(" %s", exception.name);
352 }
353 }
354 info(", was running:\n");
355 for (auto& task : *gRunning) {
356 task.dump();
357 }
358 find_culprit();
359 fflush(stdout);
360
361 // Execute default exception handler... hopefully, exit.
362 return EXCEPTION_EXECUTE_HANDLER;
363 }
364
365 static void setup_crash_handler() {
366 SetUnhandledExceptionFilter(crash_handler);
367 }
368#else
369 #include <signal.h>
370 #if !defined(SK_BUILD_FOR_ANDROID)
371 #include <execinfo.h>
372
373#endif
374
375 static constexpr int max_of() { return 0; }
376 template <typename... Rest>
377 static constexpr int max_of(int x, Rest... rest) {
378 return x > max_of(rest...) ? x : max_of(rest...);
379 }
380
381 static void (*previous_handler[max_of(SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGSEGV,SIGTERM)+1])(int);
382
383 static void crash_handler(int sig) {
385
386 info("\nCaught signal %d [%s] (%dMB RAM, peak %dMB), was running:\n",
387 sig, strsignal(sig),
389
390 for (auto& task : *gRunning) {
391 task.dump();
392 }
393 find_culprit();
394
395 #if !defined(SK_BUILD_FOR_ANDROID)
396 void* stack[128];
397 int count = backtrace(stack, std::size(stack));
398 char** symbols = backtrace_symbols(stack, count);
399 info("\nStack trace:\n");
400 for (int i = 0; i < count; i++) {
401 info(" %s\n", symbols[i]);
402 }
403 #endif
404 fflush(stdout);
405
406 if (sig == SIGINT && FLAGS_ignoreSigInt) {
407 info("Ignoring signal %d because of --ignoreSigInt.\n"
408 "This is probably a sign the bot is overloaded with work.\n", sig);
409 } else {
410 signal(sig, previous_handler[sig]);
411 raise(sig);
412 }
413 }
414
415 static void setup_crash_handler() {
416 const int kSignals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM };
417 for (int sig : kSignals) {
418 previous_handler[sig] = signal(sig, crash_handler);
419 }
420 }
421#endif
422
423/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
424
425struct Gold : public SkString {
426 Gold() : SkString("") {}
427 Gold(const SkString& sink, const SkString& src,
428 const SkString& srcOptions, const SkString& name,
429 const SkString& md5)
430 : SkString("") {
431 this->append(sink);
432 this->append(src);
433 this->append(srcOptions);
434 this->append(name);
435 this->append(md5);
436 }
437 struct Hash {
438 uint32_t operator()(const Gold& g) const {
439 return SkGoodHash()((const SkString&)g);
440 }
441 };
442};
444
446 gGold->add(Gold(r.config, r.sourceType, r.sourceOptions, r.name, r.md5));
447}
448
449static void gather_gold() {
450 if (!FLAGS_readPath.isEmpty()) {
451 SkString path(FLAGS_readPath[0]);
452 path.append("/dm.json");
453 if (!JsonWriter::ReadJson(path.c_str(), add_gold)) {
454 fail(SkStringPrintf("Couldn't read %s for golden results.", path.c_str()));
455 }
456 }
457}
458
459/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
460
461#if defined(SK_BUILD_FOR_WIN)
462 static constexpr char kNewline[] = "\r\n";
463#else
464 static constexpr char kNewline[] = "\n";
465#endif
466
468
470 if (!FLAGS_uninterestingHashesFile.isEmpty()) {
471 sk_sp<SkData> data(SkData::MakeFromFileName(FLAGS_uninterestingHashesFile[0]));
472 if (!data) {
473 info("WARNING: unable to read uninteresting hashes from %s\n",
474 FLAGS_uninterestingHashesFile[0]);
475 return;
476 }
477
478 // Copy to a string to make sure SkStrSplit has a terminating \0 to find.
479 SkString contents((const char*)data->data(), data->size());
480
482 SkStrSplit(contents.c_str(), kNewline, &hashes);
483 for (const SkString& hash : hashes) {
485 }
486 info("FYI: loaded %d distinct uninteresting hashes from %d lines\n",
487 gUninterestingHashes->count(), hashes.size());
488 }
489}
490
491/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
492
493struct TaggedSrc : public std::unique_ptr<Src> {
496};
497
498struct TaggedSink : public std::unique_ptr<Sink> {
500};
501
502static constexpr bool kMemcpyOK = true;
503
506
507static bool in_shard() {
508 static int N = 0;
509 return N++ % FLAGS_shards == FLAGS_shard;
510}
511
512static void push_src(const char* tag, ImplicitString options, Src* inSrc) {
513 std::unique_ptr<Src> src(inSrc);
514 if (in_shard() && FLAGS_src.contains(tag) &&
515 !CommandLineFlags::ShouldSkip(FLAGS_match, src->name().c_str())) {
516 TaggedSrc& s = gSrcs->push_back();
517 s.reset(src.release()); // NOLINT(misc-uniqueptr-reset-release)
518 s.tag = tag;
519 s.options = options;
520 }
521}
522
524 SkAlphaType dstAlphaType, float scale) {
525 if (FLAGS_simpleCodec) {
526 const bool simple = CodecSrc::kCodec_Mode == mode || CodecSrc::kAnimated_Mode == mode;
527 if (!simple || dstColorType != CodecSrc::kGetFromCanvas_DstColorType || scale != 1.0f) {
528 // Only decode in the simple case.
529 return;
530 }
531 }
533 switch (mode) {
534 case CodecSrc::kCodec_Mode:
535 folder.append("codec");
536 break;
537 case CodecSrc::kCodecZeroInit_Mode:
538 folder.append("codec_zero_init");
539 break;
540 case CodecSrc::kScanline_Mode:
541 folder.append("scanline");
542 break;
543 case CodecSrc::kStripe_Mode:
544 folder.append("stripe");
545 break;
546 case CodecSrc::kCroppedScanline_Mode:
547 folder.append("crop");
548 break;
549 case CodecSrc::kSubset_Mode:
550 folder.append("codec_subset");
551 break;
552 case CodecSrc::kAnimated_Mode:
553 folder.append("codec_animated");
554 break;
555 }
556
557 switch (dstColorType) {
558 case CodecSrc::kGrayscale_Always_DstColorType:
559 folder.append("_kGray8");
560 break;
561 case CodecSrc::kNonNative8888_Always_DstColorType:
562 folder.append("_kNonNative");
563 break;
564 default:
565 break;
566 }
567
568 switch (dstAlphaType) {
570 folder.append("_premul");
571 break;
573 folder.append("_unpremul");
574 break;
575 default:
576 break;
577 }
578
579 if (1.0f != scale) {
580 folder.appendf("_%.3f", scale);
581 }
582
583 CodecSrc* src = new CodecSrc(path, mode, dstColorType, dstAlphaType, scale);
584 push_src("image", folder, src);
585}
586
588 SkAlphaType dstAlphaType, int sampleSize) {
590 folder.append("scaled_codec");
591
592 switch (dstColorType) {
593 case CodecSrc::kGrayscale_Always_DstColorType:
594 folder.append("_kGray8");
595 break;
596 case CodecSrc::kNonNative8888_Always_DstColorType:
597 folder.append("_kNonNative");
598 break;
599 default:
600 break;
601 }
602
603 switch (dstAlphaType) {
605 folder.append("_premul");
606 break;
608 folder.append("_unpremul");
609 break;
610 default:
611 break;
612 }
613
614 if (1 != sampleSize) {
615 folder.appendf("_%.3f", 1.0f / (float) sampleSize);
616 }
617
618 AndroidCodecSrc* src = new AndroidCodecSrc(path, dstColorType, dstAlphaType, sampleSize);
619 push_src("image", folder, src);
620}
621
622static void push_image_gen_src(Path path, ImageGenSrc::Mode mode, SkAlphaType alphaType, bool isGpu)
623{
625 switch (mode) {
626 case ImageGenSrc::kCodec_Mode:
627 folder.append("gen_codec");
628 break;
629 case ImageGenSrc::kPlatform_Mode:
630 folder.append("gen_platform");
631 break;
632 }
633
634 if (isGpu) {
635 folder.append("_gpu");
636 } else {
637 switch (alphaType) {
639 folder.append("_opaque");
640 break;
642 folder.append("_premul");
643 break;
645 folder.append("_unpremul");
646 break;
647 default:
648 break;
649 }
650 }
651
652 ImageGenSrc* src = new ImageGenSrc(path, mode, alphaType, isGpu);
653 push_src("image", folder, src);
654}
655
656#ifdef SK_ENABLE_ANDROID_UTILS
657static void push_brd_src(Path path, CodecSrc::DstColorType dstColorType, BRDSrc::Mode mode,
658 uint32_t sampleSize) {
659 SkString folder("brd_android_codec");
660 switch (mode) {
661 case BRDSrc::kFullImage_Mode:
662 break;
663 case BRDSrc::kDivisor_Mode:
664 folder.append("_divisor");
665 break;
666 default:
667 SkASSERT(false);
668 return;
669 }
670
671 switch (dstColorType) {
672 case CodecSrc::kGetFromCanvas_DstColorType:
673 break;
674 case CodecSrc::kGrayscale_Always_DstColorType:
675 folder.append("_kGray");
676 break;
677 default:
678 SkASSERT(false);
679 return;
680 }
681
682 if (1 != sampleSize) {
683 folder.appendf("_%.3f", 1.0f / (float) sampleSize);
684 }
685
686 BRDSrc* src = new BRDSrc(path, mode, dstColorType, sampleSize);
687 push_src("image", folder, src);
688}
689
690static void push_brd_srcs(Path path, bool gray) {
691 if (gray) {
692 // Only run grayscale to one sampleSize and Mode. Though interesting
693 // to test grayscale, it should not reveal anything across various
694 // sampleSizes and Modes
695 // Arbitrarily choose Mode and sampleSize.
696 push_brd_src(path, CodecSrc::kGrayscale_Always_DstColorType,
697 BRDSrc::kFullImage_Mode, 2);
698 }
699
700 // Test on a variety of sampleSizes, making sure to include:
701 // - 2, 4, and 8, which are natively supported by jpeg
702 // - multiples of 2 which are not divisible by 4 (analogous for 4)
703 // - larger powers of two, since BRD clients generally use powers of 2
704 // We will only produce output for the larger sizes on large images.
705 const uint32_t sampleSizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32, 64 };
706
707 const BRDSrc::Mode modes[] = { BRDSrc::kFullImage_Mode, BRDSrc::kDivisor_Mode, };
708
709 for (uint32_t sampleSize : sampleSizes) {
710 for (BRDSrc::Mode mode : modes) {
711 push_brd_src(path, CodecSrc::kGetFromCanvas_DstColorType, mode, sampleSize);
712 }
713 }
714}
715#endif // SK_ENABLE_ANDROID_UTILS
716
719 if (!encoded) {
720 info("Couldn't read %s.", path.c_str());
721 return;
722 }
723 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(encoded);
724 if (nullptr == codec) {
725 info("Couldn't create codec for %s.", path.c_str());
726 return;
727 }
728
729 // native scaling is only supported by WEBP and JPEG
730 bool supportsNativeScaling = false;
731
732 TArray<CodecSrc::Mode> nativeModes;
733 nativeModes.push_back(CodecSrc::kCodec_Mode);
734 nativeModes.push_back(CodecSrc::kCodecZeroInit_Mode);
735 switch (codec->getEncodedFormat()) {
737 nativeModes.push_back(CodecSrc::kScanline_Mode);
738 nativeModes.push_back(CodecSrc::kStripe_Mode);
739 nativeModes.push_back(CodecSrc::kCroppedScanline_Mode);
740 supportsNativeScaling = true;
741 break;
743 nativeModes.push_back(CodecSrc::kSubset_Mode);
744 supportsNativeScaling = true;
745 break;
747 break;
748 default:
749 nativeModes.push_back(CodecSrc::kScanline_Mode);
750 break;
751 }
752
754 colorTypes.push_back(CodecSrc::kGetFromCanvas_DstColorType);
755 colorTypes.push_back(CodecSrc::kNonNative8888_Always_DstColorType);
756 switch (codec->getInfo().colorType()) {
758 colorTypes.push_back(CodecSrc::kGrayscale_Always_DstColorType);
759 break;
760 default:
761 break;
762 }
763
764 TArray<SkAlphaType> alphaModes;
765 alphaModes.push_back(kPremul_SkAlphaType);
766 if (codec->getInfo().alphaType() != kOpaque_SkAlphaType) {
768 }
769
770 for (CodecSrc::Mode mode : nativeModes) {
771 for (CodecSrc::DstColorType colorType : colorTypes) {
772 for (SkAlphaType alphaType : alphaModes) {
773 // Only test kCroppedScanline_Mode when the alpha type is premul. The test is
774 // slow and won't be interestingly different with different alpha types.
775 if (CodecSrc::kCroppedScanline_Mode == mode &&
776 kPremul_SkAlphaType != alphaType) {
777 continue;
778 }
779
780 push_codec_src(path, mode, colorType, alphaType, 1.0f);
781
782 // Skip kNonNative on different native scales. It won't be interestingly
783 // different.
784 if (supportsNativeScaling &&
785 CodecSrc::kNonNative8888_Always_DstColorType == colorType) {
786 // Native Scales
787 // SkJpegCodec natively supports scaling to the following:
788 for (auto scale : { 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.750f, 0.875f }) {
789 push_codec_src(path, mode, colorType, alphaType, scale);
790 }
791 }
792 }
793 }
794 }
795
796 {
797 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
798 if (frameInfos.size() > 1) {
799 for (auto dstCT : { CodecSrc::kNonNative8888_Always_DstColorType,
800 CodecSrc::kGetFromCanvas_DstColorType }) {
801 for (auto at : { kUnpremul_SkAlphaType, kPremul_SkAlphaType }) {
802 push_codec_src(path, CodecSrc::kAnimated_Mode, dstCT, at, 1.0f);
803 }
804 }
805 for (float scale : { .5f, .33f }) {
806 push_codec_src(path, CodecSrc::kAnimated_Mode, CodecSrc::kGetFromCanvas_DstColorType,
808 }
809 }
810
811 }
812
813 if (FLAGS_simpleCodec) {
814 return;
815 }
816
817 const int sampleSizes[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
818
819 for (int sampleSize : sampleSizes) {
820 for (CodecSrc::DstColorType colorType : colorTypes) {
821 for (SkAlphaType alphaType : alphaModes) {
822 // We can exercise all of the kNonNative support code in the swizzler with just a
823 // few sample sizes. Skip the rest.
824 if (CodecSrc::kNonNative8888_Always_DstColorType == colorType && sampleSize > 3) {
825 continue;
826 }
827
828 push_android_codec_src(path, colorType, alphaType, sampleSize);
829 }
830 }
831 }
832
833 const char* ext = strrchr(path.c_str(), '.');
834 if (ext) {
835 ext++;
836
837 static const char* const rawExts[] = {
838 "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
839 "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
840 };
841 for (const char* rawExt : rawExts) {
842 if (0 == strcmp(rawExt, ext)) {
843 // RAW is not supported by image generator (skbug.com/5079) or BRD.
844 return;
845 }
846 }
847
848#ifdef SK_ENABLE_ANDROID_UTILS
849 static const char* const brdExts[] = {
850 "jpg", "jpeg", "png", "webp",
851 "JPG", "JPEG", "PNG", "WEBP",
852 };
853 for (const char* brdExt : brdExts) {
854 if (0 == strcmp(brdExt, ext)) {
855 bool gray = codec->getInfo().colorType() == kGray_8_SkColorType;
856 push_brd_srcs(path, gray);
857 break;
858 }
859 }
860#endif
861 }
862
863 // Push image generator GPU test.
864 push_image_gen_src(path, ImageGenSrc::kCodec_Mode, codec->getInfo().alphaType(), true);
865
866 // Push image generator CPU tests.
867 for (SkAlphaType alphaType : alphaModes) {
868 push_image_gen_src(path, ImageGenSrc::kCodec_Mode, alphaType, false);
869
870#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
871 if (SkEncodedImageFormat::kWEBP != codec->getEncodedFormat() &&
872 SkEncodedImageFormat::kWBMP != codec->getEncodedFormat() &&
873 kUnpremul_SkAlphaType != alphaType)
874 {
875 push_image_gen_src(path, ImageGenSrc::kPlatform_Mode, alphaType, false);
876 }
877#elif defined(SK_BUILD_FOR_WIN)
878 if (SkEncodedImageFormat::kWEBP != codec->getEncodedFormat() &&
879 SkEncodedImageFormat::kWBMP != codec->getEncodedFormat())
880 {
881 push_image_gen_src(path, ImageGenSrc::kPlatform_Mode, alphaType, false);
882 }
883#elif defined(SK_ENABLE_NDK_IMAGES)
884 push_image_gen_src(path, ImageGenSrc::kPlatform_Mode, alphaType, false);
885#endif
886 }
887}
888
889template <typename T>
891 const char* ext,
892 const char* src_name = nullptr) {
893 if (!src_name) {
894 // With the exception of Lottie files, the source name is the extension.
895 src_name = ext;
896 }
897
898 for (int i = 0; i < flags.size(); i++) {
899 const char* path = flags[i];
900 if (sk_isdir(path)) {
902 for (SkString file; it.next(&file); ) {
903 push_src(src_name, "", new T(SkOSPath::Join(path, file.c_str())));
904 }
905 } else {
906 push_src(src_name, "", new T(path));
907 }
908 }
909}
910
911static bool gather_srcs() {
913 push_src("gm", "", new GMSrc(f));
914 }
915
916 gather_file_srcs<SKPSrc>(FLAGS_skps, "skp");
917 gather_file_srcs<MSKPSrc>(FLAGS_mskps, "mskp");
918#if defined(SK_ENABLE_SKOTTIE)
919 gather_file_srcs<SkottieSrc>(FLAGS_lotties, "json", "lottie");
920#endif
921#if defined(SK_ENABLE_SVG)
922 gather_file_srcs<SVGSrc>(FLAGS_svgs, "svg");
923#endif
924 if (!FLAGS_bisect.isEmpty()) {
925 // An empty l/r trail string will draw all the paths.
926 push_src("bisect", "",
927 new BisectSrc(FLAGS_bisect[0], FLAGS_bisect.size() > 1 ? FLAGS_bisect[1] : ""));
928 }
929
931 if (!CommonFlags::CollectImages(FLAGS_images, &images)) {
932 return false;
933 }
934
935 for (const SkString& image : images) {
937 }
938
939 TArray<SkString> colorImages;
940 if (!CommonFlags::CollectImages(FLAGS_colorImages, &colorImages)) {
941 return false;
942 }
943
944 for (const SkString& colorImage : colorImages) {
945 push_src("colorImage", "decode_native", new ColorCodecSrc(colorImage, false));
946 push_src("colorImage", "decode_to_dst", new ColorCodecSrc(colorImage, true));
947 }
948
949 return true;
950}
951
952static void push_sink(const SkCommandLineConfig& config, Sink* s) {
953 std::unique_ptr<Sink> sink(s);
954
955 // Try a simple Src as a canary. If it fails, skip this sink.
956 struct : public Src {
958 c->drawRect(SkRect::MakeWH(1,1), SkPaint());
959 return Result::Ok();
960 }
961 SkISize size() const override { return SkISize::Make(16, 16); }
962 Name name() const override { return "justOneRect"; }
963 } justOneRect;
964
968 Result result = sink->draw(justOneRect, &bitmap, &stream, &log);
969 if (result.isFatal()) {
970 info("Could not run %s: %s\n", config.getTag().c_str(), result.c_str());
971 exit(1);
972 }
973
974 TaggedSink& ts = gSinks->push_back();
975 ts.reset(sink.release()); // NOLINT(misc-uniqueptr-reset-release)
976 ts.tag = config.getTag();
977}
978
979static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLineConfig* config) {
980 if (FLAGS_gpu) {
981 if (const SkCommandLineConfigGpu* gpuConfig = config->asConfigGpu()) {
982 GrContextFactory testFactory(grCtxOptions);
983 if (!testFactory.get(gpuConfig->getContextType(), gpuConfig->getContextOverrides())) {
984 info("WARNING: can not create GPU context for config '%s'. "
985 "GM tests will be skipped.\n", gpuConfig->getTag().c_str());
986 return nullptr;
987 }
988 if (gpuConfig->getTestPersistentCache()) {
989 return new GPUPersistentCacheTestingSink(gpuConfig, grCtxOptions);
990 } else if (gpuConfig->getTestPrecompile()) {
991 return new GPUPrecompileTestingSink(gpuConfig, grCtxOptions);
992 } else if (gpuConfig->getUseDDLSink()) {
993 return new GPUDDLSink(gpuConfig, grCtxOptions);
994 } else if (gpuConfig->getSlug()) {
995 return new GPUSlugSink(gpuConfig, grCtxOptions);
996 } else if (gpuConfig->getSerializedSlug()) {
997 return new GPUSerializeSlugSink(gpuConfig, grCtxOptions);
998 } else if (gpuConfig->getRemoteSlug()) {
999 return new GPURemoteSlugSink(gpuConfig, grCtxOptions);
1000 } else {
1001 return new GPUSink(gpuConfig, grCtxOptions);
1002 }
1003 }
1004 }
1005#if defined(SK_GRAPHITE)
1006 if (FLAGS_graphite) {
1007 if (const SkCommandLineConfigGraphite *graphiteConfig = config->asConfigGraphite()) {
1008#if defined(SK_ENABLE_PRECOMPILE)
1009 if (graphiteConfig->getTestPrecompile()) {
1010 return new GraphitePrecompileTestingSink(graphiteConfig);
1011 } else
1012#endif // SK_ENABLE_PRECOMPILE
1013 {
1014 return new GraphiteSink(graphiteConfig);
1015 }
1016 }
1017 }
1018#endif // SK_GRAPHITE
1019 if (const SkCommandLineConfigSvg* svgConfig = config->asConfigSvg()) {
1020 int pageIndex = svgConfig->getPageIndex();
1021 return new SVGSink(pageIndex);
1022 }
1023
1024#define SINK(t, sink, ...) if (config->getBackend().equals(t)) return new sink(__VA_ARGS__)
1025
1026 if (FLAGS_cpu) {
1030 SINK("8888", RasterSink, kN32_SkColorType);
1036 SINK("bgra1010102", RasterSink, kBGRA_1010102_SkColorType);
1042
1043 SINK("pdf", PDFSink, false, SK_ScalarDefaultRasterDPI);
1044 SINK("skp", SKPSink);
1045 SINK("svg", SVGSink);
1046 SINK("null", NullSink);
1047 SINK("xps", XPSSink);
1048 SINK("pdfa", PDFSink, true, SK_ScalarDefaultRasterDPI);
1049 SINK("pdf300", PDFSink, false, 300);
1050 SINK("jsdebug", DebugSink);
1051 }
1052#undef SINK
1053 return nullptr;
1054}
1055
1056static Sink* create_via(const SkString& tag, Sink* wrapped) {
1057#define VIA(t, via, ...) if (tag.equals(t)) return new via(__VA_ARGS__)
1058#ifdef TEST_VIA_SVG
1059 VIA("svg", ViaSVG, wrapped);
1060#endif
1061 VIA("serialize", ViaSerialization, wrapped);
1062 VIA("pic", ViaPicture, wrapped);
1063 VIA("rtblend", ViaRuntimeBlend, wrapped);
1064
1065 if (FLAGS_matrix.size() == 4) {
1066 SkMatrix m;
1067 m.reset();
1068 m.setScaleX((SkScalar)atof(FLAGS_matrix[0]));
1069 m.setSkewX ((SkScalar)atof(FLAGS_matrix[1]));
1070 m.setSkewY ((SkScalar)atof(FLAGS_matrix[2]));
1071 m.setScaleY((SkScalar)atof(FLAGS_matrix[3]));
1072 VIA("matrix", ViaMatrix, m, wrapped);
1073 VIA("upright", ViaUpright, m, wrapped);
1074 }
1075
1076#undef VIA
1077
1078 return nullptr;
1079}
1080
1081static bool gather_sinks(const GrContextOptions& grCtxOptions, bool defaultConfigs) {
1082 if (FLAGS_src.size() == 1 && FLAGS_src.contains("tests")) {
1083 // If we're just running tests skip trying to accumulate sinks. The 'justOneRect' test
1084 // can fail for protected contexts.
1085 return true;
1086 }
1087
1089 ParseConfigs(FLAGS_config, &configs);
1091 for (int i = 0; i < configs.size(); i++) {
1092 const SkCommandLineConfig& config = *configs[i];
1093 Sink* sink = create_sink(grCtxOptions, &config);
1094 if (sink == nullptr) {
1095 info("Skipping config %s: Don't understand '%s'.\n", config.getTag().c_str(),
1096 config.getTag().c_str());
1097 continue;
1098 }
1099
1100 // The command line config already parsed out the via-style color space. Apply it here.
1101 sink->setColorSpace(config.refColorSpace());
1102
1103 const TArray<SkString>& parts = config.getViaParts();
1104 for (int j = parts.size(); j-- > 0;) {
1105 const SkString& part = parts[j];
1106 Sink* next = create_via(part, sink);
1107 if (next == nullptr) {
1108 info("Skipping config %s: Don't understand '%s'.\n", config.getTag().c_str(),
1109 part.c_str());
1110 delete sink;
1111 sink = nullptr;
1112 break;
1113 }
1114 sink = next;
1115 }
1116 if (sink) {
1117 push_sink(config, sink);
1118 }
1119 }
1120
1121 // If no configs were requested (just running tests, perhaps?), then we're okay.
1122 if (configs.size() == 0 ||
1123 // If we're using the default configs, we're okay.
1125 // Otherwise, make sure that all specified configs have become sinks.
1126 configs.size() == gSinks->size()) {
1127 return true;
1128 }
1129 return false;
1130}
1131
1132static bool match(const char* needle, const char* haystack) {
1133 if ('~' == needle[0]) {
1134 return !match(needle + 1, haystack);
1135 }
1136 if (0 == strcmp("_", needle)) {
1137 return true;
1138 }
1139 return nullptr != strstr(haystack, needle);
1140}
1141
1142static bool should_skip(const char* sink, const char* src,
1143 const char* srcOptions, const char* name) {
1144 for (int i = 0; i < FLAGS_skip.size() - 3; i += 4) {
1145 if (match(FLAGS_skip[i+0], sink) &&
1146 match(FLAGS_skip[i+1], src) &&
1147 match(FLAGS_skip[i+2], srcOptions) &&
1148 match(FLAGS_skip[i+3], name)) {
1149 return true;
1150 }
1151 }
1152 return false;
1153}
1154
1155// Even when a Task Sink reports to be non-threadsafe (e.g. GPU), we know things like
1156// .png encoding are definitely thread safe. This lets us offload that work to CPU threads.
1158
1159// The finest-grained unit of work we can run: draw a single Src into a single Sink,
1160// report any errors, and perhaps write out the output: a .png of the bitmap, or a raw stream.
1161struct Task {
1162 Task(const TaggedSrc& src, const TaggedSink& sink) : src(src), sink(sink) {}
1165
1166 static void Run(const Task& task) {
1168 SkString name = task.src->name();
1169
1170 SkString log;
1171 if (!FLAGS_dryRun) {
1174 start(task.sink.tag.c_str(), task.src.tag.c_str(),
1175 task.src.options.c_str(), name.c_str());
1176 Result result = task.sink->draw(*task.src, &bitmap, &stream, &log);
1177 if (!log.isEmpty()) {
1178 info("%s %s %s %s:\n%s\n", task.sink.tag.c_str()
1179 , task.src.tag.c_str()
1180 , task.src.options.c_str()
1181 , name.c_str()
1182 , log.c_str());
1183 }
1184 if (result.isSkip()) {
1185 done(task.sink.tag.c_str(), task.src.tag.c_str(),
1186 task.src.options.c_str(), name.c_str());
1187 return;
1188 }
1189 if (result.isFatal()) {
1190 fail(SkStringPrintf("%s %s %s %s: %s",
1191 task.sink.tag.c_str(),
1192 task.src.tag.c_str(),
1193 task.src.options.c_str(),
1194 name.c_str(),
1195 result.c_str()));
1196 }
1197
1198 // We're likely switching threads here, so we must capture by value, [=] or [foo,bar].
1199 SkStreamAsset* data = stream.detachAsStream().release();
1201 std::unique_ptr<SkStreamAsset> ownedData(data);
1202
1203 std::unique_ptr<HashAndEncode> hashAndEncode;
1204
1205 SkString md5;
1206 if (!FLAGS_writePath.isEmpty() || !FLAGS_readPath.isEmpty()) {
1207 SkMD5 hash;
1208 if (data->getLength()) {
1209 hash.writeStream(data, data->getLength());
1210 data->rewind();
1211 } else {
1212 hashAndEncode = std::make_unique<HashAndEncode>(bitmap);
1213 hashAndEncode->feedHash(&hash);
1214 }
1215 md5 = hash.finish().toLowercaseHexString();
1216 }
1217
1218 if (!FLAGS_readPath.isEmpty() &&
1219 !gGold->contains(Gold(task.sink.tag, task.src.tag,
1220 task.src.options, name, md5))) {
1221 fail(SkStringPrintf("%s not found for %s %s %s %s in %s",
1222 md5.c_str(),
1223 task.sink.tag.c_str(),
1224 task.src.tag.c_str(),
1225 task.src.options.c_str(),
1226 name.c_str(),
1227 FLAGS_readPath[0]));
1228 }
1229
1230 // Tests sometimes use a nullptr ext to indicate no image should be uploaded.
1231 const char* ext = task.sink->fileExtension();
1232 if (ext && !FLAGS_writePath.isEmpty()) {
1233 #if defined(SK_BUILD_FOR_MAC)
1234 if (FLAGS_rasterize_pdf && SkString("pdf").equals(ext)) {
1235 SkASSERT(data->getLength() > 0);
1236
1237 sk_sp<SkData> blob = SkData::MakeFromStream(data, data->getLength());
1238
1239 SkUniqueCFRef<CGDataProviderRef> provider{
1240 CGDataProviderCreateWithData(nullptr,
1241 blob->data(),
1242 blob->size(),
1243 nullptr)};
1244
1245 SkUniqueCFRef<CGPDFDocumentRef> pdf{
1246 CGPDFDocumentCreateWithProvider(provider.get())};
1247
1248 CGPDFPageRef page = CGPDFDocumentGetPage(pdf.get(), 1);
1249
1250 CGRect bounds = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
1251 const int w = (int)CGRectGetWidth (bounds),
1252 h = (int)CGRectGetHeight(bounds);
1253
1254 SkBitmap rasterized;
1255 rasterized.allocPixels(SkImageInfo::Make(
1257 rasterized.eraseColor(SK_ColorWHITE);
1258
1259 SkUniqueCFRef<CGColorSpaceRef> cs{CGColorSpaceCreateDeviceRGB()};
1260 CGBitmapInfo info = kCGBitmapByteOrder32Big |
1261 (CGBitmapInfo)kCGImageAlphaPremultipliedLast;
1262
1263 SkUniqueCFRef<CGContextRef> ctx{CGBitmapContextCreate(
1264 rasterized.getPixels(), w,h,8, rasterized.rowBytes(), cs.get(), info)};
1265 CGContextDrawPDFPage(ctx.get(), page);
1266
1267 // Skip calling hashAndEncode->feedHash(SkMD5*)... we want the .pdf's hash.
1268 hashAndEncode = std::make_unique<HashAndEncode>(rasterized);
1269 WriteToDisk(task, md5, "png", nullptr,0, &rasterized, hashAndEncode.get());
1270 } else
1271 #endif
1272 if (data->getLength()) {
1273 WriteToDisk(task, md5, ext, data, data->getLength(), nullptr, nullptr);
1274 SkASSERT(bitmap.drawsNothing());
1275 } else if (!bitmap.drawsNothing()) {
1276 WriteToDisk(task, md5, ext, nullptr, 0, &bitmap, hashAndEncode.get());
1277 }
1278 }
1279
1280 SkPixmap pm;
1281 if (FLAGS_checkF16 && bitmap.colorType() == kRGBA_F16Norm_SkColorType &&
1282 bitmap.peekPixels(&pm)) {
1283 bool unclamped = false;
1284 for (int y = 0; y < pm.height() && !unclamped; ++y)
1285 for (int x = 0; x < pm.width() && !unclamped; ++x) {
1287 float a = rgba[3];
1288 if (a > 1.0f || any(rgba < 0.0f) || any(rgba > a)) {
1289 SkDebugf("[%s] F16Norm pixel [%d, %d] unclamped: (%g, %g, %g, %g)\n",
1290 name.c_str(), x, y, rgba[0], rgba[1], rgba[2], rgba[3]);
1291 unclamped = true;
1292 }
1293 }
1294 }
1295 });
1296 }
1297 done(task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str(), name.c_str());
1298 }
1299
1301 if (!cs) {
1302 return SkString("untagged");
1303 }
1304
1305 skcms_Matrix3x3 gamut;
1306 if (cs->toXYZD50(&gamut)) {
1307 auto eq = [](skcms_Matrix3x3 x, skcms_Matrix3x3 y) {
1308 for (int i = 0; i < 3; i++)
1309 for (int j = 0; j < 3; j++) {
1310 if (x.vals[i][j] != y.vals[i][j]) { return false; }
1311 }
1312 return true;
1313 };
1314
1315 if (eq(gamut, SkNamedGamut::kSRGB )) { return SkString("sRGB"); }
1316 if (eq(gamut, SkNamedGamut::kAdobeRGB )) { return SkString("Adobe"); }
1317 if (eq(gamut, SkNamedGamut::kDisplayP3)) { return SkString("P3"); }
1318 if (eq(gamut, SkNamedGamut::kRec2020 )) { return SkString("2020"); }
1319 if (eq(gamut, SkNamedGamut::kXYZ )) { return SkString("XYZ"); }
1320 if (eq(gamut, gNarrow_toXYZD50 )) { return SkString("narrow"); }
1321 return SkString("other");
1322 }
1323 return SkString("non-XYZ");
1324 }
1325
1327 if (!cs) {
1328 return SkString("untagged");
1329 }
1330
1332 return x.g == y.g
1333 && x.a == y.a
1334 && x.b == y.b
1335 && x.c == y.c
1336 && x.d == y.d
1337 && x.e == y.e
1338 && x.f == y.f;
1339 };
1340
1342 cs->transferFn(&tf);
1343 switch (skcms_TransferFunction_getType(&tf)) {
1345 if (tf.a == 1 && tf.b == 0 && tf.c == 0 && tf.d == 0 && tf.e == 0 && tf.f == 0) {
1346 return SkStringPrintf("gamma %.3g", tf.g);
1347 }
1348 if (eq(tf, SkNamedTransferFn::kSRGB)) { return SkString("sRGB"); }
1349 if (eq(tf, SkNamedTransferFn::kRec2020)) { return SkString("2020"); }
1350 return SkStringPrintf("%.3g %.3g %.3g %.3g %.3g %.3g %.3g",
1351 tf.g, tf.a, tf.b, tf.c, tf.d, tf.e, tf.f);
1352
1353 case skcms_TFType_PQish:
1354 if (eq(tf, SkNamedTransferFn::kPQ)) { return SkString("PQ"); }
1355 return SkStringPrintf("PQish %.3g %.3g %.3g %.3g %.3g %.3g",
1356 tf.a, tf.b, tf.c, tf.d, tf.e, tf.f);
1357
1359 if (eq(tf, SkNamedTransferFn::kHLG)) { return SkString("HLG"); }
1360 return SkStringPrintf("HLGish %.3g %.3g %.3g %.3g %.3g (%.3g)",
1361 tf.a, tf.b, tf.c, tf.d, tf.e, tf.f+1);
1362
1363 case skcms_TFType_HLGinvish: break;
1364 case skcms_TFType_Invalid: break;
1365 }
1366 return SkString("non-numeric");
1367 }
1368
1369 static void WriteToDisk(const Task& task,
1370 SkString md5,
1371 const char* ext,
1372 SkStream* data, size_t len,
1373 const SkBitmap* bitmap,
1374 const HashAndEncode* hashAndEncode) {
1375
1376 // Determine whether or not the OldestSupportedSkpVersion extra_config is provided.
1377 bool isOldestSupportedSkp = false;
1378 for (int i = 1; i < FLAGS_key.size(); i += 2) {
1379 if (0 == strcmp(FLAGS_key[i-1], "extra_config") &&
1380 0 == strcmp(FLAGS_key[i], "OldestSupportedSkpVersion")) {
1381 isOldestSupportedSkp = true;
1382 break;
1383 }
1384 }
1385
1387 result.name = task.src->name();
1388 result.config = task.sink.tag;
1389 result.sourceType = task.src.tag;
1390 // If the OldestSupportedSkpVersion extra_config is provided, override the "skp"
1391 // source_type with "old-skp". This has the effect of grouping the oldest supported SKPs in
1392 // a separate Gold corpus for easier triaging.
1393 if (isOldestSupportedSkp && 0 == strcmp(result.sourceType.c_str(), "skp")) {
1394 result.sourceType = "old-skp";
1395 }
1396 result.sourceOptions = task.src.options;
1397 result.ext = ext;
1398 result.md5 = md5;
1399 if (bitmap) {
1400 result.gamut = identify_gamut (bitmap->colorSpace());
1401 result.transferFn = identify_transfer_fn (bitmap->colorSpace());
1402 result.colorType = ToolUtils::colortype_name (bitmap->colorType());
1403 result.alphaType = ToolUtils::alphatype_name (bitmap->alphaType());
1404 result.colorDepth = ToolUtils::colortype_depth(bitmap->colorType());
1405 }
1406 JsonWriter::AddBitmapResult(result);
1407
1408 // If an MD5 is uninteresting, we want it noted in the JSON file,
1409 // but don't want to dump it out as a .png (or whatever ext is).
1410 if (gUninterestingHashes->contains(md5)) {
1411 return;
1412 }
1413
1414 const char* dir = FLAGS_writePath[0];
1415 SkString resources = GetResourcePath();
1416 if (0 == strcmp(dir, "@")) { // Needed for iOS.
1417 dir = resources.c_str();
1418 }
1419 sk_mkdir(dir);
1420
1421 SkString path;
1422 if (FLAGS_nameByHash) {
1423 path = SkOSPath::Join(dir, result.md5.c_str());
1424 path.append(".");
1425 path.append(ext);
1426 if (sk_exists(path.c_str())) {
1427 return; // Content-addressed. If it exists already, we're done.
1428 }
1429 } else {
1430 path = SkOSPath::Join(dir, task.sink.tag.c_str());
1431 sk_mkdir(path.c_str());
1432 path = SkOSPath::Join(path.c_str(), task.src.tag.c_str());
1433 sk_mkdir(path.c_str());
1434 if (0 != strcmp(task.src.options.c_str(), "")) {
1436 sk_mkdir(path.c_str());
1437 }
1438 path = SkOSPath::Join(path.c_str(), task.src->name().c_str());
1439 path.append(".");
1440 path.append(ext);
1441 }
1442
1444 if (!file.isValid()) {
1445 fail(SkStringPrintf("Can't open %s for writing.\n", path.c_str()));
1446 return;
1447 }
1448 if (bitmap) {
1449 SkASSERT(hashAndEncode);
1450 if (!hashAndEncode->encodePNG(&file,
1451 result.md5.c_str(),
1452 FLAGS_key,
1453 FLAGS_properties)) {
1454 fail(SkStringPrintf("Can't encode PNG to %s.\n", path.c_str()));
1455 return;
1456 }
1457 } else {
1458 if (!file.writeStream(data, len)) {
1459 fail(SkStringPrintf("Can't write to %s.\n", path.c_str()));
1460 return;
1461 }
1462 }
1463 }
1464};
1465
1466/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1467
1468// Unit tests don't fit so well into the Src/Sink model, so we give them special treatment.
1469
1474
1475static void gather_tests() {
1476 if (!FLAGS_src.contains("tests")) {
1477 return;
1478 }
1480 if (!in_shard()) {
1481 continue;
1482 }
1483 if (CommandLineFlags::ShouldSkip(FLAGS_match, test.fName)) {
1484 continue;
1485 }
1486 if (test.fTestType == TestType::kGanesh && FLAGS_gpu) {
1487 gGaneshTests->push_back(test);
1488 } else if (test.fTestType == TestType::kGraphite && FLAGS_graphite) {
1489 gGraphiteTests->push_back(test);
1490 } else if (test.fTestType == TestType::kCPU && FLAGS_cpu) {
1491 gCPUTests->push_back(test);
1492 } else if (test.fTestType == TestType::kCPUSerial && FLAGS_cpu) {
1493 gCPUSerialTests->push_back(test);
1494 }
1495 }
1496}
1497
1499 void reportFailed(const skiatest::Failure& failure) override {
1500 fail(failure.toString());
1501 }
1502 bool allowExtendedTest() const override {
1503 return FLAGS_pathOpsExtended;
1504 }
1505 bool verbose() const override { return FLAGS_veryVerbose; }
1506};
1507
1510 if (!FLAGS_dryRun && !should_skip("_", "tests", "_", test.fName)) {
1512 start("unit", "test", "", test.fName);
1513 test.cpu(&reporter);
1514 }
1515 done("unit", "test", "", test.fName);
1516}
1517
1518static void run_ganesh_test(skiatest::Test test, const GrContextOptions& grCtxOptions) {
1520 if (!FLAGS_dryRun && !should_skip("_", "tests", "_", test.fName)) {
1522 GrContextOptions options = grCtxOptions;
1523 test.modifyGrContextOptions(&options);
1524
1526 start("unit", "test", "", test.fName);
1527 test.ganesh(&reporter, options);
1528 }
1529 done("unit", "test", "", test.fName);
1530}
1531
1534 if (!FLAGS_dryRun && !should_skip("_", "tests", "_", test.fName)) {
1536 test.modifyGraphiteContextOptions(&options.fContextOptions);
1537
1539 start("unit", "test", "", test.fName);
1540 test.graphite(&reporter, options);
1541 }
1542 done("unit", "test", "", test.fName);
1543}
1544
1545/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1546
1548 return TestHarness::kDM;
1549}
1550
1551/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1552
1553int main(int argc, char** argv) {
1554#if defined(__MSVC_RUNTIME_CHECKS)
1555 _RTC_SetErrorFunc(RuntimeCheckErrorFunc);
1556#endif
1557#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_HAS_HEIF_LIBRARY)
1558 android::ProcessState::self()->startThreadPool();
1559#endif
1561
1563
1564#if !defined(SK_BUILD_FOR_GOOGLE3) && defined(SK_BUILD_FOR_IOS)
1565 cd_Documents();
1566#endif
1567 setbuf(stdout, nullptr);
1569
1571
1572 gSkForceRasterPipelineBlitter = FLAGS_forceRasterPipelineHP || FLAGS_forceRasterPipeline;
1573 gForceHighPrecisionRasterPipeline = FLAGS_forceRasterPipelineHP;
1574 gCreateProtectedContext = FLAGS_createProtected;
1575
1576 // The bots like having a verbose.log to upload, so always touch the file even if --verbose.
1577 if (!FLAGS_writePath.isEmpty()) {
1578 sk_mkdir(FLAGS_writePath[0]);
1579 gVLog = fopen(SkOSPath::Join(FLAGS_writePath[0], "verbose.log").c_str(), "w");
1580 }
1581 if (FLAGS_verbose) {
1582 gVLog = stderr;
1583 }
1584
1585 skiatest::graphite::TestOptions graphiteOptions;
1586 if (FLAGS_neverYieldToWebGPU) {
1587 graphiteOptions.fNeverYieldToWebGPU = true;
1588 }
1589
1590 GrContextOptions grCtxOptions;
1591 CommonFlags::SetCtxOptions(&grCtxOptions);
1592
1593 dump_json(); // It's handy for the bots to assume this is ~never missing.
1594
1596#if defined(SK_ENABLE_SVG)
1598#endif
1599 SkTaskGroup::Enabler enabled(FLAGS_threads);
1601
1602 if (nullptr == GetResourceAsData("images/color_wheel.png")) {
1603 info("Some resources are missing. Do you need to set --resourcePath?\n");
1604 }
1605 gather_gold();
1607
1608 if (!gather_srcs()) {
1609 return 1;
1610 }
1611 bool defaultConfigs = true;
1612 for (int i = 0; i < argc; i++) {
1613 if (strcmp(argv[i], "--config") == 0) {
1614 defaultConfigs = false;
1615 break;
1616 }
1617 }
1618 if (!gather_sinks(grCtxOptions, defaultConfigs)) {
1619 return 1;
1620 }
1621 gather_tests();
1622 int testCount = gCPUTests->size() + gCPUSerialTests->size() +
1623 gGaneshTests->size() + gGraphiteTests->size();
1624 gPending = gSrcs->size() * gSinks->size() + testCount;
1627 info("%d srcs * %d sinks + %d tests == %d tasks\n",
1628 gSrcs->size(), gSinks->size(), testCount,
1629 gPending);
1630
1631 // Kick off as much parallel work as we can, making note of any serial work we'll need to do.
1632 // However, execute all CPU-serial tests first so that they don't have races with parallel tests
1634
1635 SkTaskGroup parallel;
1637
1638 for (TaggedSink& sink : *gSinks) {
1639 for (TaggedSrc& src : *gSrcs) {
1640 if (src->veto(sink->flags()) ||
1641 should_skip(sink.tag.c_str(), src.tag.c_str(),
1642 src.options.c_str(), src->name().c_str())) {
1643 SkAutoSpinlock lock(gMutex);
1644 gPending--;
1645 continue;
1646 }
1647
1648 Task task(src, sink);
1649 if (src->serial() || sink->serial()) {
1650 serial.push_back(task);
1651 } else {
1652 parallel.add([task] { Task::Run(task); });
1653 }
1654 }
1655 }
1656 for (skiatest::Test& test : *gCPUTests) {
1657 parallel.add([test] { run_cpu_test(test); });
1658 }
1659
1660 // With the parallel work running, run serial tasks and tests here on main thread.
1661 for (Task& task : serial) { Task::Run(task); }
1662 for (skiatest::Test& test : *gGaneshTests) { run_ganesh_test(test, grCtxOptions); }
1663 for (skiatest::Test& test : *gGraphiteTests) { run_graphite_test(test, graphiteOptions); }
1664
1665 // Wait for any remaining parallel work to complete (including any spun off of serial tasks).
1666 parallel.wait();
1668
1669 // At this point we're back in single-threaded land.
1670
1671 // We'd better have run everything.
1672 SkASSERT(gPending == 0);
1673 // Make sure we've flushed all our results to disk.
1674 dump_json();
1675
1676 if (!gFailures->empty()) {
1677 info("Failures:\n");
1678 for (const SkString& fail : *gFailures) {
1679 info("\t%s\n", fail.c_str());
1680 }
1681 info("%d failures\n", gFailures->size());
1682 return 1;
1683 }
1684
1686 info("Finished!\n");
1687
1688 return 0;
1689}
AutoreleasePool pool
static SkMD5::Digest md5(const SkBitmap &bm)
Definition: CodecTest.cpp:77
const char * options
static const char defaultConfigs[]
void ParseConfigs(const CommandLineFlags::StringArray &configs, SkCommandLineConfigArray *outResult)
static FILE * gVLog
Definition: DM.cpp:197
static bool should_skip(const char *sink, const char *src, const char *srcOptions, const char *name)
Definition: DM.cpp:1142
static void push_codec_src(Path path, CodecSrc::Mode mode, CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType, float scale)
Definition: DM.cpp:523
static void gather_gold()
Definition: DM.cpp:449
static TArray< TaggedSink, kMemcpyOK > * gSinks
Definition: DM.cpp:505
static DEFINE_int(shards, 1, "We're splitting source data into this many shards.")
static void push_codec_srcs(Path path)
Definition: DM.cpp:717
static void find_culprit()
Definition: DM.cpp:319
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition: DM.cpp:263
static SkTDArray< skiatest::Test > * gGaneshTests
Definition: DM.cpp:1472
static SkSpinlock gMutex
Definition: DM.cpp:257
static void gather_uninteresting_hashes()
Definition: DM.cpp:469
static double gLastUpdate
Definition: DM.cpp:260
void gather_file_srcs(const CommandLineFlags::StringArray &flags, const char *ext, const char *src_name=nullptr)
Definition: DM.cpp:890
static THashSet< Gold, Gold::Hash > * gGold
Definition: DM.cpp:443
int main(int argc, char **argv)
Definition: DM.cpp:1553
static void add_gold(JsonWriter::BitmapResult r)
Definition: DM.cpp:445
static DEFINE_bool(nameByHash, false, "If true, write to FLAGS_writePath[0]/<hash>.png instead of " "to FLAGS_writePath[0]/<config>/<sourceType>/<sourceOptions>/<name>.png")
static void push_src(const char *tag, ImplicitString options, Src *inSrc)
Definition: DM.cpp:512
static int gTotalCounts
Definition: DM.cpp:259
static bool gather_srcs()
Definition: DM.cpp:911
static bool gather_sinks(const GrContextOptions &grCtxOptions, bool defaultConfigs)
Definition: DM.cpp:1081
static void run_ganesh_test(skiatest::Test test, const GrContextOptions &grCtxOptions)
Definition: DM.cpp:1518
static THashSet< SkString > * gUninterestingHashes
Definition: DM.cpp:467
bool gCreateProtectedContext
static void start(const char *config, const char *src, const char *srcOptions, const char *name)
Definition: DM.cpp:312
bool gForceHighPrecisionRasterPipeline
static Sink * create_via(const SkString &tag, Sink *wrapped)
Definition: DM.cpp:1056
static SkTDArray< skiatest::Test > * gCPUSerialTests
Definition: DM.cpp:1471
static constexpr char kNewline[]
Definition: DM.cpp:464
static void push_android_codec_src(Path path, CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType, int sampleSize)
Definition: DM.cpp:587
static constexpr int max_of()
Definition: DM.cpp:375
TestHarness CurrentTestHarness()
Definition: DM.cpp:1547
static void fail(const SkString &err)
Definition: DM.cpp:234
static void run_graphite_test(skiatest::Test test, skiatest::graphite::TestOptions &options)
Definition: DM.cpp:1532
static DEFINE_int_2(threads, j, -1, "Run threadsafe tests on a threadpool with this many extra threads, " "defaulting to one extra thread per core.")
static constexpr bool kMemcpyOK
Definition: DM.cpp:502
static void dump_json()
Definition: DM.cpp:250
static DEFINE_bool2(pathOpsExtended, x, false, "Run extended pathOps tests.")
static void(* previous_handler[max_of(SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTERM)+1])(int)
Definition: DM.cpp:381
static void crash_handler(int sig)
Definition: DM.cpp:383
static SkNoDestructor< TArray< Running > > gRunning
Definition: DM.cpp:261
static TArray< SkString > * gFailures
Definition: DM.cpp:232
static bool match(const char *needle, const char *haystack)
Definition: DM.cpp:1132
static bool in_shard()
Definition: DM.cpp:507
static void push_image_gen_src(Path path, ImageGenSrc::Mode mode, SkAlphaType alphaType, bool isGpu)
Definition: DM.cpp:622
static void gather_tests()
Definition: DM.cpp:1475
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static SkTaskGroup * gDefinitelyThreadSafeWork
Definition: DM.cpp:1157
static DEFINE_string2(readPath, r, "", "If set check for equality with golden results in this directory.")
bool gSkForceRasterPipelineBlitter
Definition: SkBlitter.cpp:44
static void run_cpu_test(skiatest::Test test)
Definition: DM.cpp:1508
#define VIA(t, via,...)
#define SINK(t, sink,...)
static void push_sink(const SkCommandLineConfig &config, Sink *s)
Definition: DM.cpp:952
static Sink * create_sink(const GrContextOptions &grCtxOptions, const SkCommandLineConfig *config)
Definition: DM.cpp:979
static TArray< TaggedSrc, kMemcpyOK > * gSrcs
Definition: DM.cpp:504
static void vlog(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:201
static SkTDArray< skiatest::Test > * gCPUTests
Definition: DM.cpp:1470
static SkTDArray< skiatest::Test > * gGraphiteTests
Definition: DM.cpp:1473
static void setup_crash_handler()
Definition: DM.cpp:415
static int gPending
Definition: DM.cpp:258
static DEFINE_string(src, "tests gm skp mskp lottie rive svg image colorImage", "Source types to test.")
void initializeEventTracingForTools(const char *traceFlag)
reporter
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
Definition: M44Test.cpp:18
static float next(float f)
static const size_t testCount
kUnpremul_SkAlphaType
static const uint32_t rgba[kNumPixels]
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition: Resources.cpp:42
SkString GetResourcePath(const char *resource)
Definition: Resources.cpp:23
SkAlphaType
Definition: SkAlphaType.h:26
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SK_PRINTF_LIKE(A, B)
Definition: SkAttributes.h:52
static constexpr skcms_Matrix3x3 gNarrow_toXYZD50
@ kR8_unorm_SkColorType
Definition: SkColorType.h:54
@ kBGR_101010x_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word
Definition: SkColorType.h:30
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition: SkColorType.h:23
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kRGB_101010x_SkColorType
pixel with 10 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:29
@ kSRGBA_8888_SkColorType
Definition: SkColorType.h:53
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition: SkColorType.h:35
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:25
@ kBGRA_1010102_SkColorType
10 bits for blue, green, red; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:28
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
@ kRGBA_1010102_SkColorType
10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:27
@ kRGBA_F16Norm_SkColorType
pixel with half floats in [0,1] for red, green, blue, alpha;
Definition: SkColorType.h:36
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static constexpr SkScalar SK_ScalarDefaultRasterDPI
Definition: SkDocument.h:20
static bool skip(SkStream *stream, size_t amount)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
bool sk_mkdir(const char *path)
bool sk_exists(const char *path, SkFILE_Flags=(SkFILE_Flags) 0)
bool sk_isdir(const char *path)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
bool equals(SkDrawable *a, SkDrawable *b)
void SkStrSplit(const char *str, const char *delimiters, SkStrSplitMode splitMode, TArray< SkString > *out)
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
SkThreadID SkGetThreadID()
Definition: SkThreadID.cpp:15
int64_t SkThreadID
Definition: SkThreadID.h:16
TestHarness
Definition: TestHarness.h:14
static sk_sp< GrTextureProxy > wrapped(skiatest::Reporter *reporter, GrRecordingContext *rContext, GrProxyProvider *proxyProvider, SkBackingFit fit)
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition: aaclip.cpp:27
#define N
Definition: beziers.cpp:19
static bool ShouldSkip(const SkTDArray< const char * > &strings, const char *name)
static void Parse(int argc, const char *const *argv)
bool encodePNG(SkWStream *, const char *md5, CommandLineFlags::StringArray key, CommandLineFlags::StringArray properties) const
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
size_t rowBytes() const
Definition: SkBitmap.h:238
void * getPixels() const
Definition: SkBitmap.h:283
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
static std::unique_ptr< SkCodec > MakeFromData(sk_sp< SkData >, SkSpan< const SkCodecs::Decoder > decoders, SkPngChunkReader *=nullptr)
Definition: SkCodec.cpp:241
bool toXYZD50(skcms_Matrix3x3 *toXYZD50) const
void transferFn(float gabcdef[7]) const
sk_sp< SkColorSpace > refColorSpace() const
const SkString & getTag() const
virtual const SkCommandLineConfigSvg * asConfigSvg() const
const skia_private::TArray< SkString > & getViaParts() const
virtual const SkCommandLineConfigGpu * asConfigGpu() const
virtual const SkCommandLineConfigGraphite * asConfigGraphite() const
const void * data() const
Definition: SkData.h:37
static sk_sp< SkData > MakeFromStream(SkStream *, size_t size)
Definition: SkData.cpp:208
static sk_sp< SkData > MakeFromFileName(const char path[])
Definition: SkData.cpp:148
size_t size() const
Definition: SkData.h:30
static void PurgeAllCaches()
Definition: SkGraphics.cpp:40
static OpenTypeSVGDecoderFactory SetOpenTypeSVGDecoderFactory(OpenTypeSVGDecoderFactory)
Definition: SkGraphics.cpp:96
static void Init()
Definition: SkGraphics.cpp:22
Definition: SkMD5.h:19
SK_SPI bool next(SkString *name, bool getDir=false)
static SkString Join(const char *rootPath, const char *relativePath)
Definition: SkOSPath.cpp:14
const uint64_t * addr64() const
Definition: SkPixmap.h:365
int width() const
Definition: SkPixmap.h:160
int height() const
Definition: SkPixmap.h:166
static std::unique_ptr< SkOpenTypeSVGDecoder > Make(const uint8_t *svg, size_t svgLength)
void append(const char text[])
Definition: SkString.h:203
const char * c_str() const
Definition: SkString.h:133
void add(std::function< void(void)> fn)
Definition: SkTaskGroup.cpp:16
GrDirectContext * get(ContextType type, ContextOverrides overrides=ContextOverrides::kNone)
bool empty() const
Definition: SkTArray.h:199
int size() const
Definition: SkTArray.h:421
float SkScalar
Definition: extension.cpp:12
struct MyStruct s
struct MyStruct a[10]
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
void cd_Documents(void)
Definition: ios_utils.m:12
char ** argv
Definition: library.h:9
T __attribute__((ext_vector_type(N))) V
std::array< MockImage, 3 > images
Definition: mock_vulkan.cc:41
double y
double x
void RegisterAllAvailable()
Definition: CodecUtils.h:60
bool CollectImages(const CommandLineFlags::StringArray &dir, skia_private::TArray< SkString > *output)
void SetCtxOptions(struct GrContextOptions *)
static constexpr skcms_Matrix3x3 kSRGB
Definition: SkColorSpace.h:67
static constexpr skcms_Matrix3x3 kAdobeRGB
Definition: SkColorSpace.h:77
static constexpr skcms_Matrix3x3 kXYZ
Definition: SkColorSpace.h:99
static constexpr skcms_Matrix3x3 kRec2020
Definition: SkColorSpace.h:93
static constexpr skcms_Matrix3x3 kDisplayP3
Definition: SkColorSpace.h:87
static constexpr skcms_TransferFunction kRec2020
Definition: SkColorSpace.h:54
static constexpr skcms_TransferFunction kSRGB
Definition: SkColorSpace.h:45
static constexpr skcms_TransferFunction kHLG
Definition: SkColorSpace.h:60
static constexpr skcms_TransferFunction kPQ
Definition: SkColorSpace.h:57
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< const SkImage > image
Definition: SkRecords.h:269
double GetNSecs()
Definition: SkTime.cpp:17
const char * colortype_depth(SkColorType ct)
Definition: ToolUtils.cpp:97
const char * colortype_name(SkColorType ct)
Definition: ToolUtils.cpp:65
const char * alphatype_name(SkAlphaType at)
Definition: ToolUtils.cpp:55
Definition: bitmap.py:1
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
folder
Definition: malisc.py:18
def shard(fn, arglist)
int getCurrResidentSetSizeMB()
Definition: ProcStats.cpp:92
int getMaxResidentSetSizeMB()
Definition: ProcStats.cpp:87
std::function< std::unique_ptr< skiagm::GM >()> GMFactory
Definition: gm.h:239
void SetFontTestDataDirectory()
SIN Vec< N, float > from_half(const Vec< N, uint16_t > &x)
Definition: SkVx.h:790
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
static SkString fmt(SkColor4f c)
Definition: p3.cpp:43
SkScalar w
SkScalar h
#define T
Definition: precompiler.cc:65
skcms_TFType skcms_TransferFunction_getType(const skcms_TransferFunction *tf)
Definition: skcms.cc:183
@ skcms_TFType_Invalid
Definition: skcms_public.h:55
@ skcms_TFType_HLGish
Definition: skcms_public.h:58
@ skcms_TFType_sRGBish
Definition: skcms_public.h:56
@ skcms_TFType_HLGinvish
Definition: skcms_public.h:59
@ skcms_TFType_PQish
Definition: skcms_public.h:57
const Scalar scale
bool verbose() const override
Definition: DM.cpp:1505
bool allowExtendedTest() const override
Definition: DM.cpp:1502
void reportFailed(const skiatest::Failure &failure) override
Definition: DM.cpp:1499
virtual void setColorSpace(sk_sp< SkColorSpace >)
Definition: DMSrcSink.h:120
uint32_t operator()(const Gold &g) const
Definition: DM.cpp:438
Definition: DM.cpp:425
Gold(const SkString &sink, const SkString &src, const SkString &srcOptions, const SkString &name, const SkString &md5)
Definition: DM.cpp:427
Gold()
Definition: DM.cpp:426
Definition: DM.cpp:241
void dump() const
Definition: DM.cpp:245
SkString id
Definition: DM.cpp:242
SkThreadID thread
Definition: DM.cpp:243
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
SkString tag
Definition: DM.cpp:499
SkString tag
Definition: DM.cpp:494
SkString options
Definition: DM.cpp:495
Definition: DM.cpp:1161
static SkString identify_transfer_fn(SkColorSpace *cs)
Definition: DM.cpp:1326
static void WriteToDisk(const Task &task, SkString md5, const char *ext, SkStream *data, size_t len, const SkBitmap *bitmap, const HashAndEncode *hashAndEncode)
Definition: DM.cpp:1369
const TaggedSrc & src
Definition: DM.cpp:1163
static SkString identify_gamut(SkColorSpace *cs)
Definition: DM.cpp:1300
static void Run(const Task &task)
Definition: DM.cpp:1166
Task(const TaggedSrc &src, const TaggedSink &sink)
Definition: DM.cpp:1162
const TaggedSink & sink
Definition: DM.cpp:1164
SkString toString() const
Definition: Test.cpp:41
Definition: SkVx.h:83
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
const uintptr_t id
long LONG
Definition: windows_types.h:23
#define WINAPI
unsigned long DWORD
Definition: windows_types.h:22