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