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