DM.cpp 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  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. #include "dm/DMJsonWriter.h"
  8. #include "dm/DMSrcSink.h"
  9. #include "include/codec/SkCodec.h"
  10. #include "include/core/SkBBHFactory.h"
  11. #include "include/core/SkColorPriv.h"
  12. #include "include/core/SkColorSpace.h"
  13. #include "include/core/SkData.h"
  14. #include "include/core/SkDocument.h"
  15. #include "include/core/SkFontMgr.h"
  16. #include "include/core/SkGraphics.h"
  17. #include "include/ports/SkTypeface_win.h"
  18. #include "include/private/SkChecksum.h"
  19. #include "include/private/SkHalf.h"
  20. #include "include/private/SkSpinlock.h"
  21. #include "include/private/SkTHash.h"
  22. #include "src/core/SkColorSpacePriv.h"
  23. #include "src/core/SkLeanWindows.h"
  24. #include "src/core/SkMD5.h"
  25. #include "src/core/SkOSFile.h"
  26. #include "src/core/SkTaskGroup.h"
  27. #include "src/utils/SkOSPath.h"
  28. #include "tests/Test.h"
  29. #include "tools/AutoreleasePool.h"
  30. #include "tools/HashAndEncode.h"
  31. #include "tools/ProcStats.h"
  32. #include "tools/Resources.h"
  33. #include "tools/ToolUtils.h"
  34. #include "tools/flags/CommonFlags.h"
  35. #include "tools/flags/CommonFlagsConfig.h"
  36. #include "tools/ios_utils.h"
  37. #include "tools/trace/ChromeTracingTracer.h"
  38. #include "tools/trace/EventTracingPriv.h"
  39. #include "tools/trace/SkDebugfTracer.h"
  40. #include <vector>
  41. #include <stdlib.h>
  42. #ifndef SK_BUILD_FOR_WIN
  43. #include <unistd.h>
  44. #endif
  45. #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_HAS_HEIF_LIBRARY)
  46. #include <binder/IPCThreadState.h>
  47. #endif
  48. extern bool gSkForceRasterPipelineBlitter;
  49. static DEFINE_string(src, "tests gm skp image", "Source types to test.");
  50. static DEFINE_bool(nameByHash, false,
  51. "If true, write to FLAGS_writePath[0]/<hash>.png instead of "
  52. "to FLAGS_writePath[0]/<config>/<sourceType>/<sourceOptions>/<name>.png");
  53. static DEFINE_bool2(pathOpsExtended, x, false, "Run extended pathOps tests.");
  54. static DEFINE_string(matrix, "1 0 0 1",
  55. "2x2 scale+skew matrix to apply or upright when using "
  56. "'matrix' or 'upright' in config.");
  57. static DEFINE_bool(gpu_threading, false, "Allow GPU work to run on multiple threads?");
  58. static DEFINE_string(blacklist, "",
  59. "Space-separated config/src/srcOptions/name quadruples to blacklist. "
  60. "'_' matches anything. '~' negates the match. E.g. \n"
  61. "'--blacklist gpu skp _ _' will blacklist all SKPs drawn into the gpu config.\n"
  62. "'--blacklist gpu skp _ _ 8888 gm _ aarects' will also blacklist the aarects GM on 8888.\n"
  63. "'--blacklist ~8888 svg _ svgparse_' blocks non-8888 SVGs that contain \"svgparse_\" in "
  64. "the name.");
  65. static DEFINE_string2(readPath, r, "",
  66. "If set check for equality with golden results in this directory.");
  67. DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
  68. static DEFINE_string(uninterestingHashesFile, "",
  69. "File containing a list of uninteresting hashes. If a result hashes to something in "
  70. "this list, no image is written for that result.");
  71. static DEFINE_int(shards, 1, "We're splitting source data into this many shards.");
  72. static DEFINE_int(shard, 0, "Which shard do I run?");
  73. static DEFINE_string(mskps, "", "Directory to read mskps from, or a single mskp file.");
  74. static DEFINE_bool(forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter");
  75. static DEFINE_string(bisect, "",
  76. "Pair of: SKP file to bisect, followed by an l/r bisect trail string (e.g., 'lrll'). The "
  77. "l/r trail specifies which half to keep at each step of a binary search through the SKP's "
  78. "paths. An empty string performs no bisect. Only the SkPaths are bisected; all other draws "
  79. "are thrown out. This is useful for finding a reduced repo case for path drawing bugs.");
  80. static DEFINE_bool(ignoreSigInt, false, "ignore SIGINT signals during test execution");
  81. static DEFINE_string(dont_write, "", "File extensions to skip writing to --writePath."); // See skia:6821
  82. static DEFINE_bool(checkF16, false, "Ensure that F16Norm pixels are clamped.");
  83. static DEFINE_string(colorImages, "",
  84. "List of images and/or directories to decode with color correction. "
  85. "A directory with no images is treated as a fatal error.");
  86. static DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
  87. static DEFINE_bool(cpu, true, "master switch for running CPU-bound work.");
  88. static DEFINE_bool(gpu, true, "master switch for running GPU-bound work.");
  89. static DEFINE_bool(dryRun, false,
  90. "just print the tests that would be run, without actually running them.");
  91. static DEFINE_string(images, "",
  92. "List of images and/or directories to decode. A directory with no images"
  93. " is treated as a fatal error.");
  94. static DEFINE_bool(simpleCodec, false,
  95. "Runs of a subset of the codec tests, "
  96. "with no scaling or subsetting, always using the canvas color type.");
  97. static DEFINE_string2(match, m, nullptr,
  98. "[~][^]substring[$] [...] of name to run.\n"
  99. "Multiple matches may be separated by spaces.\n"
  100. "~ causes a matching name to always be skipped\n"
  101. "^ requires the start of the name to match\n"
  102. "$ requires the end of the name to match\n"
  103. "^ and $ requires an exact match\n"
  104. "If a name does not match any list entry,\n"
  105. "it is skipped unless some list entry starts with ~");
  106. static DEFINE_bool2(quiet, q, false, "if true, don't print status updates.");
  107. static DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
  108. static DEFINE_string(skps, "skps", "Directory to read skps from.");
  109. static DEFINE_string(lotties, "lotties", "Directory to read (Bodymovin) jsons from.");
  110. static DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
  111. static DEFINE_int_2(threads, j, -1,
  112. "Run threadsafe tests on a threadpool with this many extra threads, "
  113. "defaulting to one extra thread per core.");
  114. static DEFINE_string(key, "",
  115. "Space-separated key/value pairs to add to JSON identifying this builder.");
  116. static DEFINE_string(properties, "",
  117. "Space-separated key/value pairs to add to JSON identifying this run.");
  118. #if defined(__MSVC_RUNTIME_CHECKS)
  119. #include <rtcapi.h>
  120. int RuntimeCheckErrorFunc(int errorType, const char* filename, int linenumber,
  121. const char* moduleName, const char* fmt, ...) {
  122. va_list args;
  123. va_start(args, fmt);
  124. vfprintf(stderr, fmt, args);
  125. va_end(args);
  126. SkDebugf("Line #%d\nFile: %s\nModule: %s\n",
  127. linenumber, filename ? filename : "Unknown", moduleName ? moduleName : "Unknwon");
  128. return 1;
  129. }
  130. #endif
  131. using namespace DM;
  132. using sk_gpu_test::GrContextFactory;
  133. using sk_gpu_test::GLTestContext;
  134. using sk_gpu_test::ContextInfo;
  135. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  136. static sk_sp<SkColorSpace> rec2020() {
  137. return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020);
  138. }
  139. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  140. static FILE* gVLog;
  141. template <typename... Args>
  142. static void vlog(const char* fmt, Args&&... args) {
  143. if (gVLog) {
  144. fprintf(gVLog, fmt, args...);
  145. fflush(gVLog);
  146. }
  147. }
  148. template <typename... Args>
  149. static void info(const char* fmt, Args&&... args) {
  150. vlog(fmt, args...);
  151. if (!FLAGS_quiet) {
  152. printf(fmt, args...);
  153. }
  154. }
  155. static void info(const char* fmt) {
  156. if (!FLAGS_quiet) {
  157. printf("%s", fmt); // Clang warns printf(fmt) is insecure.
  158. }
  159. }
  160. static SkTArray<SkString> gFailures;
  161. static void fail(const SkString& err) {
  162. static SkSpinlock mutex;
  163. SkAutoSpinlock lock(mutex);
  164. SkDebugf("\n\nFAILURE: %s\n\n", err.c_str());
  165. gFailures.push_back(err);
  166. }
  167. struct Running {
  168. SkString id;
  169. SkThreadID thread;
  170. void dump() const {
  171. info("\t%s\n", id.c_str());
  172. }
  173. };
  174. static void dump_json() {
  175. if (!FLAGS_writePath.isEmpty()) {
  176. JsonWriter::DumpJson(FLAGS_writePath[0], FLAGS_key, FLAGS_properties);
  177. }
  178. }
  179. // We use a spinlock to make locking this in a signal handler _somewhat_ safe.
  180. static SkSpinlock gMutex;
  181. static int gPending;
  182. static SkTArray<Running> gRunning;
  183. static void done(const char* config, const char* src, const char* srcOptions, const char* name) {
  184. SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name);
  185. vlog("done %s\n", id.c_str());
  186. int pending;
  187. {
  188. SkAutoSpinlock lock(gMutex);
  189. for (int i = 0; i < gRunning.count(); i++) {
  190. if (gRunning[i].id == id) {
  191. gRunning.removeShuffle(i);
  192. break;
  193. }
  194. }
  195. pending = --gPending;
  196. }
  197. // We write out dm.json file and print out a progress update every once in a while.
  198. // Notice this also handles the final dm.json and progress update when pending == 0.
  199. if (pending % 500 == 0) {
  200. dump_json();
  201. int curr = sk_tools::getCurrResidentSetSizeMB(),
  202. peak = sk_tools::getMaxResidentSetSizeMB();
  203. SkAutoSpinlock lock(gMutex);
  204. info("\n%dMB RAM, %dMB peak, %d queued, %d active:\n",
  205. curr, peak, gPending - gRunning.count(), gRunning.count());
  206. for (auto& task : gRunning) {
  207. task.dump();
  208. }
  209. }
  210. }
  211. static void start(const char* config, const char* src, const char* srcOptions, const char* name) {
  212. SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name);
  213. vlog("start %s\n", id.c_str());
  214. SkAutoSpinlock lock(gMutex);
  215. gRunning.push_back({id,SkGetThreadID()});
  216. }
  217. static void find_culprit() {
  218. // Assumes gMutex is locked.
  219. SkThreadID thisThread = SkGetThreadID();
  220. for (auto& task : gRunning) {
  221. if (task.thread == thisThread) {
  222. info("Likely culprit:\n");
  223. task.dump();
  224. }
  225. }
  226. }
  227. #if defined(SK_BUILD_FOR_WIN)
  228. static LONG WINAPI crash_handler(EXCEPTION_POINTERS* e) {
  229. static const struct {
  230. const char* name;
  231. DWORD code;
  232. } kExceptions[] = {
  233. #define _(E) {#E, E}
  234. _(EXCEPTION_ACCESS_VIOLATION),
  235. _(EXCEPTION_BREAKPOINT),
  236. _(EXCEPTION_INT_DIVIDE_BY_ZERO),
  237. _(EXCEPTION_STACK_OVERFLOW),
  238. // TODO: more?
  239. #undef _
  240. };
  241. SkAutoSpinlock lock(gMutex);
  242. const DWORD code = e->ExceptionRecord->ExceptionCode;
  243. info("\nCaught exception %u", code);
  244. for (const auto& exception : kExceptions) {
  245. if (exception.code == code) {
  246. info(" %s", exception.name);
  247. }
  248. }
  249. info(", was running:\n");
  250. for (auto& task : gRunning) {
  251. task.dump();
  252. }
  253. find_culprit();
  254. fflush(stdout);
  255. // Execute default exception handler... hopefully, exit.
  256. return EXCEPTION_EXECUTE_HANDLER;
  257. }
  258. static void setup_crash_handler() {
  259. SetUnhandledExceptionFilter(crash_handler);
  260. }
  261. #else
  262. #include <signal.h>
  263. #if !defined(SK_BUILD_FOR_ANDROID)
  264. #include <execinfo.h>
  265. #endif
  266. static constexpr int max_of() { return 0; }
  267. template <typename... Rest>
  268. static constexpr int max_of(int x, Rest... rest) {
  269. return x > max_of(rest...) ? x : max_of(rest...);
  270. }
  271. static void (*previous_handler[max_of(SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGSEGV,SIGTERM)+1])(int);
  272. static void crash_handler(int sig) {
  273. SkAutoSpinlock lock(gMutex);
  274. info("\nCaught signal %d [%s] (%dMB RAM, peak %dMB), was running:\n",
  275. sig, strsignal(sig),
  276. sk_tools::getCurrResidentSetSizeMB(), sk_tools::getMaxResidentSetSizeMB());
  277. for (auto& task : gRunning) {
  278. task.dump();
  279. }
  280. find_culprit();
  281. #if !defined(SK_BUILD_FOR_ANDROID)
  282. void* stack[64];
  283. int count = backtrace(stack, SK_ARRAY_COUNT(stack));
  284. char** symbols = backtrace_symbols(stack, count);
  285. info("\nStack trace:\n");
  286. for (int i = 0; i < count; i++) {
  287. info(" %s\n", symbols[i]);
  288. }
  289. #endif
  290. fflush(stdout);
  291. if (sig == SIGINT && FLAGS_ignoreSigInt) {
  292. info("Ignoring signal %d because of --ignoreSigInt.\n"
  293. "This is probably a sign the bot is overloaded with work.\n", sig);
  294. } else {
  295. signal(sig, previous_handler[sig]);
  296. raise(sig);
  297. }
  298. }
  299. static void setup_crash_handler() {
  300. const int kSignals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM };
  301. for (int sig : kSignals) {
  302. previous_handler[sig] = signal(sig, crash_handler);
  303. }
  304. }
  305. #endif
  306. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  307. struct Gold : public SkString {
  308. Gold() : SkString("") {}
  309. Gold(const SkString& sink, const SkString& src,
  310. const SkString& srcOptions, const SkString& name,
  311. const SkString& md5)
  312. : SkString("") {
  313. this->append(sink);
  314. this->append(src);
  315. this->append(srcOptions);
  316. this->append(name);
  317. this->append(md5);
  318. }
  319. struct Hash {
  320. uint32_t operator()(const Gold& g) const {
  321. return SkGoodHash()((const SkString&)g);
  322. }
  323. };
  324. };
  325. static SkTHashSet<Gold, Gold::Hash> gGold;
  326. static void add_gold(JsonWriter::BitmapResult r) {
  327. gGold.add(Gold(r.config, r.sourceType, r.sourceOptions, r.name, r.md5));
  328. }
  329. static void gather_gold() {
  330. if (!FLAGS_readPath.isEmpty()) {
  331. SkString path(FLAGS_readPath[0]);
  332. path.append("/dm.json");
  333. if (!JsonWriter::ReadJson(path.c_str(), add_gold)) {
  334. fail(SkStringPrintf("Couldn't read %s for golden results.", path.c_str()));
  335. }
  336. }
  337. }
  338. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  339. #if defined(SK_BUILD_FOR_WIN)
  340. static const char* kNewline = "\r\n";
  341. #else
  342. static const char* kNewline = "\n";
  343. #endif
  344. static SkTHashSet<SkString> gUninterestingHashes;
  345. static void gather_uninteresting_hashes() {
  346. if (!FLAGS_uninterestingHashesFile.isEmpty()) {
  347. sk_sp<SkData> data(SkData::MakeFromFileName(FLAGS_uninterestingHashesFile[0]));
  348. if (!data) {
  349. info("WARNING: unable to read uninteresting hashes from %s\n",
  350. FLAGS_uninterestingHashesFile[0]);
  351. return;
  352. }
  353. // Copy to a string to make sure SkStrSplit has a terminating \0 to find.
  354. SkString contents((const char*)data->data(), data->size());
  355. SkTArray<SkString> hashes;
  356. SkStrSplit(contents.c_str(), kNewline, &hashes);
  357. for (const SkString& hash : hashes) {
  358. gUninterestingHashes.add(hash);
  359. }
  360. info("FYI: loaded %d distinct uninteresting hashes from %d lines\n",
  361. gUninterestingHashes.count(), hashes.count());
  362. }
  363. }
  364. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  365. struct TaggedSrc : public std::unique_ptr<Src> {
  366. SkString tag;
  367. SkString options;
  368. };
  369. struct TaggedSink : public std::unique_ptr<Sink> {
  370. SkString tag;
  371. };
  372. static const bool kMemcpyOK = true;
  373. static SkTArray<TaggedSrc, kMemcpyOK> gSrcs;
  374. static SkTArray<TaggedSink, kMemcpyOK> gSinks;
  375. static bool in_shard() {
  376. static int N = 0;
  377. return N++ % FLAGS_shards == FLAGS_shard;
  378. }
  379. static void push_src(const char* tag, ImplicitString options, Src* s) {
  380. std::unique_ptr<Src> src(s);
  381. if (in_shard() && FLAGS_src.contains(tag) &&
  382. !CommandLineFlags::ShouldSkip(FLAGS_match, src->name().c_str())) {
  383. TaggedSrc& s = gSrcs.push_back();
  384. s.reset(src.release());
  385. s.tag = tag;
  386. s.options = options;
  387. }
  388. }
  389. static void push_codec_src(Path path, CodecSrc::Mode mode, CodecSrc::DstColorType dstColorType,
  390. SkAlphaType dstAlphaType, float scale) {
  391. if (FLAGS_simpleCodec) {
  392. const bool simple = CodecSrc::kCodec_Mode == mode || CodecSrc::kAnimated_Mode == mode;
  393. if (!simple || dstColorType != CodecSrc::kGetFromCanvas_DstColorType || scale != 1.0f) {
  394. // Only decode in the simple case.
  395. return;
  396. }
  397. }
  398. SkString folder;
  399. switch (mode) {
  400. case CodecSrc::kCodec_Mode:
  401. folder.append("codec");
  402. break;
  403. case CodecSrc::kCodecZeroInit_Mode:
  404. folder.append("codec_zero_init");
  405. break;
  406. case CodecSrc::kScanline_Mode:
  407. folder.append("scanline");
  408. break;
  409. case CodecSrc::kStripe_Mode:
  410. folder.append("stripe");
  411. break;
  412. case CodecSrc::kCroppedScanline_Mode:
  413. folder.append("crop");
  414. break;
  415. case CodecSrc::kSubset_Mode:
  416. folder.append("codec_subset");
  417. break;
  418. case CodecSrc::kAnimated_Mode:
  419. folder.append("codec_animated");
  420. break;
  421. }
  422. switch (dstColorType) {
  423. case CodecSrc::kGrayscale_Always_DstColorType:
  424. folder.append("_kGray8");
  425. break;
  426. case CodecSrc::kNonNative8888_Always_DstColorType:
  427. folder.append("_kNonNative");
  428. break;
  429. default:
  430. break;
  431. }
  432. switch (dstAlphaType) {
  433. case kPremul_SkAlphaType:
  434. folder.append("_premul");
  435. break;
  436. case kUnpremul_SkAlphaType:
  437. folder.append("_unpremul");
  438. break;
  439. default:
  440. break;
  441. }
  442. if (1.0f != scale) {
  443. folder.appendf("_%.3f", scale);
  444. }
  445. CodecSrc* src = new CodecSrc(path, mode, dstColorType, dstAlphaType, scale);
  446. push_src("image", folder, src);
  447. }
  448. static void push_android_codec_src(Path path, CodecSrc::DstColorType dstColorType,
  449. SkAlphaType dstAlphaType, int sampleSize) {
  450. SkString folder;
  451. folder.append("scaled_codec");
  452. switch (dstColorType) {
  453. case CodecSrc::kGrayscale_Always_DstColorType:
  454. folder.append("_kGray8");
  455. break;
  456. case CodecSrc::kNonNative8888_Always_DstColorType:
  457. folder.append("_kNonNative");
  458. break;
  459. default:
  460. break;
  461. }
  462. switch (dstAlphaType) {
  463. case kPremul_SkAlphaType:
  464. folder.append("_premul");
  465. break;
  466. case kUnpremul_SkAlphaType:
  467. folder.append("_unpremul");
  468. break;
  469. default:
  470. break;
  471. }
  472. if (1 != sampleSize) {
  473. folder.appendf("_%.3f", 1.0f / (float) sampleSize);
  474. }
  475. AndroidCodecSrc* src = new AndroidCodecSrc(path, dstColorType, dstAlphaType, sampleSize);
  476. push_src("image", folder, src);
  477. }
  478. static void push_image_gen_src(Path path, ImageGenSrc::Mode mode, SkAlphaType alphaType, bool isGpu)
  479. {
  480. SkString folder;
  481. switch (mode) {
  482. case ImageGenSrc::kCodec_Mode:
  483. folder.append("gen_codec");
  484. break;
  485. case ImageGenSrc::kPlatform_Mode:
  486. folder.append("gen_platform");
  487. break;
  488. }
  489. if (isGpu) {
  490. folder.append("_gpu");
  491. } else {
  492. switch (alphaType) {
  493. case kOpaque_SkAlphaType:
  494. folder.append("_opaque");
  495. break;
  496. case kPremul_SkAlphaType:
  497. folder.append("_premul");
  498. break;
  499. case kUnpremul_SkAlphaType:
  500. folder.append("_unpremul");
  501. break;
  502. default:
  503. break;
  504. }
  505. }
  506. ImageGenSrc* src = new ImageGenSrc(path, mode, alphaType, isGpu);
  507. push_src("image", folder, src);
  508. }
  509. static void push_brd_src(Path path, CodecSrc::DstColorType dstColorType, BRDSrc::Mode mode,
  510. uint32_t sampleSize) {
  511. SkString folder("brd_android_codec");
  512. switch (mode) {
  513. case BRDSrc::kFullImage_Mode:
  514. break;
  515. case BRDSrc::kDivisor_Mode:
  516. folder.append("_divisor");
  517. break;
  518. default:
  519. SkASSERT(false);
  520. return;
  521. }
  522. switch (dstColorType) {
  523. case CodecSrc::kGetFromCanvas_DstColorType:
  524. break;
  525. case CodecSrc::kGrayscale_Always_DstColorType:
  526. folder.append("_kGray");
  527. break;
  528. default:
  529. SkASSERT(false);
  530. return;
  531. }
  532. if (1 != sampleSize) {
  533. folder.appendf("_%.3f", 1.0f / (float) sampleSize);
  534. }
  535. BRDSrc* src = new BRDSrc(path, mode, dstColorType, sampleSize);
  536. push_src("image", folder, src);
  537. }
  538. static void push_brd_srcs(Path path, bool gray) {
  539. if (gray) {
  540. // Only run grayscale to one sampleSize and Mode. Though interesting
  541. // to test grayscale, it should not reveal anything across various
  542. // sampleSizes and Modes
  543. // Arbitrarily choose Mode and sampleSize.
  544. push_brd_src(path, CodecSrc::kGrayscale_Always_DstColorType,
  545. BRDSrc::kFullImage_Mode, 2);
  546. }
  547. // Test on a variety of sampleSizes, making sure to include:
  548. // - 2, 4, and 8, which are natively supported by jpeg
  549. // - multiples of 2 which are not divisible by 4 (analogous for 4)
  550. // - larger powers of two, since BRD clients generally use powers of 2
  551. // We will only produce output for the larger sizes on large images.
  552. const uint32_t sampleSizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32, 64 };
  553. const BRDSrc::Mode modes[] = { BRDSrc::kFullImage_Mode, BRDSrc::kDivisor_Mode, };
  554. for (uint32_t sampleSize : sampleSizes) {
  555. for (BRDSrc::Mode mode : modes) {
  556. push_brd_src(path, CodecSrc::kGetFromCanvas_DstColorType, mode, sampleSize);
  557. }
  558. }
  559. }
  560. static void push_codec_srcs(Path path) {
  561. sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
  562. if (!encoded) {
  563. info("Couldn't read %s.", path.c_str());
  564. return;
  565. }
  566. std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(encoded);
  567. if (nullptr == codec.get()) {
  568. info("Couldn't create codec for %s.", path.c_str());
  569. return;
  570. }
  571. // native scaling is only supported by WEBP and JPEG
  572. bool supportsNativeScaling = false;
  573. SkTArray<CodecSrc::Mode> nativeModes;
  574. nativeModes.push_back(CodecSrc::kCodec_Mode);
  575. nativeModes.push_back(CodecSrc::kCodecZeroInit_Mode);
  576. switch (codec->getEncodedFormat()) {
  577. case SkEncodedImageFormat::kJPEG:
  578. nativeModes.push_back(CodecSrc::kScanline_Mode);
  579. nativeModes.push_back(CodecSrc::kStripe_Mode);
  580. nativeModes.push_back(CodecSrc::kCroppedScanline_Mode);
  581. supportsNativeScaling = true;
  582. break;
  583. case SkEncodedImageFormat::kWEBP:
  584. nativeModes.push_back(CodecSrc::kSubset_Mode);
  585. supportsNativeScaling = true;
  586. break;
  587. case SkEncodedImageFormat::kDNG:
  588. break;
  589. default:
  590. nativeModes.push_back(CodecSrc::kScanline_Mode);
  591. break;
  592. }
  593. SkTArray<CodecSrc::DstColorType> colorTypes;
  594. colorTypes.push_back(CodecSrc::kGetFromCanvas_DstColorType);
  595. colorTypes.push_back(CodecSrc::kNonNative8888_Always_DstColorType);
  596. switch (codec->getInfo().colorType()) {
  597. case kGray_8_SkColorType:
  598. colorTypes.push_back(CodecSrc::kGrayscale_Always_DstColorType);
  599. break;
  600. default:
  601. break;
  602. }
  603. SkTArray<SkAlphaType> alphaModes;
  604. alphaModes.push_back(kPremul_SkAlphaType);
  605. if (codec->getInfo().alphaType() != kOpaque_SkAlphaType) {
  606. alphaModes.push_back(kUnpremul_SkAlphaType);
  607. }
  608. for (CodecSrc::Mode mode : nativeModes) {
  609. for (CodecSrc::DstColorType colorType : colorTypes) {
  610. for (SkAlphaType alphaType : alphaModes) {
  611. // Only test kCroppedScanline_Mode when the alpha type is premul. The test is
  612. // slow and won't be interestingly different with different alpha types.
  613. if (CodecSrc::kCroppedScanline_Mode == mode &&
  614. kPremul_SkAlphaType != alphaType) {
  615. continue;
  616. }
  617. push_codec_src(path, mode, colorType, alphaType, 1.0f);
  618. // Skip kNonNative on different native scales. It won't be interestingly
  619. // different.
  620. if (supportsNativeScaling &&
  621. CodecSrc::kNonNative8888_Always_DstColorType == colorType) {
  622. // Native Scales
  623. // SkJpegCodec natively supports scaling to the following:
  624. for (auto scale : { 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.750f, 0.875f }) {
  625. push_codec_src(path, mode, colorType, alphaType, scale);
  626. }
  627. }
  628. }
  629. }
  630. }
  631. {
  632. std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
  633. if (frameInfos.size() > 1) {
  634. for (auto dstCT : { CodecSrc::kNonNative8888_Always_DstColorType,
  635. CodecSrc::kGetFromCanvas_DstColorType }) {
  636. for (auto at : { kUnpremul_SkAlphaType, kPremul_SkAlphaType }) {
  637. push_codec_src(path, CodecSrc::kAnimated_Mode, dstCT, at, 1.0f);
  638. }
  639. }
  640. }
  641. }
  642. if (FLAGS_simpleCodec) {
  643. return;
  644. }
  645. const int sampleSizes[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
  646. for (int sampleSize : sampleSizes) {
  647. for (CodecSrc::DstColorType colorType : colorTypes) {
  648. for (SkAlphaType alphaType : alphaModes) {
  649. // We can exercise all of the kNonNative support code in the swizzler with just a
  650. // few sample sizes. Skip the rest.
  651. if (CodecSrc::kNonNative8888_Always_DstColorType == colorType && sampleSize > 3) {
  652. continue;
  653. }
  654. push_android_codec_src(path, colorType, alphaType, sampleSize);
  655. }
  656. }
  657. }
  658. const char* ext = strrchr(path.c_str(), '.');
  659. if (ext) {
  660. ext++;
  661. static const char* const rawExts[] = {
  662. "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
  663. "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
  664. };
  665. for (const char* rawExt : rawExts) {
  666. if (0 == strcmp(rawExt, ext)) {
  667. // RAW is not supported by image generator (skbug.com/5079) or BRD.
  668. return;
  669. }
  670. }
  671. static const char* const brdExts[] = {
  672. "jpg", "jpeg", "png", "webp",
  673. "JPG", "JPEG", "PNG", "WEBP",
  674. };
  675. for (const char* brdExt : brdExts) {
  676. if (0 == strcmp(brdExt, ext)) {
  677. bool gray = codec->getInfo().colorType() == kGray_8_SkColorType;
  678. push_brd_srcs(path, gray);
  679. break;
  680. }
  681. }
  682. }
  683. // Push image generator GPU test.
  684. push_image_gen_src(path, ImageGenSrc::kCodec_Mode, codec->getInfo().alphaType(), true);
  685. // Push image generator CPU tests.
  686. for (SkAlphaType alphaType : alphaModes) {
  687. push_image_gen_src(path, ImageGenSrc::kCodec_Mode, alphaType, false);
  688. #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
  689. if (SkEncodedImageFormat::kWEBP != codec->getEncodedFormat() &&
  690. SkEncodedImageFormat::kWBMP != codec->getEncodedFormat() &&
  691. kUnpremul_SkAlphaType != alphaType)
  692. {
  693. push_image_gen_src(path, ImageGenSrc::kPlatform_Mode, alphaType, false);
  694. }
  695. #elif defined(SK_BUILD_FOR_WIN)
  696. if (SkEncodedImageFormat::kWEBP != codec->getEncodedFormat() &&
  697. SkEncodedImageFormat::kWBMP != codec->getEncodedFormat())
  698. {
  699. push_image_gen_src(path, ImageGenSrc::kPlatform_Mode, alphaType, false);
  700. }
  701. #endif
  702. }
  703. }
  704. template <typename T>
  705. void gather_file_srcs(const CommandLineFlags::StringArray& flags,
  706. const char* ext,
  707. const char* src_name = nullptr) {
  708. if (!src_name) {
  709. // With the exception of Lottie files, the source name is the extension.
  710. src_name = ext;
  711. }
  712. for (int i = 0; i < flags.count(); i++) {
  713. const char* path = flags[i];
  714. if (sk_isdir(path)) {
  715. SkOSFile::Iter it(path, ext);
  716. for (SkString file; it.next(&file); ) {
  717. push_src(src_name, "", new T(SkOSPath::Join(path, file.c_str())));
  718. }
  719. } else {
  720. push_src(src_name, "", new T(path));
  721. }
  722. }
  723. }
  724. static bool gather_srcs() {
  725. for (skiagm::GMFactory f : skiagm::GMRegistry::Range()) {
  726. push_src("gm", "", new GMSrc(f));
  727. }
  728. gather_file_srcs<SKPSrc>(FLAGS_skps, "skp");
  729. gather_file_srcs<MSKPSrc>(FLAGS_mskps, "mskp");
  730. #if defined(SK_ENABLE_SKOTTIE)
  731. gather_file_srcs<SkottieSrc>(FLAGS_lotties, "json", "lottie");
  732. #endif
  733. #if defined(SK_XML)
  734. gather_file_srcs<SVGSrc>(FLAGS_svgs, "svg");
  735. #endif
  736. if (!FLAGS_bisect.isEmpty()) {
  737. // An empty l/r trail string will draw all the paths.
  738. push_src("bisect", "",
  739. new BisectSrc(FLAGS_bisect[0], FLAGS_bisect.count() > 1 ? FLAGS_bisect[1] : ""));
  740. }
  741. SkTArray<SkString> images;
  742. if (!CollectImages(FLAGS_images, &images)) {
  743. return false;
  744. }
  745. for (auto image : images) {
  746. push_codec_srcs(image);
  747. }
  748. SkTArray<SkString> colorImages;
  749. if (!CollectImages(FLAGS_colorImages, &colorImages)) {
  750. return false;
  751. }
  752. for (auto colorImage : colorImages) {
  753. push_src("colorImage", "decode_native", new ColorCodecSrc(colorImage, false));
  754. push_src("colorImage", "decode_to_dst", new ColorCodecSrc(colorImage, true));
  755. }
  756. return true;
  757. }
  758. static void push_sink(const SkCommandLineConfig& config, Sink* s) {
  759. std::unique_ptr<Sink> sink(s);
  760. // Try a simple Src as a canary. If it fails, skip this sink.
  761. struct : public Src {
  762. Error draw(SkCanvas* c) const override {
  763. c->drawRect(SkRect::MakeWH(1,1), SkPaint());
  764. return "";
  765. }
  766. SkISize size() const override { return SkISize::Make(16, 16); }
  767. Name name() const override { return "justOneRect"; }
  768. } justOneRect;
  769. SkBitmap bitmap;
  770. SkDynamicMemoryWStream stream;
  771. SkString log;
  772. Error err = sink->draw(justOneRect, &bitmap, &stream, &log);
  773. if (err.isFatal()) {
  774. info("Could not run %s: %s\n", config.getTag().c_str(), err.c_str());
  775. exit(1);
  776. }
  777. TaggedSink& ts = gSinks.push_back();
  778. ts.reset(sink.release());
  779. ts.tag = config.getTag();
  780. }
  781. static sk_sp<SkColorSpace> rgb_to_gbr() {
  782. return SkColorSpace::MakeSRGB()->makeColorSpin();
  783. }
  784. static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLineConfig* config) {
  785. if (FLAGS_gpu) {
  786. if (const SkCommandLineConfigGpu* gpuConfig = config->asConfigGpu()) {
  787. GrContextFactory::ContextType contextType = gpuConfig->getContextType();
  788. GrContextFactory::ContextOverrides contextOverrides = gpuConfig->getContextOverrides();
  789. GrContextFactory testFactory(grCtxOptions);
  790. if (!testFactory.get(contextType, contextOverrides)) {
  791. info("WARNING: can not create GPU context for config '%s'. "
  792. "GM tests will be skipped.\n", gpuConfig->getTag().c_str());
  793. return nullptr;
  794. }
  795. if (gpuConfig->getTestThreading()) {
  796. SkASSERT(!gpuConfig->getTestPersistentCache());
  797. return new GPUThreadTestingSink(
  798. contextType, contextOverrides, gpuConfig->getSurfType(),
  799. gpuConfig->getSamples(), gpuConfig->getUseDIText(),
  800. gpuConfig->getColorType(), gpuConfig->getAlphaType(),
  801. sk_ref_sp(gpuConfig->getColorSpace()), FLAGS_gpu_threading, grCtxOptions);
  802. } else if (gpuConfig->getTestPersistentCache()) {
  803. return new GPUPersistentCacheTestingSink(
  804. contextType, contextOverrides, gpuConfig->getSurfType(),
  805. gpuConfig->getSamples(), gpuConfig->getUseDIText(),
  806. gpuConfig->getColorType(), gpuConfig->getAlphaType(),
  807. sk_ref_sp(gpuConfig->getColorSpace()), FLAGS_gpu_threading, grCtxOptions,
  808. gpuConfig->getTestPersistentCache());
  809. } else {
  810. return new GPUSink(contextType, contextOverrides, gpuConfig->getSurfType(),
  811. gpuConfig->getSamples(), gpuConfig->getUseDIText(),
  812. gpuConfig->getColorType(), gpuConfig->getAlphaType(),
  813. sk_ref_sp(gpuConfig->getColorSpace()), FLAGS_gpu_threading,
  814. grCtxOptions);
  815. }
  816. }
  817. }
  818. if (const SkCommandLineConfigSvg* svgConfig = config->asConfigSvg()) {
  819. int pageIndex = svgConfig->getPageIndex();
  820. return new SVGSink(pageIndex);
  821. }
  822. #define SINK(t, sink, ...) if (config->getBackend().equals(t)) return new sink(__VA_ARGS__)
  823. if (FLAGS_cpu) {
  824. SINK("g8", RasterSink, kGray_8_SkColorType);
  825. SINK("565", RasterSink, kRGB_565_SkColorType);
  826. SINK("4444", RasterSink, kARGB_4444_SkColorType);
  827. SINK("8888", RasterSink, kN32_SkColorType);
  828. SINK("rgba", RasterSink, kRGBA_8888_SkColorType);
  829. SINK("bgra", RasterSink, kBGRA_8888_SkColorType);
  830. SINK("rgbx", RasterSink, kRGB_888x_SkColorType);
  831. SINK("1010102", RasterSink, kRGBA_1010102_SkColorType);
  832. SINK("101010x", RasterSink, kRGB_101010x_SkColorType);
  833. SINK("pdf", PDFSink, false, SK_ScalarDefaultRasterDPI);
  834. SINK("skp", SKPSink);
  835. SINK("svg", SVGSink);
  836. SINK("null", NullSink);
  837. SINK("xps", XPSSink);
  838. SINK("pdfa", PDFSink, true, SK_ScalarDefaultRasterDPI);
  839. SINK("pdf300", PDFSink, false, 300);
  840. SINK("jsdebug", DebugSink);
  841. // Configs relevant to color management testing (and 8888 for reference).
  842. // 'narrow' has a gamut narrower than sRGB, and different transfer function.
  843. auto narrow = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gNarrow_toXYZD50),
  844. srgb = SkColorSpace::MakeSRGB(),
  845. srgbLinear = SkColorSpace::MakeSRGBLinear(),
  846. p3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
  847. SINK( "f16", RasterSink, kRGBA_F16_SkColorType, srgbLinear);
  848. SINK( "srgb", RasterSink, kRGBA_8888_SkColorType, srgb );
  849. SINK( "esrgb", RasterSink, kRGBA_F16_SkColorType, srgb );
  850. SINK( "esgbr", RasterSink, kRGBA_F16_SkColorType, rgb_to_gbr());
  851. SINK( "narrow", RasterSink, kRGBA_8888_SkColorType, narrow );
  852. SINK( "enarrow", RasterSink, kRGBA_F16_SkColorType, narrow );
  853. SINK( "p3", RasterSink, kRGBA_8888_SkColorType, p3 );
  854. SINK( "ep3", RasterSink, kRGBA_F16_SkColorType, p3 );
  855. SINK( "rec2020", RasterSink, kRGBA_8888_SkColorType, rec2020() );
  856. SINK("erec2020", RasterSink, kRGBA_F16_SkColorType, rec2020() );
  857. SINK("f16norm", RasterSink, kRGBA_F16Norm_SkColorType, srgb);
  858. SINK( "f32", RasterSink, kRGBA_F32_SkColorType, srgbLinear);
  859. }
  860. #undef SINK
  861. return nullptr;
  862. }
  863. static Sink* create_via(const SkString& tag, Sink* wrapped) {
  864. #define VIA(t, via, ...) if (tag.equals(t)) return new via(__VA_ARGS__)
  865. #ifdef TEST_VIA_SVG
  866. VIA("svg", ViaSVG, wrapped);
  867. #endif
  868. VIA("serialize", ViaSerialization, wrapped);
  869. VIA("pic", ViaPicture, wrapped);
  870. VIA("tiles", ViaTiles, 256, 256, nullptr, wrapped);
  871. VIA("tiles_rt", ViaTiles, 256, 256, new SkRTreeFactory, wrapped);
  872. VIA("ddl", ViaDDL, 1, 3, wrapped);
  873. VIA("ddl2", ViaDDL, 2, 3, wrapped);
  874. if (FLAGS_matrix.count() == 4) {
  875. SkMatrix m;
  876. m.reset();
  877. m.setScaleX((SkScalar)atof(FLAGS_matrix[0]));
  878. m.setSkewX ((SkScalar)atof(FLAGS_matrix[1]));
  879. m.setSkewY ((SkScalar)atof(FLAGS_matrix[2]));
  880. m.setScaleY((SkScalar)atof(FLAGS_matrix[3]));
  881. VIA("matrix", ViaMatrix, m, wrapped);
  882. VIA("upright", ViaUpright, m, wrapped);
  883. }
  884. #undef VIA
  885. return nullptr;
  886. }
  887. static bool gather_sinks(const GrContextOptions& grCtxOptions, bool defaultConfigs) {
  888. SkCommandLineConfigArray configs;
  889. ParseConfigs(FLAGS_config, &configs);
  890. AutoreleasePool pool;
  891. for (int i = 0; i < configs.count(); i++) {
  892. const SkCommandLineConfig& config = *configs[i];
  893. Sink* sink = create_sink(grCtxOptions, &config);
  894. if (sink == nullptr) {
  895. info("Skipping config %s: Don't understand '%s'.\n", config.getTag().c_str(),
  896. config.getTag().c_str());
  897. continue;
  898. }
  899. const SkTArray<SkString>& parts = config.getViaParts();
  900. for (int j = parts.count(); j-- > 0;) {
  901. const SkString& part = parts[j];
  902. Sink* next = create_via(part, sink);
  903. if (next == nullptr) {
  904. info("Skipping config %s: Don't understand '%s'.\n", config.getTag().c_str(),
  905. part.c_str());
  906. delete sink;
  907. sink = nullptr;
  908. break;
  909. }
  910. sink = next;
  911. }
  912. if (sink) {
  913. push_sink(config, sink);
  914. }
  915. }
  916. // If no configs were requested (just running tests, perhaps?), then we're okay.
  917. if (configs.count() == 0 ||
  918. // If we're using the default configs, we're okay.
  919. defaultConfigs ||
  920. // Otherwise, make sure that all specified configs have become sinks.
  921. configs.count() == gSinks.count()) {
  922. return true;
  923. }
  924. return false;
  925. }
  926. static bool match(const char* needle, const char* haystack) {
  927. if ('~' == needle[0]) {
  928. return !match(needle + 1, haystack);
  929. }
  930. if (0 == strcmp("_", needle)) {
  931. return true;
  932. }
  933. return nullptr != strstr(haystack, needle);
  934. }
  935. static bool is_blacklisted(const char* sink, const char* src,
  936. const char* srcOptions, const char* name) {
  937. for (int i = 0; i < FLAGS_blacklist.count() - 3; i += 4) {
  938. if (match(FLAGS_blacklist[i+0], sink) &&
  939. match(FLAGS_blacklist[i+1], src) &&
  940. match(FLAGS_blacklist[i+2], srcOptions) &&
  941. match(FLAGS_blacklist[i+3], name)) {
  942. return true;
  943. }
  944. }
  945. return false;
  946. }
  947. // Even when a Task Sink reports to be non-threadsafe (e.g. GPU), we know things like
  948. // .png encoding are definitely thread safe. This lets us offload that work to CPU threads.
  949. static SkTaskGroup gDefinitelyThreadSafeWork;
  950. // The finest-grained unit of work we can run: draw a single Src into a single Sink,
  951. // report any errors, and perhaps write out the output: a .png of the bitmap, or a raw stream.
  952. struct Task {
  953. Task(const TaggedSrc& src, const TaggedSink& sink) : src(src), sink(sink) {}
  954. const TaggedSrc& src;
  955. const TaggedSink& sink;
  956. static void Run(const Task& task) {
  957. AutoreleasePool pool;
  958. SkString name = task.src->name();
  959. SkString log;
  960. if (!FLAGS_dryRun) {
  961. SkBitmap bitmap;
  962. SkDynamicMemoryWStream stream;
  963. start(task.sink.tag.c_str(), task.src.tag.c_str(),
  964. task.src.options.c_str(), name.c_str());
  965. Error err = task.sink->draw(*task.src, &bitmap, &stream, &log);
  966. if (!log.isEmpty()) {
  967. info("%s %s %s %s:\n%s\n", task.sink.tag.c_str()
  968. , task.src.tag.c_str()
  969. , task.src.options.c_str()
  970. , name.c_str()
  971. , log.c_str());
  972. }
  973. if (!err.isEmpty()) {
  974. if (err.isFatal()) {
  975. fail(SkStringPrintf("%s %s %s %s: %s",
  976. task.sink.tag.c_str(),
  977. task.src.tag.c_str(),
  978. task.src.options.c_str(),
  979. name.c_str(),
  980. err.c_str()));
  981. } else {
  982. done(task.sink.tag.c_str(), task.src.tag.c_str(),
  983. task.src.options.c_str(), name.c_str());
  984. return;
  985. }
  986. }
  987. // We're likely switching threads here, so we must capture by value, [=] or [foo,bar].
  988. SkStreamAsset* data = stream.detachAsStream().release();
  989. gDefinitelyThreadSafeWork.add([task,name,bitmap,data]{
  990. std::unique_ptr<SkStreamAsset> ownedData(data);
  991. std::unique_ptr<HashAndEncode> hashAndEncode;
  992. SkString md5;
  993. if (!FLAGS_writePath.isEmpty() || !FLAGS_readPath.isEmpty()) {
  994. SkMD5 hash;
  995. if (data->getLength()) {
  996. hash.writeStream(data, data->getLength());
  997. data->rewind();
  998. } else {
  999. hashAndEncode.reset(new HashAndEncode(bitmap));
  1000. hashAndEncode->write(&hash);
  1001. }
  1002. SkMD5::Digest digest = hash.finish();
  1003. for (int i = 0; i < 16; i++) {
  1004. md5.appendf("%02x", digest.data[i]);
  1005. }
  1006. }
  1007. if (!FLAGS_readPath.isEmpty() &&
  1008. !gGold.contains(Gold(task.sink.tag, task.src.tag,
  1009. task.src.options, name, md5))) {
  1010. fail(SkStringPrintf("%s not found for %s %s %s %s in %s",
  1011. md5.c_str(),
  1012. task.sink.tag.c_str(),
  1013. task.src.tag.c_str(),
  1014. task.src.options.c_str(),
  1015. name.c_str(),
  1016. FLAGS_readPath[0]));
  1017. }
  1018. if (!FLAGS_writePath.isEmpty()) {
  1019. const char* ext = task.sink->fileExtension();
  1020. if (ext && !FLAGS_dont_write.contains(ext)) {
  1021. if (data->getLength()) {
  1022. WriteToDisk(task, md5, ext, data, data->getLength(), nullptr, nullptr);
  1023. SkASSERT(bitmap.drawsNothing());
  1024. } else if (!bitmap.drawsNothing()) {
  1025. WriteToDisk(task, md5, ext, nullptr, 0, &bitmap, hashAndEncode.get());
  1026. }
  1027. }
  1028. }
  1029. SkPixmap pm;
  1030. if (FLAGS_checkF16 && bitmap.colorType() == kRGBA_F16Norm_SkColorType &&
  1031. bitmap.peekPixels(&pm)) {
  1032. bool unclamped = false;
  1033. for (int y = 0; y < pm.height() && !unclamped; ++y)
  1034. for (int x = 0; x < pm.width() && !unclamped; ++x) {
  1035. Sk4f rgba = SkHalfToFloat_finite_ftz(*pm.addr64(x, y));
  1036. float a = rgba[3];
  1037. if (a > 1.0f || (rgba < 0.0f).anyTrue() || (rgba > a).anyTrue()) {
  1038. SkDebugf("[%s] F16Norm pixel [%d, %d] unclamped: (%g, %g, %g, %g)\n",
  1039. name.c_str(), x, y, rgba[0], rgba[1], rgba[2], rgba[3]);
  1040. unclamped = true;
  1041. }
  1042. }
  1043. }
  1044. });
  1045. }
  1046. done(task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str(), name.c_str());
  1047. }
  1048. static SkString identify_gamut(SkColorSpace* cs) {
  1049. if (!cs) {
  1050. return SkString("untagged");
  1051. }
  1052. skcms_Matrix3x3 gamut;
  1053. if (cs->toXYZD50(&gamut)) {
  1054. auto eq = [](skcms_Matrix3x3 x, skcms_Matrix3x3 y) {
  1055. for (int i = 0; i < 3; i++)
  1056. for (int j = 0; j < 3; j++) {
  1057. if (x.vals[i][j] != y.vals[i][j]) { return false; }
  1058. }
  1059. return true;
  1060. };
  1061. if (eq(gamut, SkNamedGamut::kSRGB )) { return SkString("sRGB"); }
  1062. if (eq(gamut, SkNamedGamut::kAdobeRGB)) { return SkString("Adobe"); }
  1063. if (eq(gamut, SkNamedGamut::kDCIP3 )) { return SkString("P3"); }
  1064. if (eq(gamut, SkNamedGamut::kRec2020 )) { return SkString("2020"); }
  1065. if (eq(gamut, SkNamedGamut::kXYZ )) { return SkString("XYZ"); }
  1066. if (eq(gamut, gNarrow_toXYZD50 )) { return SkString("narrow"); }
  1067. return SkString("other");
  1068. }
  1069. return SkString("non-XYZ");
  1070. }
  1071. static SkString identify_transfer_fn(SkColorSpace* cs) {
  1072. if (!cs) {
  1073. return SkString("untagged");
  1074. }
  1075. skcms_TransferFunction tf;
  1076. if (cs->isNumericalTransferFn(&tf)) {
  1077. auto eq = [](skcms_TransferFunction x, skcms_TransferFunction y) {
  1078. return x.g == y.g
  1079. && x.a == y.a
  1080. && x.b == y.b
  1081. && x.c == y.c
  1082. && x.d == y.d
  1083. && x.e == y.e
  1084. && x.f == y.f;
  1085. };
  1086. if (tf.a == 1 && tf.b == 0 && tf.c == 0 && tf.d == 0 && tf.e == 0 && tf.f == 0) {
  1087. return SkStringPrintf("gamma %.3g", tf.g);
  1088. }
  1089. if (eq(tf, SkNamedTransferFn::kSRGB )) { return SkString("sRGB"); }
  1090. if (eq(tf, SkNamedTransferFn::kRec2020)) { return SkString("2020"); }
  1091. return SkStringPrintf("%.3g %.3g %.3g %.3g %.3g %.3g %.3g",
  1092. tf.g, tf.a, tf.b, tf.c, tf.d, tf.e, tf.f);
  1093. }
  1094. return SkString("non-numeric");
  1095. }
  1096. static void WriteToDisk(const Task& task,
  1097. SkString md5,
  1098. const char* ext,
  1099. SkStream* data, size_t len,
  1100. const SkBitmap* bitmap,
  1101. const HashAndEncode* hashAndEncode) {
  1102. JsonWriter::BitmapResult result;
  1103. result.name = task.src->name();
  1104. result.config = task.sink.tag;
  1105. result.sourceType = task.src.tag;
  1106. result.sourceOptions = task.src.options;
  1107. result.ext = ext;
  1108. result.md5 = md5;
  1109. if (bitmap) {
  1110. result.gamut = identify_gamut (bitmap->colorSpace());
  1111. result.transferFn = identify_transfer_fn (bitmap->colorSpace());
  1112. result.colorType = ToolUtils::colortype_name (bitmap->colorType());
  1113. result.alphaType = ToolUtils::alphatype_name (bitmap->alphaType());
  1114. result.colorDepth = ToolUtils::colortype_depth(bitmap->colorType());
  1115. }
  1116. JsonWriter::AddBitmapResult(result);
  1117. // If an MD5 is uninteresting, we want it noted in the JSON file,
  1118. // but don't want to dump it out as a .png (or whatever ext is).
  1119. if (gUninterestingHashes.contains(md5)) {
  1120. return;
  1121. }
  1122. const char* dir = FLAGS_writePath[0];
  1123. SkString resources = GetResourcePath();
  1124. if (0 == strcmp(dir, "@")) { // Needed for iOS.
  1125. dir = resources.c_str();
  1126. }
  1127. sk_mkdir(dir);
  1128. SkString path;
  1129. if (FLAGS_nameByHash) {
  1130. path = SkOSPath::Join(dir, result.md5.c_str());
  1131. path.append(".");
  1132. path.append(ext);
  1133. if (sk_exists(path.c_str())) {
  1134. return; // Content-addressed. If it exists already, we're done.
  1135. }
  1136. } else {
  1137. path = SkOSPath::Join(dir, task.sink.tag.c_str());
  1138. sk_mkdir(path.c_str());
  1139. path = SkOSPath::Join(path.c_str(), task.src.tag.c_str());
  1140. sk_mkdir(path.c_str());
  1141. if (strcmp(task.src.options.c_str(), "") != 0) {
  1142. path = SkOSPath::Join(path.c_str(), task.src.options.c_str());
  1143. sk_mkdir(path.c_str());
  1144. }
  1145. path = SkOSPath::Join(path.c_str(), task.src->name().c_str());
  1146. path.append(".");
  1147. path.append(ext);
  1148. }
  1149. if (bitmap) {
  1150. SkASSERT(hashAndEncode);
  1151. if (!hashAndEncode->writePngTo(path.c_str(),
  1152. result.md5.c_str(),
  1153. FLAGS_key,
  1154. FLAGS_properties)) {
  1155. fail(SkStringPrintf("Can't encode PNG to %s.\n", path.c_str()));
  1156. return;
  1157. }
  1158. } else {
  1159. SkFILEWStream file(path.c_str());
  1160. if (!file.isValid()) {
  1161. fail(SkStringPrintf("Can't open %s for writing.\n", path.c_str()));
  1162. return;
  1163. }
  1164. if (!file.writeStream(data, len)) {
  1165. fail(SkStringPrintf("Can't write to %s.\n", path.c_str()));
  1166. return;
  1167. }
  1168. }
  1169. }
  1170. };
  1171. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1172. // Unit tests don't fit so well into the Src/Sink model, so we give them special treatment.
  1173. static SkTDArray<skiatest::Test> gParallelTests, gSerialTests;
  1174. static void gather_tests() {
  1175. if (!FLAGS_src.contains("tests")) {
  1176. return;
  1177. }
  1178. for (const skiatest::Test& test : skiatest::TestRegistry::Range()) {
  1179. if (!in_shard()) {
  1180. continue;
  1181. }
  1182. if (CommandLineFlags::ShouldSkip(FLAGS_match, test.name)) {
  1183. continue;
  1184. }
  1185. if (test.needsGpu && FLAGS_gpu) {
  1186. (FLAGS_gpu_threading ? gParallelTests : gSerialTests).push_back(test);
  1187. } else if (!test.needsGpu && FLAGS_cpu) {
  1188. gParallelTests.push_back(test);
  1189. }
  1190. }
  1191. }
  1192. static void run_test(skiatest::Test test, const GrContextOptions& grCtxOptions) {
  1193. struct : public skiatest::Reporter {
  1194. void reportFailed(const skiatest::Failure& failure) override {
  1195. fail(failure.toString());
  1196. }
  1197. bool allowExtendedTest() const override {
  1198. return FLAGS_pathOpsExtended;
  1199. }
  1200. bool verbose() const override { return FLAGS_veryVerbose; }
  1201. } reporter;
  1202. if (!FLAGS_dryRun && !is_blacklisted("_", "tests", "_", test.name)) {
  1203. AutoreleasePool pool;
  1204. GrContextOptions options = grCtxOptions;
  1205. test.modifyGrContextOptions(&options);
  1206. skiatest::ReporterContext ctx(&reporter, SkString(test.name));
  1207. start("unit", "test", "", test.name);
  1208. test.run(&reporter, options);
  1209. }
  1210. done("unit", "test", "", test.name);
  1211. }
  1212. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1213. int main(int argc, char** argv) {
  1214. #if defined(__MSVC_RUNTIME_CHECKS)
  1215. _RTC_SetErrorFunc(RuntimeCheckErrorFunc);
  1216. #endif
  1217. #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_HAS_HEIF_LIBRARY)
  1218. android::ProcessState::self()->startThreadPool();
  1219. #endif
  1220. CommandLineFlags::Parse(argc, argv);
  1221. initializeEventTracingForTools();
  1222. #if !defined(SK_BUILD_FOR_GOOGLE3) && defined(SK_BUILD_FOR_IOS)
  1223. cd_Documents();
  1224. #endif
  1225. setbuf(stdout, nullptr);
  1226. setup_crash_handler();
  1227. ToolUtils::SetDefaultFontMgr();
  1228. SetAnalyticAAFromCommonFlags();
  1229. if (FLAGS_forceRasterPipeline) {
  1230. gSkForceRasterPipelineBlitter = true;
  1231. }
  1232. // The bots like having a verbose.log to upload, so always touch the file even if --verbose.
  1233. if (!FLAGS_writePath.isEmpty()) {
  1234. sk_mkdir(FLAGS_writePath[0]);
  1235. gVLog = fopen(SkOSPath::Join(FLAGS_writePath[0], "verbose.log").c_str(), "w");
  1236. }
  1237. if (FLAGS_verbose) {
  1238. gVLog = stderr;
  1239. }
  1240. GrContextOptions grCtxOptions;
  1241. SetCtxOptionsFromCommonFlags(&grCtxOptions);
  1242. dump_json(); // It's handy for the bots to assume this is ~never missing.
  1243. SkAutoGraphics ag;
  1244. SkTaskGroup::Enabler enabled(FLAGS_threads);
  1245. if (nullptr == GetResourceAsData("images/color_wheel.png")) {
  1246. info("Some resources are missing. Do you need to set --resourcePath?\n");
  1247. }
  1248. gather_gold();
  1249. gather_uninteresting_hashes();
  1250. if (!gather_srcs()) {
  1251. return 1;
  1252. }
  1253. // TODO(dogben): This is a bit ugly. Find a cleaner way to do this.
  1254. bool defaultConfigs = true;
  1255. for (int i = 0; i < argc; i++) {
  1256. static const char* kConfigArg = "--config";
  1257. if (strcmp(argv[i], kConfigArg) == 0) {
  1258. defaultConfigs = false;
  1259. break;
  1260. }
  1261. }
  1262. if (!gather_sinks(grCtxOptions, defaultConfigs)) {
  1263. return 1;
  1264. }
  1265. gather_tests();
  1266. gPending = gSrcs.count() * gSinks.count() + gParallelTests.count() + gSerialTests.count();
  1267. info("%d srcs * %d sinks + %d tests == %d tasks\n",
  1268. gSrcs.count(), gSinks.count(), gParallelTests.count() + gSerialTests.count(), gPending);
  1269. // Kick off as much parallel work as we can, making note of any serial work we'll need to do.
  1270. SkTaskGroup parallel;
  1271. SkTArray<Task> serial;
  1272. for (auto& sink : gSinks)
  1273. for (auto& src : gSrcs) {
  1274. if (src->veto(sink->flags()) ||
  1275. is_blacklisted(sink.tag.c_str(), src.tag.c_str(),
  1276. src.options.c_str(), src->name().c_str())) {
  1277. SkAutoSpinlock lock(gMutex);
  1278. gPending--;
  1279. continue;
  1280. }
  1281. Task task(src, sink);
  1282. if (src->serial() || sink->serial()) {
  1283. serial.push_back(task);
  1284. } else {
  1285. parallel.add([task] { Task::Run(task); });
  1286. }
  1287. }
  1288. for (auto test : gParallelTests) {
  1289. parallel.add([test, grCtxOptions] { run_test(test, grCtxOptions); });
  1290. }
  1291. // With the parallel work running, run serial tasks and tests here on main thread.
  1292. for (auto task : serial) { Task::Run(task); }
  1293. for (auto test : gSerialTests) { run_test(test, grCtxOptions); }
  1294. // Wait for any remaining parallel work to complete (including any spun off of serial tasks).
  1295. parallel.wait();
  1296. gDefinitelyThreadSafeWork.wait();
  1297. // At this point we're back in single-threaded land.
  1298. // We'd better have run everything.
  1299. SkASSERT(gPending == 0);
  1300. // Make sure we've flushed all our results to disk.
  1301. dump_json();
  1302. if (gFailures.count() > 0) {
  1303. info("Failures:\n");
  1304. for (int i = 0; i < gFailures.count(); i++) {
  1305. info("\t%s\n", gFailures[i].c_str());
  1306. }
  1307. info("%d failures\n", gFailures.count());
  1308. // A non-zero return code does not make it to Swarming
  1309. // An abort does.
  1310. #ifdef SK_BUILD_FOR_IOS
  1311. SK_ABORT("There were failures!");
  1312. #endif
  1313. return 1;
  1314. }
  1315. SkGraphics::PurgeAllCaches();
  1316. info("Finished!\n");
  1317. return 0;
  1318. }