diff options
author | 2017-12-11 17:46:26 -0500 | |
---|---|---|
committer | 2017-12-15 17:23:48 +0000 | |
commit | d7b3845f3d3f3498c2adc542b4b20003ac7d3ab0 (patch) | |
tree | 11ed4db86efb28f344255a6cc44f0c19d926c8ef /tools/skqp/gm_runner.cpp | |
parent | 0215e39d7e415d0530231df6ad20d5f215c72152 (diff) |
SkQP: make_gmkb, gm_knowledge (GM Knowledgebase)
Add a real implementation for gm_knowledge.h This depends on
the presence of files in the form $GMK_DIR/foo/{max,min}.png
The implementation also writes out failures in a report directory.
Add a utility: experimental/make_gmkb which is a stand-alone
go executable that generates the foo/{max,min}.png data.
tools/skqp/README.md has instructions on running SkQP.
Also: add SkFontMgrPriv.h
Change-Id: Ibe1e9a7e7de143d14eee3877f5f2d2d8713f7f49
Reviewed-on: https://skia-review.googlesource.com/65380
Reviewed-by: Yuqian Li <liyuqian@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
Diffstat (limited to 'tools/skqp/gm_runner.cpp')
-rw-r--r-- | tools/skqp/gm_runner.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/tools/skqp/gm_runner.cpp b/tools/skqp/gm_runner.cpp new file mode 100644 index 0000000000..3c3885ef5c --- /dev/null +++ b/tools/skqp/gm_runner.cpp @@ -0,0 +1,213 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm_runner.h" + +#include <algorithm> + +#include "../dm/DMFontMgr.h" +#include "GrContext.h" +#include "GrContextOptions.h" +#include "SkFontMgrPriv.h" +#include "SkFontStyle.h" +#include "SkGraphics.h" +#include "SkSurface.h" +#include "Test.h" +#include "gl/GLTestContext.h" +#include "gm.h" +#include "gm_knowledge.h" +#include "vk/VkTestContext.h" + +namespace gm_runner { + +const char* GetErrorString(Error e) { + switch (e) { + case Error::None: return ""; + case Error::BadSkiaOutput: return "Bad Skia Output"; + case Error::BadGMKBData: return "Bad GMKB Data"; + case Error::SkiaFailure: return "Skia Failure"; + default: SkASSERT(false); + return "unknown"; + } +} + +std::vector<std::string> ExecuteTest(UnitTest test) { + struct : public skiatest::Reporter { + std::vector<std::string> fErrors; + void reportFailed(const skiatest::Failure& failure) override { + SkString desc = failure.toString(); + fErrors.push_back(std::string(desc.c_str(), desc.size())); + } + } r; + GrContextOptions options; + if (test->fContextOptionsProc) { + test->fContextOptionsProc(&options); + } + test->proc(&r, options); + return std::move(r.fErrors); +} + +const char* GetUnitTestName(UnitTest test) { return test->name; } + +std::vector<UnitTest> GetUnitTests() { + std::vector<UnitTest> tests; + for (const skiatest::TestRegistry* r = skiatest::TestRegistry::Head(); r; r = r->next()) { + const skiatest::Test& test = r->factory(); + if (test.needsGpu) { + tests.push_back(&test); + } + } + return tests; +} + +const char* GetBackendName(SkiaBackend backend) { + switch (backend) { + case SkiaBackend::kGL: return "gl"; + case SkiaBackend::kGLES: return "gles"; + case SkiaBackend::kVulkan: return "vk"; + default: SkASSERT(false); + return "error"; + } +} + +static std::unique_ptr<sk_gpu_test::TestContext> make_test_context(SkiaBackend backend) { + using U = std::unique_ptr<sk_gpu_test::TestContext>; + switch (backend) { + case SkiaBackend::kGL: + return U(sk_gpu_test::CreatePlatformGLTestContext(kGL_GrGLStandard, nullptr)); + case SkiaBackend::kGLES: + return U(sk_gpu_test::CreatePlatformGLTestContext(kGLES_GrGLStandard, nullptr)); +#ifdef SK_VULKAN + case SkiaBackend::kVulkan: + return U(sk_gpu_test::CreatePlatformVkTestContext(nullptr)); +#endif + default: + return nullptr; + } +} + +static GrContextOptions context_options(skiagm::GM* gm = nullptr) { + GrContextOptions grContextOptions; + grContextOptions.fAllowPathMaskCaching = true; + grContextOptions.fSuppressPathRendering = true; + if (gm) { + gm->modifyGrContextOptions(&grContextOptions); + } + return grContextOptions; +} + +std::vector<SkiaBackend> GetSupportedBackends() { + std::vector<SkiaBackend> result; + SkiaBackend backends[] = { + #ifndef SK_BUILD_FOR_ANDROID + SkiaBackend::kGL, // Used for testing on desktop machines. + #endif + SkiaBackend::kGLES, + SkiaBackend::kVulkan, + }; + for (SkiaBackend backend : backends) { + std::unique_ptr<sk_gpu_test::TestContext> testCtx = make_test_context(backend); + if (testCtx) { + testCtx->makeCurrent(); + if (nullptr != testCtx->makeGrContext(context_options())) { + result.push_back(backend); + } + } + } + return result; +} + +static bool evaluate_gm(SkiaBackend backend, + skiagm::GM* gm, + int* width, + int* height, + std::vector<uint32_t>* storage) { + constexpr SkColorType ct = kRGBA_8888_SkColorType; + SkASSERT(storage); + SkASSERT(gm); + SkASSERT(width); + SkASSERT(height); + SkISize size = gm->getISize(); + int w = size.width(), + h = size.height(); + *width = w; + *height = h; + SkImageInfo info = SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, nullptr); + SkSurfaceProps props(0, SkSurfaceProps::kLegacyFontHost_InitType); + + std::unique_ptr<sk_gpu_test::TestContext> testCtx = make_test_context(backend); + if (!testCtx) { + return false; + } + testCtx->makeCurrent(); + sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget( + testCtx->makeGrContext(context_options(gm)).get(), SkBudgeted::kNo, info, 0, &props); + if (!surf) { + return false; + } + gm->draw(surf->getCanvas()); + + storage->resize(w * h); + uint32_t* pix = storage->data(); + size_t rb = w * sizeof(uint32_t); + SkASSERT(SkColorTypeBytesPerPixel(ct) == sizeof(uint32_t)); + if (!surf->readPixels(SkImageInfo::Make(w, h, ct, kUnpremul_SkAlphaType), pix, rb, 0, 0)) { + storage->resize(0); + return false; + } + return true; +} + +std::tuple<float, Error> EvaluateGM(SkiaBackend backend, + GMFactory gmFact, + skqp::AssetManager* assetManager, + const char* reportDirectoryPath) { + std::vector<uint32_t> pixels; + std::unique_ptr<skiagm::GM> gm(gmFact(nullptr)); + int width = 0, height = 0; + if (!evaluate_gm(backend, gm.get(), &width, &height, &pixels)) { + return std::make_tuple(FLT_MAX, Error::SkiaFailure); + } + gmkb::Error e; + float value = gmkb::Check(pixels.data(), width, height, + gm->getName(), GetBackendName(backend), assetManager, + reportDirectoryPath, &e); + Error error = gmkb::Error::kBadInput == e ? Error::BadSkiaOutput + : gmkb::Error::kBadData == e ? Error::BadGMKBData + : Error::None; + return std::make_tuple(value, error); +} + +void InitSkia() { + SkGraphics::Init(); + gSkFontMgr_DefaultFactory = &DM::MakeFontMgr; +} + +std::vector<GMFactory> GetGMFactories(skqp::AssetManager* assetManager) { + std::vector<GMFactory> result; + for (const skiagm::GMRegistry* r = skiagm::GMRegistry::Head(); r; r = r->next()) { + GMFactory f = r->factory(); + + if (gmkb::IsGoodGM(GetGMName(f).c_str(), assetManager)) { + result.push_back(r->factory()); + SkASSERT(result.back()); + } + } + struct { + bool operator()(GMFactory u, GMFactory v) const { return GetGMName(u) < GetGMName(v); } + } less; + std::sort(result.begin(), result.end(), less); + return result; +} + +std::string GetGMName(GMFactory gmFactory) { + SkASSERT(gmFactory); + std::unique_ptr<skiagm::GM> gm(gmFactory(nullptr)); + SkASSERT(gm); + return std::string(gm->getName()); +} +} // namespace gm_runner |