1 // Main binary for DM. 2 // For a high-level overview, please see dm/README. 3 4 #include "GrContext.h" 5 #include "GrContextFactory.h" 6 #include "SkCommandLineFlags.h" 7 #include "SkForceLinking.h" 8 #include "SkGraphics.h" 9 #include "SkString.h" 10 #include "gm.h" 11 12 #include "DMReporter.h" 13 #include "DMTask.h" 14 #include "DMTaskRunner.h" 15 #include "DMCpuTask.h" 16 #include "DMGpuTask.h" 17 #include "DMWriteTask.h" 18 19 #include <string.h> 20 21 using skiagm::GM; 22 using skiagm::GMRegistry; 23 24 DEFINE_int32(cpuThreads, -1, "Threads for CPU work. Default NUM_CPUS."); 25 DEFINE_int32(gpuThreads, 1, "Threads for GPU work."); 26 DEFINE_string2(expectations, r, "", 27 "If a directory, compare generated images against images under this path. " 28 "If a file, compare generated images against JSON expectations at this path."); 29 DEFINE_string(resources, "resources", "Path to resources directory."); 30 DEFINE_string(match, "", "[~][^]substring[$] [...] of GM name to run.\n" 31 "Multiple matches may be separated by spaces.\n" 32 "~ causes a matching GM to always be skipped\n" 33 "^ requires the start of the GM to match\n" 34 "$ requires the end of the GM to match\n" 35 "^ and $ requires an exact match\n" 36 "If a GM does not match any list entry,\n" 37 "it is skipped unless some list entry starts with ~"); 38 DEFINE_string(config, "8888 gpu", 39 "Options: 565 8888 gpu msaa4 msaa16 gpunull gpudebug angle mesa"); // TODO(mtklein): pdf 40 41 __SK_FORCE_IMAGE_DECODER_LINKING; 42 43 // "FooBar" -> "foobar". Obviously, ASCII only. 44 static SkString lowercase(SkString s) { 45 for (size_t i = 0; i < s.size(); i++) { 46 s[i] = tolower(s[i]); 47 } 48 return s; 49 } 50 51 static void kick_off_tasks(const SkTDArray<GMRegistry::Factory>& gms, 52 const SkTArray<SkString>& configs, 53 const DM::Expectations& expectations, 54 DM::Reporter* reporter, 55 DM::TaskRunner* tasks) { 56 const SkBitmap::Config _565 = SkBitmap::kRGB_565_Config; 57 const SkBitmap::Config _8888 = SkBitmap::kARGB_8888_Config; 58 const GrContextFactory::GLContextType native = GrContextFactory::kNative_GLContextType; 59 const GrContextFactory::GLContextType null = GrContextFactory::kNull_GLContextType; 60 const GrContextFactory::GLContextType debug = GrContextFactory::kDebug_GLContextType; 61 const GrContextFactory::GLContextType angle = 62 #if SK_ANGLE 63 GrContextFactory::kANGLE_GLContextType; 64 #else 65 native; 66 #endif 67 const GrContextFactory::GLContextType mesa = 68 #if SK_MESA 69 GLContextFactory::kMESA_GLContextType; 70 #else 71 native; 72 #endif 73 74 for (int i = 0; i < gms.count(); i++) { 75 #define START(name, type, ...) \ 76 if (lowercase(configs[j]).equals(name)) { \ 77 tasks->add(SkNEW_ARGS(DM::type, \ 78 (name, reporter, tasks, expectations, gms[i], __VA_ARGS__))); \ 79 } 80 for (int j = 0; j < configs.count(); j++) { 81 START("565", CpuTask, _565); 82 START("8888", CpuTask, _8888); 83 START("gpu", GpuTask, _8888, native, 0); 84 START("msaa4", GpuTask, _8888, native, 4); 85 START("msaa16", GpuTask, _8888, native, 16); 86 START("gpunull", GpuTask, _8888, null, 0); 87 START("gpudebug", GpuTask, _8888, debug, 0); 88 START("angle", GpuTask, _8888, angle, 0); 89 START("mesa", GpuTask, _8888, mesa, 0); 90 //START("pdf", PdfTask, _8888); 91 } 92 } 93 #undef START 94 } 95 96 static void report_failures(const DM::Reporter& reporter) { 97 SkTArray<SkString> failures; 98 reporter.getFailures(&failures); 99 100 if (failures.count() == 0) { 101 return; 102 } 103 104 SkDebugf("Failures:\n"); 105 for (int i = 0; i < failures.count(); i++) { 106 SkDebugf(" %s\n", failures[i].c_str()); 107 } 108 } 109 110 int tool_main(int argc, char** argv); 111 int tool_main(int argc, char** argv) { 112 SkGraphics::Init(); 113 114 SkCommandLineFlags::Parse(argc, argv); 115 GM::SetResourcePath(FLAGS_resources[0]); 116 SkTArray<SkString> configs; 117 for (int i = 0; i < FLAGS_config.count(); i++) { 118 SkStrSplit(FLAGS_config[i], ", ", &configs); 119 } 120 121 SkTDArray<GMRegistry::Factory> gms; 122 for (const GMRegistry* reg = GMRegistry::Head(); reg != NULL; reg = reg->next()) { 123 SkAutoTDelete<GM> gmForName(reg->factory()(NULL)); 124 if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gmForName->shortName())) { 125 *gms.append() = reg->factory(); 126 } 127 } 128 SkDebugf("%d GMs x %d configs\n", gms.count(), configs.count()); 129 130 SkAutoTDelete<DM::Expectations> expectations(SkNEW(DM::NoExpectations)); 131 if (FLAGS_expectations.count() > 0) { 132 const char* path = FLAGS_expectations[0]; 133 if (sk_isdir(path)) { 134 expectations.reset(SkNEW_ARGS(DM::WriteTask::Expectations, (path))); 135 } else { 136 expectations.reset(SkNEW_ARGS(DM::JsonExpectations, (path))); 137 } 138 } 139 140 DM::Reporter reporter; 141 DM::TaskRunner tasks(FLAGS_cpuThreads, FLAGS_gpuThreads); 142 kick_off_tasks(gms, configs, *expectations, &reporter, &tasks); 143 tasks.wait(); 144 145 reporter.updateStatusLine(); 146 SkDebugf("\n"); 147 report_failures(reporter); 148 149 SkGraphics::Term(); 150 151 return reporter.failed() > 0; 152 } 153 154 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) 155 int main(int argc, char** argv) { 156 return tool_main(argc, argv); 157 } 158 #endif 159