1 /*
2 * Copyright 2018 Google Inc.
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
8 #include "tools/skqp/src/skqp.h"
9
10 #include "gm/gm.h"
11 #include "include/core/SkGraphics.h"
12 #include "include/core/SkStream.h"
13 #include "include/core/SkSurface.h"
14 #include "include/gpu/ganesh/GrContextOptions.h"
15 #include "include/gpu/ganesh/GrDirectContext.h"
16 #include "src/core/SkOSFile.h"
17 #include "src/utils/SkOSPath.h"
18 #include "tests/CtsEnforcement.h"
19 #include "tests/Test.h"
20 #include "tests/TestHarness.h"
21 #include "tools/Resources.h"
22 #include "tools/fonts/FontToolUtils.h"
23 #ifdef SK_GL
24 #include "tools/gpu/gl/GLTestContext.h"
25 #endif
26 #ifdef SK_VULKAN
27 #include "tools/gpu/vk/VkTestContext.h"
28 #endif
29
30 #ifdef SK_GRAPHITE
31 #include "tools/graphite/TestOptions.h"
32 #endif
33
34 #ifdef SK_BUILD_FOR_ANDROID
35 #include <sys/system_properties.h>
36 #endif
37
38 #include <algorithm>
39 #include <regex>
40
41 static constexpr char kUnitTestReportPath[] = "unit_tests.txt";
42
43 // Returns a list of every unit test to be run.
get_unit_tests(int enforcedAndroidAPILevel)44 static std::vector<SkQP::UnitTest> get_unit_tests(int enforcedAndroidAPILevel) {
45 std::vector<SkQP::UnitTest> unitTests;
46 for (const skiatest::Test& test : skiatest::TestRegistry::Range()) {
47 const auto ctsMode = test.fCTSEnforcement.eval(enforcedAndroidAPILevel);
48 if (ctsMode != CtsEnforcement::RunMode::kSkip) {
49 SkASSERTF(test.fTestType != skiatest::TestType::kCPU,
50 "Non-GPU test was included in SkQP: %s\n", test.fName);
51 unitTests.push_back(&test);
52 }
53 }
54 auto lt = [](SkQP::UnitTest u, SkQP::UnitTest v) { return strcmp(u->fName, v->fName) < 0; };
55 std::sort(unitTests.begin(), unitTests.end(), lt);
56 return unitTests;
57 }
58
59 /**
60 * SkSL error tests are used by CTS to verify that Android's RuntimeShader API fails when certain
61 * shader programs are compiled. Unlike unit tests these error tests are defined in resource files
62 * not source code. As such, we are unable to mark each test with a CtsEnforcement value. This
63 * list of exclusion rules excludes tests based on their file name so that we can have some form of
64 * control for which Android version an SkSL error test is expected to run.
65 */
66 static const std::pair<std::regex, CtsEnforcement> sExclusionRulesForSkSLTests[] = {
67 // disable all ES3 tests until AGSL supports it.
68 {std::regex(".*ES3.*"), CtsEnforcement::kNever}};
69
70 // Returns a list of every SkSL error test to be run.
get_sksl_error_tests(SkQPAssetManager * assetManager,int enforcedAndroidAPILevel)71 static std::vector<SkQP::SkSLErrorTest> get_sksl_error_tests(SkQPAssetManager* assetManager,
72 int enforcedAndroidAPILevel) {
73 std::vector<SkQP::SkSLErrorTest> skslErrorTests;
74 auto iterateFn = [&](const char* directory, const char* extension) {
75 std::vector<std::string> paths = assetManager->iterateDir(directory, extension);
76 for (const std::string& path : paths) {
77 SkString name = SkOSPath::Basename(path.c_str());
78 for (auto& exclusionEntry : sExclusionRulesForSkSLTests) {
79 if (std::regex_match(name.c_str(), exclusionEntry.first) &&
80 exclusionEntry.second.eval(enforcedAndroidAPILevel) ==
81 CtsEnforcement::RunMode::kSkip) {
82 continue;
83 }
84 }
85 sk_sp<SkData> shaderText = GetResourceAsData(path.c_str());
86 if (!shaderText) {
87 continue;
88 }
89 skslErrorTests.push_back({
90 name.c_str(),
91 std::string(static_cast<const char*>(shaderText->data()), shaderText->size())
92 });
93 }
94 };
95
96 // Android only supports runtime shaders, not fragment shaders, color filters or blenders.
97 iterateFn("sksl/errors/", ".rts");
98 iterateFn("sksl/runtime_errors/", ".rts");
99
100 auto lt = [](const SkQP::SkSLErrorTest& a, const SkQP::SkSLErrorTest& b) {
101 return a.name < b.name;
102 };
103 std::sort(skslErrorTests.begin(), skslErrorTests.end(), lt);
104 return skslErrorTests;
105 }
106
107 ////////////////////////////////////////////////////////////////////////////////
108
CurrentTestHarness()109 TestHarness CurrentTestHarness() {
110 return TestHarness::kSkQP;
111 }
112
113 ////////////////////////////////////////////////////////////////////////////////
114
GetUnitTestName(SkQP::UnitTest t)115 const char* SkQP::GetUnitTestName(SkQP::UnitTest t) { return t->fName; }
116
SkQP()117 SkQP::SkQP() {}
118
~SkQP()119 SkQP::~SkQP() {}
120
init(SkQPAssetManager * assetManager,const char * reportDirectory)121 void SkQP::init(SkQPAssetManager* assetManager, const char* reportDirectory) {
122 SkASSERT_RELEASE(assetManager);
123 fReportDirectory = reportDirectory;
124
125 SkGraphics::Init();
126 ToolUtils::UsePortableFontMgr();
127
128 #ifdef SK_BUILD_FOR_ANDROID
129 // This is defined by the AllSkQPTestCases test module in the Android framework, which runs all
130 // tests that are included in SkQP, regardless of the device's actual vendor API level (excluding
131 // those marked with kNever). This is used for ensuring testing coverage, and isn't enforced in CTS.
132 #ifdef SKQP_ENFORCE_ALL_INCLUDED_TESTS
133 fEnforcedAndroidAPILevel = CtsEnforcement::kNextRelease;
134 #else
135 // ro.vendor.api_level contains the minAPI level based on the order defined in
136 // docs.partner.android.com/gms/building/integrating/extending-os-upgrade-support-windows
137 // 1. board's current api level (for boards that have been upgraded by the SoC vendor)
138 // 2. board's first api level (for devices that initially shipped with an older version)
139 // 3. product's first api level
140 // 4. product's current api level
141 char minAPIVersionStr[PROP_VALUE_MAX];
142 int strLength = __system_property_get("ro.vendor.api_level", minAPIVersionStr);
143 if (strLength != 0) {
144 fEnforcedAndroidAPILevel = atoi(minAPIVersionStr);
145 }
146 #endif // SKQP_ENFORCE_ALL_INCLUDED_TESTS
147 #endif // SK_BUILD_FOR_ANDROID
148
149 SkDebugf("Gathering tests enforced for ro.vendor.api_level: %d", fEnforcedAndroidAPILevel);
150 fUnitTests = get_unit_tests(fEnforcedAndroidAPILevel);
151 fSkSLErrorTests = get_sksl_error_tests(assetManager, fEnforcedAndroidAPILevel);
152
153 printBackendInfo((fReportDirectory + "/grdump.txt").c_str());
154 }
155
executeTest(SkQP::UnitTest test)156 std::vector<std::string> SkQP::executeTest(SkQP::UnitTest test) {
157 struct : public skiatest::Reporter {
158 std::vector<std::string> fErrors;
159 void reportFailed(const skiatest::Failure& failure) override {
160 SkString desc = failure.toString();
161 fErrors.push_back(std::string(desc.c_str(), desc.size()));
162 }
163 } r;
164
165 if (test->fTestType == skiatest::TestType::kGanesh) {
166 GrContextOptions options;
167 if (test->fCTSEnforcement.eval(fEnforcedAndroidAPILevel) ==
168 CtsEnforcement::RunMode::kRunStrict) {
169 options.fDisableDriverCorrectnessWorkarounds = true;
170 }
171 if (test->fGaneshContextOptionsProc) {
172 test->fGaneshContextOptionsProc(&options);
173 }
174 test->ganesh(&r, options);
175 }
176 #ifdef SK_GRAPHITE
177 else if (test->fTestType == skiatest::TestType::kGraphite) {
178 skiatest::graphite::TestOptions options;
179 if (test->fCTSEnforcement.eval(fEnforcedAndroidAPILevel) ==
180 CtsEnforcement::RunMode::kRunStrict) {
181 options.fContextOptions.fDisableDriverCorrectnessWorkarounds = true;
182 }
183 if (test->fGraphiteContextOptionsProc) {
184 test->fGraphiteContextOptionsProc(&options.fContextOptions);
185 }
186 test->graphite(&r, options);
187 }
188 #endif
189
190 fTestResults.push_back(TestResult{test->fName, r.fErrors});
191 return r.fErrors;
192 }
193
194 ////////////////////////////////////////////////////////////////////////////////
195
196 template <typename T>
write(SkWStream * wStream,const T & text)197 inline void write(SkWStream* wStream, const T& text) {
198 wStream->write(text.c_str(), text.size());
199 }
200
makeReport()201 void SkQP::makeReport() {
202 if (!sk_isdir(fReportDirectory.c_str())) {
203 SkDebugf("Report destination does not exist: '%s'\n", fReportDirectory.c_str());
204 return;
205 }
206 SkFILEWStream report(SkOSPath::Join(fReportDirectory.c_str(), kUnitTestReportPath).c_str());
207 SkASSERT_RELEASE(report.isValid());
208 for (const SkQP::TestResult& result : fTestResults) {
209 report.writeText(result.name.c_str());
210 if (result.errors.empty()) {
211 report.writeText(" PASSED\n* * *\n");
212 } else {
213 write(&report, SkStringPrintf(" FAILED (%zu errors)\n", result.errors.size()));
214 for (const std::string& err : result.errors) {
215 write(&report, err);
216 report.newline();
217 }
218 report.writeText("* * *\n");
219 }
220 }
221 }
222