Index: dm/DM.cpp |
diff --git a/dm/DM.cpp b/dm/DM.cpp |
index d8efc5844812f9b3d8637aa2aad21f3eb571f5e4..7113ad839a02e4e61cc028adf608c389e389edea 100644 |
--- a/dm/DM.cpp |
+++ b/dm/DM.cpp |
@@ -1,384 +1,222 @@ |
+// 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 |
+ |
+#include <ctype.h> |
+ |
+using skiagm::GM; |
+using skiagm::GMRegistry; |
+using skiatest::Test; |
+using skiatest::TestRegistry; |
+ |
+static const char kGpuAPINameGL[] = "gl"; |
+static const char kGpuAPINameGLES[] = "gles"; |
+ |
+DEFINE_bool(gms, true, "Run GMs?"); |
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."); |
+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_FORCE_IMAGE_DECODER_LINKING; |
-using namespace DM; |
- |
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
- |
-static int gPending = 0, gFailures = 0; |
- |
-static void fail(ImplicitString err) { |
- SkDebugf("\n\nERROR: %s\n\n", err.c_str()); |
- sk_atomic_inc(&gFailures); |
-} |
- |
-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()); |
-} |
- |
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
- |
-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; |
- } |
-} |
- |
-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()))); |
- } |
- } |
- 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 DM::RasterizePdfProc get_pdf_rasterizer_proc() { |
+ return reinterpret_cast<DM::RasterizePdfProc>( |
+ FLAGS_rasterPDF ? RASTERIZE_PDF_PROC : NULL); |
+} |
+ |
+// "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 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__))); \ |
+ } |
+ 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 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 find_files(const char* dir, |
+ const char* suffixes[], |
+ size_t num_suffixes, |
+ SkTArray<SkString>* files) { |
+ if (0 == strcmp(dir, "")) { |
+ 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())); |
} |
} |
} |
} |
-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)) { |
+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); |
+ } |
+ |
+ 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); |
+ } |
+ 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*/))); |
+ } |
+} |
+ |
+ |
+static void report_failures(const SkTArray<SkString>& failures) { |
+ if (failures.count() == 0) { |
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; |
- } |
- |
- 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 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); |
- } |
- } |
-} |
- |
-// 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); |
- } |
- } |
- } |
- 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; |
- } |
- |
- 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; |
- } |
- } |
- } |
-}; |
- |
-// 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); |
- } |
-} |
- |
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
- |
-// 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()) { |
- continue; |
- } |
- if (!test->isGPUTest() && !FLAGS_cpu) { |
- continue; |
- } |
- test->setReporter(&gTestReporter); |
- gTests.push_back().reset(test.detach()); |
- } |
-} |
- |
-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, "test", "", test->getName()); |
-} |
- |
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
+ |
+ SkDebugf("Failures:\n"); |
+ for (int i = 0; i < failures.count(); i++) { |
+ SkDebugf(" %s\n", failures[i].c_str()); |
+ } |
+ 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; |
+} |
+ |
+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(); |
+ } |
+ } |
+} |
int dm_main(); |
int dm_main() { |
@@ -386,38 +224,70 @@ |
SkAutoGraphics ag; |
SkTaskGroup::Enabler enabled(FLAGS_threads); |
- 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])); |
- } |
- } |
- |
- 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(); |
- |
- if (!FLAGS_verbose) { |
- SkDebugf("\n"); |
- } |
- |
- JsonWriter::DumpJson(); |
- return gPending == 0 && gFailures == 0 ? 0 : 1; |
+ 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); |
+ } |
+ |
+ GrGLStandard gpuAPI = get_gl_standard(); |
+ |
+ SkTDArray<GMRegistry::Factory> gms; |
+ if (FLAGS_gms) { |
+ append_matching_factories<GM>(GMRegistry::Head(), &gms); |
+ } |
+ |
+ SkTDArray<TestRegistry::Factory> tests; |
+ if (FLAGS_tests) { |
+ append_matching_factories<Test>(TestRegistry::Head(), &tests); |
+ } |
+ |
+ |
+ 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); |
+ } |
+ |
+ 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(); |
+ } |
+#endif |
+ |
+ SkTArray<SkString> failures; |
+ reporter.getFailures(&failures); |
+ report_failures(failures); |
+ return failures.count() > 0; |
} |
#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |