1// Main binary for DM.
2// For a high-level overview, please see dm/README.
3
4#include "CrashHandler.h"
5#include "LazyDecodeBitmap.h"
6#include "SkCommonFlags.h"
7#include "SkForceLinking.h"
8#include "SkGraphics.h"
9#include "SkOSFile.h"
10#include "SkPicture.h"
11#include "SkString.h"
12#include "SkTaskGroup.h"
13#include "Test.h"
14#include "gm.h"
15#include "sk_tool_utils.h"
16#include "sk_tool_utils_flags.h"
17
18#include "DMCpuGMTask.h"
19#include "DMGpuGMTask.h"
20#include "DMGpuSupport.h"
21#include "DMPDFTask.h"
22#include "DMReporter.h"
23#include "DMSKPTask.h"
24#include "DMTask.h"
25#include "DMTaskRunner.h"
26#include "DMTestTask.h"
27#include "DMWriteTask.h"
28
29#ifdef SK_BUILD_POPPLER
30#  include "SkPDFRasterizer.h"
31#  define RASTERIZE_PDF_PROC SkPopplerRasterizePDF
32#else
33#  define RASTERIZE_PDF_PROC NULL
34#endif
35
36#include <ctype.h>
37
38using skiagm::GM;
39using skiagm::GMRegistry;
40using skiatest::Test;
41using skiatest::TestRegistry;
42
43static const char kGpuAPINameGL[] = "gl";
44static const char kGpuAPINameGLES[] = "gles";
45
46DEFINE_bool(gms, true, "Run GMs?");
47DEFINE_bool(tests, true, "Run tests?");
48DEFINE_bool(reportUsedChars, false, "Output test font construction data to be pasted into"
49                                    " create_test_font.cpp.");
50
51__SK_FORCE_IMAGE_DECODER_LINKING;
52
53// "FooBar" -> "foobar".  Obviously, ASCII only.
54static SkString lowercase(SkString s) {
55    for (size_t i = 0; i < s.size(); i++) {
56        s[i] = tolower(s[i]);
57    }
58    return s;
59}
60
61static const GrContextFactory::GLContextType native = GrContextFactory::kNative_GLContextType;
62static const GrContextFactory::GLContextType nvpr   = GrContextFactory::kNVPR_GLContextType;
63static const GrContextFactory::GLContextType null   = GrContextFactory::kNull_GLContextType;
64static const GrContextFactory::GLContextType debug  = GrContextFactory::kDebug_GLContextType;
65#if SK_ANGLE
66static const GrContextFactory::GLContextType angle  = GrContextFactory::kANGLE_GLContextType;
67#endif
68#if SK_MESA
69static const GrContextFactory::GLContextType mesa   = GrContextFactory::kMESA_GLContextType;
70#endif
71
72static void kick_off_gms(const SkTDArray<GMRegistry::Factory>& gms,
73                         const SkTArray<SkString>& configs,
74                         GrGLStandard gpuAPI,
75                         DM::Reporter* reporter,
76                         DM::TaskRunner* tasks) {
77#define START(name, type, ...)                                                              \
78    if (lowercase(configs[j]).equals(name)) {                                               \
79        tasks->add(SkNEW_ARGS(DM::type, (name, reporter, tasks, gms[i], ## __VA_ARGS__)));  \
80    }
81    for (int i = 0; i < gms.count(); i++) {
82        for (int j = 0; j < configs.count(); j++) {
83
84            START("565",        CpuGMTask, kRGB_565_SkColorType);
85            START("8888",       CpuGMTask, kN32_SkColorType);
86            START("gpu",        GpuGMTask, native, gpuAPI, 0);
87            START("msaa4",      GpuGMTask, native, gpuAPI, 4);
88            START("msaa16",     GpuGMTask, native, gpuAPI, 16);
89            START("nvprmsaa4",  GpuGMTask, nvpr,   gpuAPI, 4);
90            START("nvprmsaa16", GpuGMTask, nvpr,   gpuAPI, 16);
91            START("gpunull",    GpuGMTask, null,   gpuAPI, 0);
92            START("gpudebug",   GpuGMTask, debug,  gpuAPI, 0);
93#if SK_ANGLE
94            START("angle",      GpuGMTask, angle,  gpuAPI, 0);
95#endif
96#if SK_MESA
97            START("mesa",       GpuGMTask, mesa,   gpuAPI, 0);
98#endif
99            START("pdf",        PDFTask,   RASTERIZE_PDF_PROC);
100        }
101    }
102#undef START
103}
104
105static void kick_off_tests(const SkTDArray<TestRegistry::Factory>& tests,
106                           DM::Reporter* reporter,
107                           DM::TaskRunner* tasks) {
108    for (int i = 0; i < tests.count(); i++) {
109        SkAutoTDelete<Test> test(tests[i](NULL));
110        if (test->isGPUTest()) {
111            tasks->add(SkNEW_ARGS(DM::GpuTestTask, (reporter, tasks, tests[i])));
112        } else {
113            tasks->add(SkNEW_ARGS(DM::CpuTestTask, (reporter, tasks, tests[i])));
114        }
115    }
116}
117
118static void find_skps(SkTArray<SkString>* skps) {
119    if (FLAGS_skps.isEmpty()) {
120        return;
121    }
122
123    SkOSFile::Iter it(FLAGS_skps[0], ".skp");
124    SkString filename;
125    while (it.next(&filename)) {
126        if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) {
127            skps->push_back(SkOSPath::Join(FLAGS_skps[0], filename.c_str()));
128        }
129    }
130}
131
132static void kick_off_skps(const SkTArray<SkString>& skps,
133                          DM::Reporter* reporter,
134                          DM::TaskRunner* tasks) {
135    for (int i = 0; i < skps.count(); ++i) {
136        SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(skps[i].c_str()));
137        if (stream.get() == NULL) {
138            SkDebugf("Could not read %s.\n", skps[i].c_str());
139            exit(1);
140        }
141        SkAutoTUnref<SkPicture> pic(
142                SkPicture::CreateFromStream(stream.get(), &sk_tools::LazyDecodeBitmap));
143        if (pic.get() == NULL) {
144            SkDebugf("Could not read %s as an SkPicture.\n", skps[i].c_str());
145            exit(1);
146        }
147
148        SkString filename = SkOSPath::Basename(skps[i].c_str());
149        tasks->add(SkNEW_ARGS(DM::SKPTask, (reporter, tasks, pic, filename)));
150        tasks->add(SkNEW_ARGS(DM::PDFTask, (reporter, tasks, pic, filename, RASTERIZE_PDF_PROC)));
151    }
152}
153
154static void report_failures(const SkTArray<SkString>& failures) {
155    if (failures.count() == 0) {
156        return;
157    }
158
159    SkDebugf("Failures:\n");
160    for (int i = 0; i < failures.count(); i++) {
161        SkDebugf("  %s\n", failures[i].c_str());
162    }
163    SkDebugf("%d failures.\n", failures.count());
164}
165
166static GrGLStandard get_gl_standard() {
167  if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
168      return kGL_GrGLStandard;
169  }
170  if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
171      return kGLES_GrGLStandard;
172  }
173  return kNone_GrGLStandard;
174}
175
176template <typename T, typename Registry>
177static void append_matching_factories(Registry* head, SkTDArray<typename Registry::Factory>* out) {
178    for (const Registry* reg = head; reg != NULL; reg = reg->next()) {
179        SkAutoTDelete<T> forName(reg->factory()(NULL));
180        if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, forName->getName())) {
181            *out->append() = reg->factory();
182        }
183    }
184}
185
186int dm_main();
187int dm_main() {
188    SetupCrashHandler();
189    SkAutoGraphics ag;
190    SkTaskGroup::Enabler enabled(FLAGS_threads);
191
192    if (FLAGS_dryRun) {
193        FLAGS_verbose = true;
194    }
195#if SK_ENABLE_INST_COUNT
196    gPrintInstCount = FLAGS_leaks;
197#endif
198
199    SkTArray<SkString> configs;
200    for (int i = 0; i < FLAGS_config.count(); i++) {
201        SkStrSplit(FLAGS_config[i], ", ", &configs);
202    }
203
204    GrGLStandard gpuAPI = get_gl_standard();
205
206    SkTDArray<GMRegistry::Factory> gms;
207    if (FLAGS_gms) {
208        append_matching_factories<GM>(GMRegistry::Head(), &gms);
209    }
210
211    SkTDArray<TestRegistry::Factory> tests;
212    if (FLAGS_tests) {
213        append_matching_factories<Test>(TestRegistry::Head(), &tests);
214    }
215
216    SkTArray<SkString> skps;
217    find_skps(&skps);
218
219    SkDebugf("%d GMs x %d configs, %d tests, %d pictures\n",
220             gms.count(), configs.count(), tests.count(), skps.count());
221    DM::Reporter reporter;
222
223    DM::TaskRunner tasks;
224    kick_off_tests(tests, &reporter, &tasks);
225    kick_off_gms(gms, configs, gpuAPI, &reporter, &tasks);
226    kick_off_skps(skps, &reporter, &tasks);
227    tasks.wait();
228
229    DM::WriteTask::DumpJson();
230
231    SkDebugf("\n");
232#ifdef SK_DEBUG
233    if (FLAGS_portableFonts && FLAGS_reportUsedChars) {
234        sk_tool_utils::report_used_chars();
235    }
236#endif
237
238    SkTArray<SkString> failures;
239    reporter.getFailures(&failures);
240    report_failures(failures);
241    return failures.count() > 0;
242}
243
244#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
245int main(int argc, char** argv) {
246    SkCommandLineFlags::Parse(argc, argv);
247    return dm_main();
248}
249#endif
250