diff options
author | 2015-01-15 10:56:12 -0800 | |
---|---|---|
committer | 2015-01-15 10:56:12 -0800 | |
commit | 748ca3bf2d170708f263693e8579e6722389d0ef (patch) | |
tree | d35f621f82ec6addff9639fc60ab4937004e5243 /dm/DM.cpp | |
parent | 0063a9b69a6a5d377f207c2aa1ea1e7220c19ba9 (diff) |
Sketch DM refactor.
BUG=skia:3255
I think this supports everything DM used to, but has completely refactored how
it works to fit the design in the bug.
Configs like "tiles-gpu" are automatically wired up.
I wouldn't suggest looking at this as a diff. There's just a bunch of deleted
files, a few new files, and one new file that shares a name with a deleted file
(DM.cpp).
NOTREECHECKS=true
Committed: https://skia.googlesource.com/skia/+/709d2c3e5062c5b57f91273bfc11a751f5b2bb88
Review URL: https://codereview.chromium.org/788243008
Diffstat (limited to 'dm/DM.cpp')
-rw-r--r-- | dm/DM.cpp | 596 |
1 files changed, 373 insertions, 223 deletions
@@ -1,293 +1,443 @@ -// Main binary for DM. -// For a high-level overview, please see dm/README. - #include "CrashHandler.h" -#include "LazyDecodeBitmap.h" +#include "DMJsonWriter.h" +#include "DMSrcSink.h" +#include "OverwriteLine.h" +#include "ProcStats.h" +#include "SkBBHFactory.h" #include "SkCommonFlags.h" #include "SkForceLinking.h" #include "SkGraphics.h" +#include "SkMD5.h" #include "SkOSFile.h" -#include "SkPicture.h" -#include "SkString.h" #include "SkTaskGroup.h" #include "Test.h" -#include "gm.h" -#include "sk_tool_utils.h" -#include "sk_tool_utils_flags.h" - -#include "DMCpuGMTask.h" -#include "DMGpuGMTask.h" -#include "DMGpuSupport.h" -#include "DMImageTask.h" -#include "DMJsonWriter.h" -#include "DMPDFTask.h" -#include "DMPDFRasterizeTask.h" -#include "DMReporter.h" -#include "DMSKPTask.h" -#include "DMTask.h" -#include "DMTaskRunner.h" -#include "DMTestTask.h" - -#ifdef SK_BUILD_POPPLER -# include "SkPDFRasterizer.h" -# define RASTERIZE_PDF_PROC SkPopplerRasterizePDF -#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) -# include "SkCGUtils.h" -# define RASTERIZE_PDF_PROC SkPDFDocumentToBitmap -#else -# define RASTERIZE_PDF_PROC NULL -#endif +#include "Timer.h" -#include <ctype.h> +DEFINE_bool(tests, true, "Run tests?"); +DEFINE_string(images, "resources", "Images to decode."); +//DEFINE_string(src, "gm skp image subset", "Source types to test."); +DEFINE_string(src, "gm skp", "Source types to test. TEMPORARILY DISABLED"); +DEFINE_bool(nameByHash, false, + "If true, write to FLAGS_writePath[0]/<hash>.png instead of " + "to FLAGS_writePath[0]/<config>/<sourceType>/<name>.png"); +DEFINE_bool2(pathOpsExtended, x, false, "Run extended pathOps tests."); +DEFINE_string(matrix, "1 0 0 0 1 0 0 0 1", + "Matrix to apply when using 'matrix' in config."); -using skiagm::GM; -using skiagm::GMRegistry; -using skiatest::Test; -using skiatest::TestRegistry; +__SK_FORCE_IMAGE_DECODER_LINKING; +using namespace DM; -static const char kGpuAPINameGL[] = "gl"; -static const char kGpuAPINameGLES[] = "gles"; +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -DEFINE_bool(gms, true, "Run GMs?"); -DEFINE_bool(tests, true, "Run tests?"); -DEFINE_bool(reportUsedChars, false, "Output test font construction data to be pasted into" - " create_test_font.cpp."); -DEFINE_string(images, "resources", "Path to directory containing images to decode."); -DEFINE_bool(rasterPDF, true, "Rasterize PDFs?"); +SK_DECLARE_STATIC_MUTEX(gFailuresMutex); +static SkTArray<SkString> gFailures; -__SK_FORCE_IMAGE_DECODER_LINKING; +static void fail(ImplicitString err) { + SkAutoMutexAcquire lock(gFailuresMutex); + SkDebugf("\n\nFAILURE: %s\n\n", err.c_str()); + gFailures.push_back(err); +} -static DM::RasterizePdfProc get_pdf_rasterizer_proc() { - return reinterpret_cast<DM::RasterizePdfProc>( - FLAGS_rasterPDF ? RASTERIZE_PDF_PROC : NULL); +static int32_t gPending = 0; // Atomic. + +static void done(double ms, ImplicitString config, ImplicitString src, ImplicitString name) { + SkDebugf("%s(%4dMB %5d) %s\t%s %s %s ", FLAGS_verbose ? "\n" : kSkOverwriteLine + , sk_tools::getMaxResidentSetSizeMB() + , sk_atomic_dec(&gPending)-1 + , HumanizeMs(ms).c_str() + , config.c_str() + , src.c_str() + , name.c_str()); } -// "FooBar" -> "foobar". Obviously, ASCII only. -static SkString lowercase(SkString s) { - for (size_t i = 0; i < s.size(); i++) { - s[i] = tolower(s[i]); +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +template <typename T> +struct Tagged : public SkAutoTDelete<T> { const char* tag; }; + +static const bool kMemcpyOK = true; + +static SkTArray<Tagged<Src>, kMemcpyOK> gSrcs; +static SkTArray<Tagged<Sink>, kMemcpyOK> gSinks; + +static void push_src(const char* tag, Src* s) { + SkAutoTDelete<Src> src(s); + if (FLAGS_src.contains(tag) && + !SkCommandLineFlags::ShouldSkip(FLAGS_match, src->name().c_str())) { + Tagged<Src>& s = gSrcs.push_back(); + s.reset(src.detach()); + s.tag = tag; } - return s; } -static const GrContextFactory::GLContextType native = GrContextFactory::kNative_GLContextType; -static const GrContextFactory::GLContextType nvpr = GrContextFactory::kNVPR_GLContextType; -static const GrContextFactory::GLContextType null = GrContextFactory::kNull_GLContextType; -static const GrContextFactory::GLContextType debug = GrContextFactory::kDebug_GLContextType; -#if SK_ANGLE -static const GrContextFactory::GLContextType angle = GrContextFactory::kANGLE_GLContextType; -#endif -#if SK_MESA -static const GrContextFactory::GLContextType mesa = GrContextFactory::kMESA_GLContextType; -#endif - -static void kick_off_gms(const SkTDArray<GMRegistry::Factory>& gms, - const SkTArray<SkString>& configs, - GrGLStandard gpuAPI, - DM::Reporter* reporter, - DM::TaskRunner* tasks) { -#define START(name, type, ...) \ - if (lowercase(configs[j]).equals(name)) { \ - tasks->add(SkNEW_ARGS(DM::type, (name, reporter, tasks, gms[i], ## __VA_ARGS__))); \ +static void gather_srcs() { + for (const skiagm::GMRegistry* r = skiagm::GMRegistry::Head(); r; r = r->next()) { + push_src("gm", new GMSrc(r->factory())); } - for (int i = 0; i < gms.count(); i++) { - for (int j = 0; j < configs.count(); j++) { - - START("565", CpuGMTask, kRGB_565_SkColorType); - START("8888", CpuGMTask, kN32_SkColorType); - START("gpu", GpuGMTask, native, gpuAPI, 0, false); - START("msaa4", GpuGMTask, native, gpuAPI, 4, false); - START("msaa16", GpuGMTask, native, gpuAPI, 16, false); - START("nvprmsaa4", GpuGMTask, nvpr, gpuAPI, 4, false); - START("nvprmsaa16", GpuGMTask, nvpr, gpuAPI, 16, false); - START("gpudft", GpuGMTask, native, gpuAPI, 0, true); - START("gpunull", GpuGMTask, null, gpuAPI, 0, false); - START("gpudebug", GpuGMTask, debug, gpuAPI, 0, false); -#if SK_ANGLE - START("angle", GpuGMTask, angle, gpuAPI, 0, false); -#endif -#if SK_MESA - START("mesa", GpuGMTask, mesa, gpuAPI, 0, false); -#endif - START("pdf", PDFTask, get_pdf_rasterizer_proc()); + if (!FLAGS_skps.isEmpty()) { + SkOSFile::Iter it(FLAGS_skps[0], "skp"); + for (SkString file; it.next(&file); ) { + push_src("skp", new SKPSrc(SkOSPath::Join(FLAGS_skps[0], file.c_str()))); } } -#undef START -} - -static void kick_off_tests(const SkTDArray<TestRegistry::Factory>& tests, - DM::Reporter* reporter, - DM::TaskRunner* tasks) { - for (int i = 0; i < tests.count(); i++) { - SkAutoTDelete<Test> test(tests[i](NULL)); - if (test->isGPUTest()) { - tasks->add(SkNEW_ARGS(DM::GpuTestTask, (reporter, tasks, tests[i]))); - } else { - tasks->add(SkNEW_ARGS(DM::CpuTestTask, (reporter, tasks, tests[i]))); + if (!FLAGS_images.isEmpty()) { + const char* exts[] = { + "bmp", "gif", "jpg", "jpeg", "png", "webp", "ktx", "astc", "wbmp", "ico", + "BMP", "GIF", "JPG", "JPEG", "PNG", "WEBP", "KTX", "ASTC", "WBMP", "ICO", + }; + for (size_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { + SkOSFile::Iter it(FLAGS_images[0], exts[i]); + for (SkString file; it.next(&file); ) { + SkString path = SkOSPath::Join(FLAGS_images[0], file.c_str()); + push_src("image", new ImageSrc(path)); // Decode entire image. + push_src("subset", new ImageSrc(path, 5)); // Decode 5 random subsets. + } } } } -static void find_files(const char* dir, - const char* suffixes[], - size_t num_suffixes, - SkTArray<SkString>* files) { - if (0 == strcmp(dir, "")) { +static GrGLStandard get_gpu_api() { + if (FLAGS_gpuAPI.contains("gl")) { return kGL_GrGLStandard; } + if (FLAGS_gpuAPI.contains("gles")) { return kGLES_GrGLStandard; } + return kNone_GrGLStandard; +} + +static void push_sink(const char* tag, Sink* s) { + SkAutoTDelete<Sink> sink(s); + if (!FLAGS_config.contains(tag)) { + return; + } + // Try a noop Src as a canary. If it fails, skip this sink. + struct : public Src { + Error draw(SkCanvas*) const SK_OVERRIDE { return ""; } + SkISize size() const SK_OVERRIDE { return SkISize::Make(16, 16); } + Name name() const SK_OVERRIDE { return "noop"; } + } noop; + + SkBitmap bitmap; + SkDynamicMemoryWStream stream; + Error err = sink->draw(noop, &bitmap, &stream); + if (!err.isEmpty()) { + SkDebugf("Skipping %s: %s\n", tag, err.c_str()); return; } - SkString filename; - for (size_t i = 0; i < num_suffixes; i++) { - SkOSFile::Iter it(dir, suffixes[i]); - while (it.next(&filename)) { - if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) { - files->push_back(SkOSPath::Join(dir, filename.c_str())); - } + Tagged<Sink>& ts = gSinks.push_back(); + ts.reset(sink.detach()); + ts.tag = tag; +} + +static bool gpu_supported() { +#if SK_SUPPORT_GPU + return FLAGS_gpu; +#else + return false; +#endif +} + +static Sink* create_sink(const char* tag) { +#define SINK(t, sink, ...) if (0 == strcmp(t, tag)) { return new sink(__VA_ARGS__); } + if (gpu_supported()) { + const GrGLStandard api = get_gpu_api(); + SINK("gpunull", GPUSink, GrContextFactory::kNull_GLContextType, api, 0, false); + SINK("gpudebug", GPUSink, GrContextFactory::kDebug_GLContextType, api, 0, false); + SINK("gpu", GPUSink, GrContextFactory::kNative_GLContextType, api, 0, false); + SINK("gpudft", GPUSink, GrContextFactory::kNative_GLContextType, api, 0, true); + SINK("msaa4", GPUSink, GrContextFactory::kNative_GLContextType, api, 4, false); + SINK("msaa16", GPUSink, GrContextFactory::kNative_GLContextType, api, 16, false); + SINK("nvprmsaa4", GPUSink, GrContextFactory::kNVPR_GLContextType, api, 4, false); + SINK("nvprmsaa16", GPUSink, GrContextFactory::kNVPR_GLContextType, api, 16, false); + #if SK_ANGLE + SINK("angle", GPUSink, GrContextFactory::kANGLE_GLContextType, api, 0, false); + #endif + #if SK_MESA + SINK("mesa", GPUSink, GrContextFactory::kMESA_GLContextType, api, 0, false); + #endif + } + + if (FLAGS_cpu) { + SINK("565", RasterSink, kRGB_565_SkColorType); + SINK("8888", RasterSink, kN32_SkColorType); + // TODO(mtklein): reenable once skiagold can handle .pdf uploads. + //SINK("pdf", PDFSink); + } +#undef SINK + return NULL; +} + +static Sink* create_via(const char* tag, Sink* wrapped) { +#define VIA(t, via, ...) if (0 == strcmp(t, tag)) { return new via(__VA_ARGS__); } + VIA("serialize", ViaSerialization, wrapped); + + VIA("tiles", ViaTiles, 256, 256, NULL, wrapped); + VIA("tiles_rt", ViaTiles, 256, 256, new SkRTreeFactory, wrapped); + + const int xp = SkGPipeWriter::kCrossProcess_Flag, + sa = xp | SkGPipeWriter::kSharedAddressSpace_Flag; + VIA("pipe", ViaPipe, 0, wrapped); + VIA("pipe_xp", ViaPipe, xp, wrapped); + VIA("pipe_sa", ViaPipe, sa, wrapped); + + if (FLAGS_matrix.count() == 9) { + SkMatrix m; + for (int i = 0; i < 9; i++) { + m[i] = (SkScalar)atof(FLAGS_matrix[i]); } + VIA("matrix", ViaMatrix, m, wrapped); } +#undef VIA + return NULL; } -static void kick_off_skps(const SkTArray<SkString>& skps, - DM::Reporter* reporter, - DM::TaskRunner* tasks) { - for (int i = 0; i < skps.count(); ++i) { - SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(skps[i].c_str())); - if (stream.get() == NULL) { - SkDebugf("Could not read %s.\n", skps[i].c_str()); - exit(1); +static void gather_sinks() { + for (int i = 0; i < FLAGS_config.count(); i++) { + const char* config = FLAGS_config[i]; + SkTArray<SkString> parts; + SkStrSplit(config, "-", &parts); + + Sink* sink = NULL; + for (int i = parts.count(); i-- > 0;) { + const char* part = parts[i].c_str(); + Sink* next = (sink == NULL) ? create_sink(part) : create_via(part, sink); + if (next == NULL) { + SkDebugf("Skipping %s: Don't understand '%s'.\n", config, part); + delete sink; + sink = NULL; + break; + } + sink = next; } - SkAutoTUnref<SkPicture> pic( - SkPicture::CreateFromStream(stream.get(), &sk_tools::LazyDecodeBitmap)); - if (pic.get() == NULL) { - SkDebugf("Could not read %s as an SkPicture.\n", skps[i].c_str()); - exit(1); + if (sink) { + push_sink(config, sink); } - - SkString filename = SkOSPath::Basename(skps[i].c_str()); - tasks->add(SkNEW_ARGS(DM::SKPTask, (reporter, tasks, pic, filename))); - tasks->add(SkNEW_ARGS(DM::PDFTask, (reporter, tasks, pic, filename, - get_pdf_rasterizer_proc()))); } } -static void kick_off_images(const SkTArray<SkString>& images, - DM::Reporter* reporter, - DM::TaskRunner* tasks) { - for (int i = 0; i < images.count(); i++) { - SkAutoTUnref<SkData> image(SkData::NewFromFileName(images[i].c_str())); - if (!image) { - SkDebugf("Could not read %s.\n", images[i].c_str()); - exit(1); +// The finest-grained unit of work we can run: draw a single Src into a single Sink, +// report any errors, and perhaps write out the output: a .png of the bitmap, or a raw stream. +struct Task { + Task(const Tagged<Src>& src, const Tagged<Sink>& sink) : src(src), sink(sink) {} + const Tagged<Src>& src; + const Tagged<Sink>& sink; + + static void Run(Task* task) { + WallTimer timer; + timer.start(); + if (!FLAGS_dryRun) { + SkBitmap bitmap; + SkDynamicMemoryWStream stream; + Error err = task->sink->draw(*task->src, &bitmap, &stream); + if (!err.isEmpty()) { + fail(SkStringPrintf("%s %s %s: %s", + task->sink.tag, + task->src.tag, + task->src->name().c_str(), + err.c_str())); + } + if (!FLAGS_writePath.isEmpty()) { + const char* ext = task->sink->fileExtension(); + if (stream.bytesWritten() == 0) { + SkMemoryStream pixels(bitmap.getPixels(), bitmap.getSize()); + WriteToDisk(*task, &pixels, bitmap.getSize(), &bitmap, ext); + } else { + SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream()); + WriteToDisk(*task, data, data->getLength(), NULL, ext); + } + } } - SkString filename = SkOSPath::Basename(images[i].c_str()); - tasks->add(SkNEW_ARGS(DM::ImageTask, (reporter, tasks, image, filename))); - tasks->add(SkNEW_ARGS(DM::ImageTask, (reporter, tasks, image, filename, 5/*subsets*/))); + timer.end(); + done(timer.fWall, task->sink.tag, task->src.tag, task->src->name()); } -} + static void WriteToDisk(const Task& task, + SkStream* data, size_t len, + const SkBitmap* bitmap, + const char* ext) { + SkMD5 hash; + hash.writeStream(data, len); + SkMD5::Digest digest; + hash.finish(digest); + + JsonWriter::BitmapResult result; + result.name = task.src->name(); + result.config = task.sink.tag; + result.sourceType = task.src.tag; + result.ext = ext; + for (int i = 0; i < 16; i++) { + result.md5.appendf("%02x", digest.data[i]); + } + JsonWriter::AddBitmapResult(result); -static void report_failures(const SkTArray<SkString>& failures) { - if (failures.count() == 0) { - return; + const char* dir = FLAGS_writePath[0]; + if (0 == strcmp(dir, "@")) { // Needed for iOS. + dir = FLAGS_resourcePath[0]; + } + sk_mkdir(dir); + + SkString path; + if (FLAGS_nameByHash) { + path = SkOSPath::Join(dir, result.md5.c_str()); + path.append("."); + path.append(ext); + if (sk_exists(path.c_str())) { + return; // Content-addressed. If it exists already, we're done. + } + } else { + path = SkOSPath::Join(dir, task.sink.tag); + sk_mkdir(path.c_str()); + path = SkOSPath::Join(path.c_str(), task.src.tag); + sk_mkdir(path.c_str()); + path = SkOSPath::Join(path.c_str(), task.src->name().c_str()); + path.append("."); + path.append(ext); + } + + SkFILEWStream file(path.c_str()); + if (!file.isValid()) { + fail(SkStringPrintf("Can't open %s for writing.\n", path.c_str())); + return; + } + + data->rewind(); + if (bitmap) { + // We can't encode A8 bitmaps as PNGs. Convert them to 8888 first. + SkBitmap converted; + if (bitmap->info().colorType() == kAlpha_8_SkColorType) { + if (!bitmap->copyTo(&converted, kN32_SkColorType)) { + fail("Can't convert A8 to 8888.\n"); + return; + } + bitmap = &converted; + } + if (!SkImageEncoder::EncodeStream(&file, *bitmap, SkImageEncoder::kPNG_Type, 100)) { + fail(SkStringPrintf("Can't encode PNG to %s.\n", path.c_str())); + return; + } + } else { + if (!file.writeStream(data, len)) { + fail(SkStringPrintf("Can't write to %s.\n", path.c_str())); + return; + } + } } +}; - SkDebugf("Failures:\n"); - for (int i = 0; i < failures.count(); i++) { - SkDebugf(" %s\n", failures[i].c_str()); +// Run all tasks in the same enclave serially on the same thread. +// They can't possibly run concurrently with each other. +static void run_enclave(SkTArray<Task>* tasks) { + for (int i = 0; i < tasks->count(); i++) { + Task::Run(tasks->begin() + i); } - SkDebugf("%d failures.\n", failures.count()); } -static GrGLStandard get_gl_standard() { - if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) { - return kGL_GrGLStandard; - } - if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) { - return kGLES_GrGLStandard; - } - return kNone_GrGLStandard; +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +// Unit tests don't fit so well into the Src/Sink model, so we give them special treatment. + +static struct : public skiatest::Reporter { + void onReportFailed(const skiatest::Failure& failure) SK_OVERRIDE { + SkString s; + failure.getFailureString(&s); + fail(s); + JsonWriter::AddTestFailure(failure); + } + bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_pathOpsExtended; } + bool verbose() const SK_OVERRIDE { return FLAGS_veryVerbose; } +} gTestReporter; + +static SkTArray<SkAutoTDelete<skiatest::Test>, kMemcpyOK> gTests; + +static void gather_tests() { + if (!FLAGS_tests) { + return; + } + for (const skiatest::TestRegistry* r = skiatest::TestRegistry::Head(); r; r = r->next()) { + SkAutoTDelete<skiatest::Test> test(r->factory()(NULL)); + if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) { + continue; + } + if (test->isGPUTest() /*&& !gpu_supported()*/) { // TEMPORARILY DISABLED + continue; + } + if (!test->isGPUTest() && !FLAGS_cpu) { + continue; + } + test->setReporter(&gTestReporter); + gTests.push_back().reset(test.detach()); + } } -template <typename T, typename Registry> -static void append_matching_factories(Registry* head, SkTDArray<typename Registry::Factory>* out) { - for (const Registry* reg = head; reg != NULL; reg = reg->next()) { - SkAutoTDelete<T> forName(reg->factory()(NULL)); - if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, forName->getName())) { - *out->append() = reg->factory(); +static void run_test(SkAutoTDelete<skiatest::Test>* t) { + WallTimer timer; + timer.start(); + skiatest::Test* test = t->get(); + if (!FLAGS_dryRun) { + GrContextFactory grFactory; + test->setGrContextFactory(&grFactory); + test->run(); + if (!test->passed()) { + fail(SkStringPrintf("test %s failed", test->getName())); } } + timer.end(); + done(timer.fWall, "unit", "test", test->getName()); } +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + int dm_main(); int dm_main() { SetupCrashHandler(); SkAutoGraphics ag; SkTaskGroup::Enabler enabled(FLAGS_threads); - if (FLAGS_dryRun || FLAGS_veryVerbose) { - FLAGS_verbose = true; - } -#if SK_ENABLE_INST_COUNT - gPrintInstCount = FLAGS_leaks; -#endif - - SkTArray<SkString> configs; - for (int i = 0; i < FLAGS_config.count(); i++) { - SkStrSplit(FLAGS_config[i], ", ", &configs); + gather_srcs(); + gather_sinks(); + gather_tests(); + + gPending = gSrcs.count() * gSinks.count() + gTests.count(); + SkDebugf("%d srcs * %d sinks + %d tests == %d tasks\n", + gSrcs.count(), gSinks.count(), gTests.count(), gPending); + + // We try to exploit as much parallelism as is safe. Most Src/Sink pairs run on any thread, + // but Sinks that identify as part of a particular enclave run serially on a single thread. + // Tests run on any thread, with a separate GrContextFactory for each GPU test. + SkTArray<Task> enclaves[kNumEnclaves]; + for (int j = 0; j < gSinks.count(); j++) { + SkTArray<Task>& tasks = enclaves[gSinks[j]->enclave()]; + for (int i = 0; i < gSrcs.count(); i++) { + tasks.push_back(Task(gSrcs[i], gSinks[j])); + } } - GrGLStandard gpuAPI = get_gl_standard(); + SK_COMPILE_ASSERT(kAnyThread_Enclave == 0, AnyThreadZero); + SkTaskGroup tg; + tg.batch( Task::Run, enclaves[0].begin(), enclaves[0].count()); + tg.batch(run_enclave, enclaves+1, kNumEnclaves-1); + tg.batch( run_test, gTests.begin(), gTests.count()); + tg.wait(); - SkTDArray<GMRegistry::Factory> gms; - if (FLAGS_gms) { - append_matching_factories<GM>(GMRegistry::Head(), &gms); - } + // At this point we're back in single-threaded land. - SkTDArray<TestRegistry::Factory> tests; - if (FLAGS_tests) { - append_matching_factories<Test>(TestRegistry::Head(), &tests); + if (!FLAGS_verbose) { + SkDebugf("\n"); } + JsonWriter::DumpJson(); - SkTArray<SkString> skps; - if (!FLAGS_skps.isEmpty()) { - const char* suffixes[] = { "skp" }; - find_files(FLAGS_skps[0], suffixes, SK_ARRAY_COUNT(suffixes), &skps); - } - - SkTArray<SkString> images; - if (!FLAGS_images.isEmpty()) { - const char* suffixes[] = { - "bmp", "gif", "jpg", "jpeg", "png", "webp", "ktx", "astc", "wbmp", "ico", - "BMP", "GIF", "JPG", "JPEG", "PNG", "WEBP", "KTX", "ASTC", "WBMP", "ICO", - }; - find_files(FLAGS_images[0], suffixes, SK_ARRAY_COUNT(suffixes), &images); + if (gFailures.count() > 0) { + SkDebugf("Failures:\n"); + for (int i = 0; i < gFailures.count(); i++) { + SkDebugf("\t%s", gFailures[i].c_str()); + } + SkDebugf("%d failures\n", gFailures.count()); + return 1; } - - SkDebugf("%d GMs x %d configs, %d tests, %d pictures, %d images\n", - gms.count(), configs.count(), tests.count(), skps.count(), images.count()); - DM::Reporter reporter; - - DM::TaskRunner tasks; - kick_off_tests(tests, &reporter, &tasks); - kick_off_gms(gms, configs, gpuAPI, &reporter, &tasks); - kick_off_skps(skps, &reporter, &tasks); - kick_off_images(images, &reporter, &tasks); - tasks.wait(); - - DM::JsonWriter::DumpJson(); - - SkDebugf("\n"); -#ifdef SK_DEBUG - if (FLAGS_portableFonts && FLAGS_reportUsedChars) { - sk_tool_utils::report_used_chars(); + if (gPending > 0) { + SkDebugf("Hrm, we didn't seem to run everything we intended to! Please file a bug.\n"); + return 1; } -#endif - - SkTArray<SkString> failures; - reporter.getFailures(&failures); - report_failures(failures); - return failures.count() > 0; + return 0; } #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |