xref: /aosp_15_r20/external/skia/tools/skqp/src/skqp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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