• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 "gm_runner.h"
9 
10 #include <algorithm>
11 
12 #include "../tools/fonts/SkTestFontMgr.h"
13 #include "GrContext.h"
14 #include "GrContextOptions.h"
15 #include "SkFontMgrPriv.h"
16 #include "SkFontStyle.h"
17 #include "SkGraphics.h"
18 #include "SkImageInfoPriv.h"
19 #include "SkSurface.h"
20 #include "Test.h"
21 #include "gl/GLTestContext.h"
22 #include "gm.h"
23 #include "gm_knowledge.h"
24 #include "vk/VkTestContext.h"
25 
26 static SkTHashSet<SkString> gDoNotScoreInCompatibilityTestMode;
27 static SkTHashSet<SkString> gDoNotExecuteInExperimentalMode;
28 static SkTHashSet<SkString> gKnownGpuUnitTests;
29 static SkTHashSet<SkString> gKnownGMs;
30 static gm_runner::Mode gMode = gm_runner::Mode::kCompatibilityTestMode;
31 
is_empty(const SkTHashSet<SkString> & set)32 static bool is_empty(const SkTHashSet<SkString>& set) {
33     return 0 == set.count();
34 }
in_set(const char * s,const SkTHashSet<SkString> & set)35 static bool in_set(const char* s, const SkTHashSet<SkString>& set) {
36     return !is_empty(set) && nullptr != set.find(SkString(s));
37 }
38 
readlist(skqp::AssetManager * mgr,const char * path,SkTHashSet<SkString> * dst)39 static void readlist(skqp::AssetManager* mgr, const char* path, SkTHashSet<SkString>* dst) {
40     auto asset = mgr->open(path);
41     if (!asset || asset->getLength() == 0) {
42         return;  // missing file same as empty file.
43     }
44     std::vector<char> buffer(asset->getLength() + 1);
45     asset->read(buffer.data(), buffer.size());
46     buffer.back() = '\0';
47     const char* ptr = buffer.data();
48     const char* end = &buffer.back();
49     SkASSERT(ptr < end);
50     while (true) {
51         while (*ptr == '\n' && ptr < end) {
52             ++ptr;
53         }
54         if (ptr == end) {
55             return;
56         }
57         const char* find = strchr(ptr, '\n');
58         if (!find) {
59             find = end;
60         }
61         SkASSERT(find > ptr);
62         dst->add(SkString(ptr, find - ptr));
63         ptr = find;
64     }
65 }
66 
67 namespace gm_runner {
68 
GetErrorString(Error e)69 const char* GetErrorString(Error e) {
70     switch (e) {
71         case Error::None:          return "";
72         case Error::BadSkiaOutput: return "Bad Skia Output";
73         case Error::BadGMKBData:   return "Bad GMKB Data";
74         case Error::SkiaFailure:   return "Skia Failure";
75         default:                   SkASSERT(false);
76                                    return "unknown";
77     }
78 }
79 
ExecuteTest(UnitTest test)80 std::vector<std::string> ExecuteTest(UnitTest test) {
81     struct : public skiatest::Reporter {
82         std::vector<std::string> fErrors;
83         void reportFailed(const skiatest::Failure& failure) override {
84             SkString desc = failure.toString();
85             fErrors.push_back(std::string(desc.c_str(), desc.size()));
86         }
87     } r;
88     GrContextOptions options;
89     // options.fDisableDriverCorrectnessWorkarounds = true;
90     if (test->fContextOptionsProc) {
91         test->fContextOptionsProc(&options);
92     }
93     test->proc(&r, options);
94     return std::move(r.fErrors);
95 }
96 
GetUnitTestName(UnitTest test)97 const char* GetUnitTestName(UnitTest test) { return test->name; }
98 
GetUnitTests()99 std::vector<UnitTest> GetUnitTests() {
100     std::vector<UnitTest> tests;
101     for (const skiatest::TestRegistry* r = skiatest::TestRegistry::Head(); r; r = r->next()) {
102         const skiatest::Test& test = r->factory();
103         if ((is_empty(gKnownGpuUnitTests) || in_set(test.name, gKnownGpuUnitTests))
104             && test.needsGpu) {
105             tests.push_back(&test);
106         }
107     }
108     struct {
109         bool operator()(UnitTest u, UnitTest v) const { return strcmp(u->name, v->name) < 0; }
110     } less;
111     std::sort(tests.begin(), tests.end(), less);
112     return tests;
113 }
114 
GetBackendName(SkiaBackend backend)115 const char* GetBackendName(SkiaBackend backend) {
116     switch (backend) {
117         case SkiaBackend::kGL:     return "gl";
118         case SkiaBackend::kGLES:   return "gles";
119         case SkiaBackend::kVulkan: return "vk";
120         default:                   SkASSERT(false);
121                                    return "error";
122     }
123 }
124 
make_test_context(SkiaBackend backend)125 static std::unique_ptr<sk_gpu_test::TestContext> make_test_context(SkiaBackend backend) {
126     using U = std::unique_ptr<sk_gpu_test::TestContext>;
127     switch (backend) {
128         case SkiaBackend::kGL:
129             return U(sk_gpu_test::CreatePlatformGLTestContext(kGL_GrGLStandard, nullptr));
130         case SkiaBackend::kGLES:
131             return U(sk_gpu_test::CreatePlatformGLTestContext(kGLES_GrGLStandard, nullptr));
132 #ifdef SK_VULKAN
133         case SkiaBackend::kVulkan:
134             return U(sk_gpu_test::CreatePlatformVkTestContext(nullptr));
135 #endif
136         default:
137             return nullptr;
138     }
139 }
140 
context_options(skiagm::GM * gm=nullptr)141 static GrContextOptions context_options(skiagm::GM* gm = nullptr) {
142     GrContextOptions grContextOptions;
143     grContextOptions.fAllowPathMaskCaching = true;
144     grContextOptions.fSuppressPathRendering = true;
145     #ifndef SK_SKQP_ENABLE_DRIVER_CORRECTNESS_WORKAROUNDS
146     grContextOptions.fDisableDriverCorrectnessWorkarounds = true;
147     #endif
148     if (gm) {
149         gm->modifyGrContextOptions(&grContextOptions);
150     }
151     return grContextOptions;
152 }
153 
GetSupportedBackends()154 std::vector<SkiaBackend> GetSupportedBackends() {
155     std::vector<SkiaBackend> result;
156     SkiaBackend backends[] = {
157         #ifndef SK_BUILD_FOR_ANDROID
158         SkiaBackend::kGL,  // Used for testing on desktop machines.
159         #endif
160         SkiaBackend::kGLES,
161         SkiaBackend::kVulkan,
162     };
163     for (SkiaBackend backend : backends) {
164         std::unique_ptr<sk_gpu_test::TestContext> testCtx = make_test_context(backend);
165         if (testCtx) {
166             testCtx->makeCurrent();
167             if (nullptr != testCtx->makeGrContext(context_options())) {
168                 result.push_back(backend);
169             }
170         }
171     }
172     SkASSERT_RELEASE(result.size() > 0);
173     return result;
174 }
175 
evaluate_gm(SkiaBackend backend,skiagm::GM * gm,int * width,int * height,std::vector<uint32_t> * storage)176 static bool evaluate_gm(SkiaBackend backend,
177                         skiagm::GM* gm,
178                         int* width,
179                         int* height,
180                         std::vector<uint32_t>* storage) {
181     constexpr SkColorType ct = kRGBA_8888_SkColorType;
182     SkASSERT(storage);
183     SkASSERT(gm);
184     SkASSERT(width);
185     SkASSERT(height);
186     SkISize size = gm->getISize();
187     int w = size.width(),
188         h = size.height();
189     *width = w;
190     *height = h;
191     SkImageInfo info = SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, nullptr);
192     SkSurfaceProps props(0, SkSurfaceProps::kLegacyFontHost_InitType);
193 
194     std::unique_ptr<sk_gpu_test::TestContext> testCtx = make_test_context(backend);
195     if (!testCtx) {
196         return false;
197     }
198     testCtx->makeCurrent();
199     sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(
200             testCtx->makeGrContext(context_options(gm)).get(), SkBudgeted::kNo, info, 0, &props);
201     if (!surf) {
202         return false;
203     }
204     gm->draw(surf->getCanvas());
205 
206     storage->resize(w * h);
207     uint32_t* pix = storage->data();
208     size_t rb = w * sizeof(uint32_t);
209     SkASSERT(SkColorTypeBytesPerPixel(ct) == sizeof(uint32_t));
210     if (!surf->readPixels(SkImageInfo::Make(w, h, ct, kUnpremul_SkAlphaType), pix, rb, 0, 0)) {
211         storage->resize(0);
212         return false;
213     }
214     return true;
215 }
216 
EvaluateGM(SkiaBackend backend,GMFactory gmFact,skqp::AssetManager * assetManager,const char * reportDirectoryPath)217 std::tuple<float, Error> EvaluateGM(SkiaBackend backend,
218                                     GMFactory gmFact,
219                                     skqp::AssetManager* assetManager,
220                                     const char* reportDirectoryPath) {
221     std::vector<uint32_t> pixels;
222     SkASSERT(gmFact);
223     std::unique_ptr<skiagm::GM> gm(gmFact(nullptr));
224     SkASSERT(gm);
225     const char* name = gm->getName();
226     int width = 0, height = 0;
227     if (!evaluate_gm(backend, gm.get(), &width, &height, &pixels)) {
228         return std::make_tuple(FLT_MAX, Error::SkiaFailure);
229     }
230     if (Mode::kCompatibilityTestMode == gMode && in_set(name, gDoNotScoreInCompatibilityTestMode)) {
231         return std::make_tuple(0, Error::None);
232     }
233 
234     gmkb::Error e;
235     float value = gmkb::Check(pixels.data(), width, height,
236                               name, GetBackendName(backend), assetManager,
237                               reportDirectoryPath, &e);
238     Error error = gmkb::Error::kBadInput == e ? Error::BadSkiaOutput
239                 : gmkb::Error::kBadData  == e ? Error::BadGMKBData
240                                               : Error::None;
241     return std::make_tuple(value, error);
242 }
243 
InitSkia(Mode mode,skqp::AssetManager * mgr)244 void InitSkia(Mode mode, skqp::AssetManager* mgr) {
245     SkGraphics::Init();
246     gSkFontMgr_DefaultFactory = &sk_tool_utils::MakePortableFontMgr;
247 
248     gMode = mode;
249     readlist(mgr, "skqp/DoNotScoreInCompatibilityTestMode.txt",
250              &gDoNotScoreInCompatibilityTestMode);
251     readlist(mgr, "skqp/DoNotExecuteInExperimentalMode.txt", &gDoNotExecuteInExperimentalMode);
252     readlist(mgr, "skqp/KnownGpuUnitTests.txt", &gKnownGpuUnitTests);
253     readlist(mgr, "skqp/KnownGMs.txt", &gKnownGMs);
254 }
255 
GetGMFactories(skqp::AssetManager * assetManager)256 std::vector<GMFactory> GetGMFactories(skqp::AssetManager* assetManager) {
257     std::vector<GMFactory> result;
258     for (const skiagm::GMRegistry* r = skiagm::GMRegistry::Head(); r; r = r->next()) {
259         GMFactory f = r->factory();
260         SkASSERT(f);
261         auto name = GetGMName(f);
262         if ((is_empty(gKnownGMs) || in_set(name.c_str(), gKnownGMs)) &&
263             !(Mode::kExperimentalMode == gMode &&
264               in_set(name.c_str(), gDoNotExecuteInExperimentalMode)))
265         {
266             result.push_back(f);
267         }
268     }
269     struct {
270         bool operator()(GMFactory u, GMFactory v) const { return GetGMName(u) < GetGMName(v); }
271     } less;
272     std::sort(result.begin(), result.end(), less);
273     return result;
274 }
275 
GetGMName(GMFactory gmFactory)276 std::string GetGMName(GMFactory gmFactory) {
277     SkASSERT(gmFactory);
278     std::unique_ptr<skiagm::GM> gm(gmFactory(nullptr));
279     SkASSERT(gm);
280     return std::string(gm->getName());
281 }
282 }  // namespace gm_runner
283