1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 *
7 * This runs *all* the tests registered via the Test registry in series. If one or more fail, those
8 * error messages will be printed out and a non-zero exit code will be returned. Otherwise, the
9 * exit code will be 0.
10 */
11
12 #include "include/core/SkString.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/base/SkDebug.h"
15 #include "tests/Test.h"
16 #include "tests/TestHarness.h"
17 #include "tools/flags/CommandLineFlags.h"
18 #include "tools/testrunners/common/TestRunner.h"
19
20 #if defined(SK_GANESH)
21 #include "include/gpu/ganesh/GrContextOptions.h"
22 #include "include/gpu/ganesh/GrDirectContext.h"
23 #include "include/gpu/ganesh/GrTypes.h"
24 #include "include/private/gpu/ganesh/GrTypesPriv.h"
25 #include "tools/gpu/ContextType.h"
26 #include "tools/gpu/TestContext.h"
27 #endif
28
29 #include <ctime>
30 #include <cwchar>
31 #include <functional>
32 #include <iomanip>
33 #include <sstream>
34 #include <string>
35
36 struct tm;
37
38 static DEFINE_string(skip, "", "Space-separated list of test cases (regexps) to skip.");
39 static DEFINE_string(
40 match,
41 "",
42 "Space-separated list of test cases (regexps) to run. Will run all tests if omitted.");
43
44 // Set in //bazel/devicesrc but consumed by other C++ test runners.
45 static DEFINE_string(key, "", "Ignored by this test runner.");
46 static DEFINE_string(cpuName, "", "Ignored by this test runner.");
47 static DEFINE_string(gpuName, "", "Ignored by this test runner.");
48
49 // Set in //bazel/devicesrc but only consumed by adb_test_runner.go. We cannot use the
50 // DEFINE_string macro because the flag name includes dashes.
51 [[maybe_unused]] static bool unused =
52 SkFlagInfo::CreateStringFlag("device-specific-bazel-config",
53 nullptr,
54 new CommandLineFlags::StringArray(),
55 nullptr,
56 "Ignored by this test runner.",
57 nullptr);
58
59 class BazelReporter : public skiatest::Reporter {
60 public:
reportFailed(const skiatest::Failure & failure)61 void reportFailed(const skiatest::Failure& failure) override {
62 TestRunner::Log("FAIL: %s", failure.toString().c_str());
63 fFailed = true;
64 }
allowExtendedTest() const65 bool allowExtendedTest() const override { return false; }
verbose() const66 bool verbose() const override { return false; }
ok()67 bool ok() { return !fFailed; }
68
69 private:
70 bool fFailed = false;
71 };
72
73 #if defined(SK_GANESH)
74 namespace skiatest {
IsGLContextType(skgpu::ContextType type)75 bool IsGLContextType(skgpu::ContextType type) {
76 return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kOpenGL;
77 }
IsVulkanContextType(skgpu::ContextType type)78 bool IsVulkanContextType(skgpu::ContextType type) {
79 return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kVulkan;
80 }
IsMetalContextType(skgpu::ContextType type)81 bool IsMetalContextType(skgpu::ContextType type) {
82 return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kMetal;
83 }
IsDirect3DContextType(skgpu::ContextType type)84 bool IsDirect3DContextType(skgpu::ContextType type) {
85 return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kDirect3D;
86 }
IsMockContextType(skgpu::ContextType type)87 bool IsMockContextType(skgpu::ContextType type) { return type == skgpu::ContextType::kMock; }
88
89 skgpu::ContextType compiledInContextTypes[] = {
90 #if defined(SK_GL)
91 // Use "native" instead of explicitly trying both OpenGL and OpenGL ES. Do not use GLES on
92 // desktop since tests do not account for not fixing http://skbug.com/2809
93 #if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
94 skgpu::ContextType::kGL,
95 #else
96 skgpu::ContextType::kGLES,
97 #endif
98 #endif // defined(SK_GL)
99 #if defined(SK_VULKAN)
100 skgpu::ContextType::kVulkan,
101 #endif
102 #if defined(SK_DAWN)
103 skgpu::ContextType::kDawn,
104 #endif
105 // TODO(kjlubick) Other Ganesh backends
106 skgpu::ContextType::kMock,
107 };
108
109 // The macros defined in Test.h eventually call into this function. For each GPU backend that is
110 // compiled in, we run the testFn with a freshly created
RunWithGaneshTestContexts(GrContextTestFn * testFn,ContextTypeFilterFn * filter,Reporter * reporter,const GrContextOptions & options)111 void RunWithGaneshTestContexts(GrContextTestFn* testFn,
112 ContextTypeFilterFn* filter,
113 Reporter* reporter,
114 const GrContextOptions& options) {
115 sk_gpu_test::GrContextFactory factory(options);
116
117 for (skgpu::ContextType ctxType : compiledInContextTypes) {
118 if (filter && !(*filter)(ctxType)) {
119 continue;
120 }
121
122 sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(ctxType);
123 if (ctxInfo.directContext()) {
124 (*testFn)(reporter, ctxInfo);
125 // In case the test changed the current context make sure we move it back before
126 // calling flush.
127 ctxInfo.testContext()->makeCurrent();
128 // Sync so any release/finished procs get called.
129 ctxInfo.directContext()->flushAndSubmit(GrSyncCpu::kYes);
130 } else {
131 TestRunner::Log("Unable to make direct context for Ganesh test.");
132 SkASSERT(false);
133 return;
134 }
135 }
136 }
137
138 } // namespace skiatest
139 #endif // #if defined(SK_GANESH)
140
CurrentTestHarness()141 TestHarness CurrentTestHarness() { return TestHarness::kBazelUnitTestRunner; }
142
maybeRunTest(const char * name,std::function<void ()> testFn)143 void maybeRunTest(const char* name, std::function<void()> testFn) {
144 if (!TestRunner::ShouldRunTestCase(name, FLAGS_match, FLAGS_skip)) {
145 TestRunner::Log("Skipping %s", name);
146 return;
147 }
148
149 TestRunner::Log("Running %s", name);
150 testFn();
151 TestRunner::Log("\tDone");
152 }
153
main(int argc,char ** argv)154 int main(int argc, char** argv) {
155 TestRunner::InitAndLogCmdlineArgs(argc, argv);
156
157 CommandLineFlags::Parse(argc, argv);
158
159 BazelReporter reporter;
160 for (skiatest::Test test : skiatest::TestRegistry::Range()) {
161 if (test.fTestType == skiatest::TestType::kCPU) {
162 maybeRunTest(test.fName, [&]() { test.cpu(&reporter); });
163 }
164 }
165
166 #if defined(SK_GANESH)
167 GrContextOptions grCtxOptions;
168 // TODO(kjlubick) DM has grContextOptions set via flags. Should this runner have that too?
169 grCtxOptions.fExecutor = nullptr;
170 grCtxOptions.fAllowPathMaskCaching = true;
171 grCtxOptions.fFailFlushTimeCallbacks = false;
172 grCtxOptions.fAllPathsVolatile = false;
173 grCtxOptions.fGpuPathRenderers = GpuPathRenderers::kDefault;
174 grCtxOptions.fDisableDriverCorrectnessWorkarounds = false;
175 grCtxOptions.fResourceCacheLimitOverride = -1;
176 grCtxOptions.fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo;
177 for (skiatest::Test test : skiatest::TestRegistry::Range()) {
178 if (test.fTestType == skiatest::TestType::kGanesh) {
179 maybeRunTest(test.fName, [&]() { test.ganesh(&reporter, grCtxOptions); });
180 }
181 }
182 #endif
183
184 // TODO(kjlubick) Graphite support
185
186 if (reporter.ok()) {
187 TestRunner::Log("PASS");
188 return 0;
189 }
190 TestRunner::Log("FAIL");
191 return 1;
192 }
193