| 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)
|
|
|