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