diff options
Diffstat (limited to 'dm/DM.cpp')
-rw-r--r-- | dm/DM.cpp | 580 |
1 files changed, 225 insertions, 355 deletions
@@ -1,423 +1,293 @@ +// Main binary for DM. +// For a high-level overview, please see dm/README. + #include "CrashHandler.h" -#include "DMJsonWriter.h" -#include "DMSrcSink.h" -#include "OverwriteLine.h" -#include "ProcStats.h" -#include "SkBBHFactory.h" +#include "LazyDecodeBitmap.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 "Timer.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 -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_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."); +#include <ctype.h> -__SK_FORCE_IMAGE_DECODER_LINKING; -using namespace DM; +using skiagm::GM; +using skiagm::GMRegistry; +using skiatest::Test; +using skiatest::TestRegistry; -/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +static const char kGpuAPINameGL[] = "gl"; +static const char kGpuAPINameGLES[] = "gles"; -static int gPending = 0, gFailures = 0; +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?"); -static void fail(ImplicitString err) { - SkDebugf("\n\nERROR: %s\n\n", err.c_str()); - sk_atomic_inc(&gFailures); -} +__SK_FORCE_IMAGE_DECODER_LINKING; -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()); +static DM::RasterizePdfProc get_pdf_rasterizer_proc() { + return reinterpret_cast<DM::RasterizePdfProc>( + FLAGS_rasterPDF ? RASTERIZE_PDF_PROC : NULL); } -/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -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; +// "FooBar" -> "foobar". Obviously, ASCII only. +static SkString lowercase(SkString s) { + for (size_t i = 0; i < s.size(); i++) { + s[i] = tolower(s[i]); } + return s; } -static void gather_srcs() { - for (const skiagm::GMRegistry* r = skiagm::GMRegistry::Head(); r; r = r->next()) { - push_src("gm", new GMSrc(r->factory())); - } - 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()))); - } +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__))); \ } - 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. - } + 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()); } } +#undef START } -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 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]))); + } + } } -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()); +static void find_files(const char* dir, + const char* suffixes[], + size_t num_suffixes, + SkTArray<SkString>* files) { + if (0 == strcmp(dir, "")) { return; } - Tagged<Sink>& ts = gSinks.push_back(); - ts.reset(sink.detach()); - ts.tag = tag; + 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())); + } + } + } } -static bool gpu_supported() { -#if SK_SUPPORT_GPU - return FLAGS_gpu; -#else - return false; -#endif -} +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); + } + 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); + } -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 + 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()))); } +} - 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); +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); + } + 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*/))); } -#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); +static void report_failures(const SkTArray<SkString>& failures) { + if (failures.count() == 0) { + return; + } - 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); + SkDebugf("Failures:\n"); + for (int i = 0; i < failures.count(); i++) { + SkDebugf(" %s\n", failures[i].c_str()); } -#undef VIA - return NULL; + SkDebugf("%d failures.\n", failures.count()); } -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; - } - if (sink) { - push_sink(config, sink); - } - } +static GrGLStandard get_gl_standard() { + if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) { + return kGL_GrGLStandard; + } + if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) { + return kGLES_GrGLStandard; + } + return kNone_GrGLStandard; } -// 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); - } - } +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(); } - 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); - - 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; - } +int dm_main(); +int dm_main() { + SetupCrashHandler(); + SkAutoGraphics ag; + SkTaskGroup::Enabler enabled(FLAGS_threads); - 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; - } - } + if (FLAGS_dryRun || FLAGS_veryVerbose) { + FLAGS_verbose = true; } -}; +#if SK_ENABLE_INST_COUNT + gPrintInstCount = FLAGS_leaks; +#endif -// 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); + SkTArray<SkString> configs; + for (int i = 0; i < FLAGS_config.count(); i++) { + SkStrSplit(FLAGS_config[i], ", ", &configs); } -} -/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + GrGLStandard gpuAPI = get_gl_standard(); -// Unit tests don't fit so well into the Src/Sink model, so we give them special treatment. + SkTDArray<GMRegistry::Factory> gms; + if (FLAGS_gms) { + append_matching_factories<GM>(GMRegistry::Head(), &gms); + } -static struct : public skiatest::Reporter { - void onReportFailed(const skiatest::Failure& failure) SK_OVERRIDE { - SkString s; - failure.getFailureString(&s); - fail(s); - JsonWriter::AddTestFailure(failure); + SkTDArray<TestRegistry::Factory> tests; + if (FLAGS_tests) { + append_matching_factories<Test>(TestRegistry::Head(), &tests); } - 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()) { - continue; - } - if (!test->isGPUTest() && !FLAGS_cpu) { - continue; - } - test->setReporter(&gTestReporter); - gTests.push_back().reset(test.detach()); + SkTArray<SkString> skps; + if (!FLAGS_skps.isEmpty()) { + const char* suffixes[] = { "skp" }; + find_files(FLAGS_skps[0], suffixes, SK_ARRAY_COUNT(suffixes), &skps); } -} -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())); - } + 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); } - timer.end(); - done(timer.fWall, "test", "", test->getName()); -} -/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -int dm_main(); -int dm_main() { - SetupCrashHandler(); - SkAutoGraphics ag; - SkTaskGroup::Enabler enabled(FLAGS_threads); + 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; - 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])); - } - } + 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(); - 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(); + DM::JsonWriter::DumpJson(); - if (!FLAGS_verbose) { - SkDebugf("\n"); + SkDebugf("\n"); +#ifdef SK_DEBUG + if (FLAGS_portableFonts && FLAGS_reportUsedChars) { + sk_tool_utils::report_used_chars(); } +#endif - JsonWriter::DumpJson(); - return gPending == 0 && gFailures == 0 ? 0 : 1; + SkTArray<SkString> failures; + reporter.getFailures(&failures); + report_failures(failures); + return failures.count() > 0; } #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |