Home | History | Annotate | Download | only in skqp
      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