diff options
author | Chris Dalton <csmartdalton@google.com> | 2018-06-18 09:51:36 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-18 16:14:28 +0000 |
commit | 4da70190aadd8a346ea967a3c435d20a80a5cccd (patch) | |
tree | f986a7da77639a58363a0e840833fd1c090744b7 /tests | |
parent | ddc0c6006c44bd31ef0adc9eb06e68b17218198f (diff) |
ccpr: Implement path mask caching
Implement caching as follows:
1) Instead of deleting the mainline ccpr atlas when finished, stash it
away from flush to flush.
2) On subsequent flushes, check the stashed atlas to see if we can
reuse any of its cachable paths. Copy reusable paths into 8-bit
literal coverage atlases and store them in the resource cache.
3) Recycle the stashed atlas texture for the remaining paths in the
flush.
Bug: skia:
Change-Id: I9b20fbea708646df1df3a5f9c044e2299706b989
Reviewed-on: https://skia-review.googlesource.com/134703
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/GrCCPRTest.cpp | 130 |
1 files changed, 120 insertions, 10 deletions
diff --git a/tests/GrCCPRTest.cpp b/tests/GrCCPRTest.cpp index bbcf6706a7..3b1ab3368d 100644 --- a/tests/GrCCPRTest.cpp +++ b/tests/GrCCPRTest.cpp @@ -17,9 +17,11 @@ #include "GrRenderTargetContext.h" #include "GrRenderTargetContextPriv.h" #include "GrShape.h" +#include "GrTexture.h" #include "SkMatrix.h" #include "SkPathPriv.h" #include "SkRect.h" +#include "sk_tool_utils.h" #include "ccpr/GrCoverageCountingPathRenderer.h" #include "mock/GrMockTypes.h" #include <cmath> @@ -51,6 +53,11 @@ private: const SkPath fPath; }; +enum class MarkVolatile : bool { + kNo = false, + kYes = true +}; + class CCPRPathDrawer { public: CCPRPathDrawer(GrContext* ctx, skiatest::Reporter* reporter) @@ -68,22 +75,26 @@ public: } } + GrContext* ctx() const { return fCtx; } + GrCoverageCountingPathRenderer* ccpr() const { return fCCPR; } + bool valid() const { return fCCPR && fRTC; } void clear() const { fRTC->clear(nullptr, 0, GrRenderTargetContext::CanClearFullscreen::kYes); } void abandonGrContext() { fCtx = nullptr; fCCPR = nullptr; fRTC = nullptr; } - void drawPath(SkPath path, GrColor4f color = GrColor4f(0, 1, 0, 1)) const { + void drawPath(SkPath path, const SkMatrix& matrix = SkMatrix::I(), + MarkVolatile markVolatile = MarkVolatile::kYes) const { SkASSERT(this->valid()); GrPaint paint; - paint.setColor4f(color); + paint.setColor4f(GrColor4f(0, 1, 0, 1)); GrNoClip noClip; SkIRect clipBounds = SkIRect::MakeWH(kCanvasSize, kCanvasSize); - SkMatrix matrix = SkMatrix::I(); - - path.setIsVolatile(true); + if (MarkVolatile::kYes == markVolatile) { + path.setIsVolatile(true); + } GrShape shape(path); fCCPR->drawPath({fCtx, std::move(paint), &GrUserStencilSettings::kUnused, fRTC.get(), @@ -106,9 +117,9 @@ public: } private: - GrContext* fCtx; - GrCoverageCountingPathRenderer* fCCPR; - sk_sp<GrRenderTargetContext> fRTC; + GrContext* fCtx; + GrCoverageCountingPathRenderer* fCCPR; + sk_sp<GrRenderTargetContext> fRTC; }; class CCPRTest { @@ -120,6 +131,9 @@ public: mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderability = GrMockOptions::ConfigOptions::Renderability::kNonMSAA; mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true; + mockOptions.fConfigOptions[kAlpha_8_GrPixelConfig].fRenderability = + GrMockOptions::ConfigOptions::Renderability::kNonMSAA; + mockOptions.fConfigOptions[kAlpha_8_GrPixelConfig].fTexturable = true; mockOptions.fGeometryShaderSupport = true; mockOptions.fIntegerSupport = true; mockOptions.fFlatInterpolationSupport = true; @@ -155,8 +169,8 @@ protected: virtual void customizeMockOptions(GrMockOptions*) {} virtual void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) = 0; - sk_sp<GrContext> fMockContext; - SkPath fPath; + sk_sp<GrContext> fMockContext; + SkPath fPath; }; #define DEF_CCPR_TEST(name) \ @@ -263,6 +277,102 @@ class GrCCPRTest_parseEmptyPath : public CCPRTest { }; DEF_CCPR_TEST(GrCCPRTest_parseEmptyPath) +// This test exercises CCPR's cache capabilities by drawing many paths with two different +// transformation matrices. We then vary the matrices independently by whole and partial pixels, +// and verify the caching behaved as expected. +class GrCCPRTest_cache : public CCPRTest { + void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) override { + static constexpr int kPathSize = 20; + SkRandom rand; + + SkPath paths[200]; + int primes[11] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; + for (size_t i = 0; i < SK_ARRAY_COUNT(paths); ++i) { + int numPts = rand.nextRangeU(GrShape::kMaxKeyFromDataVerbCnt + 1, + GrShape::kMaxKeyFromDataVerbCnt * 2); + paths[i] = sk_tool_utils::make_star(SkRect::MakeIWH(kPathSize, kPathSize), numPts, + primes[rand.nextU() % SK_ARRAY_COUNT(primes)]); + } + + SkMatrix matrices[2] = { + SkMatrix::MakeTrans(5, 5), + SkMatrix::MakeTrans(kCanvasSize - kPathSize - 5, kCanvasSize - kPathSize - 5) + }; + + int firstAtlasID = -1; + + for (int flushIdx = 0; flushIdx < 10; ++flushIdx) { + // Draw all the paths and flush. + for (size_t i = 0; i < SK_ARRAY_COUNT(paths); ++i) { + ccpr.drawPath(paths[i], matrices[i % 2], MarkVolatile::kNo); + } + ccpr.flush(); + + // Figure out the mock backend ID of the atlas texture stashed away by CCPR. + GrMockTextureInfo stashedAtlasInfo; + stashedAtlasInfo.fID = -1; + const GrUniqueKey& stashedAtlasKey = ccpr.ccpr()->testingOnly_getStashedAtlasKey(); + if (stashedAtlasKey.isValid()) { + GrResourceProvider* rp = ccpr.ctx()->contextPriv().resourceProvider(); + sk_sp<GrSurface> stashedAtlas = rp->findByUniqueKey<GrSurface>(stashedAtlasKey); + REPORTER_ASSERT(reporter, stashedAtlas); + if (stashedAtlas) { + const auto& backendTexture = stashedAtlas->asTexture()->getBackendTexture(); + backendTexture.getMockTextureInfo(&stashedAtlasInfo); + } + } + + if (0 == flushIdx) { + // First flush: just note the ID of the stashed atlas and continue. + REPORTER_ASSERT(reporter, stashedAtlasKey.isValid()); + firstAtlasID = stashedAtlasInfo.fID; + continue; + } + + switch (flushIdx % 3) { + case 1: + // This draw should have gotten 100% cache hits; we only did integer translates + // last time (or none if it was the first flush). Therefore, no atlas should + // have been stashed away. + REPORTER_ASSERT(reporter, !stashedAtlasKey.isValid()); + + // Invalidate even path masks. + matrices[0].preTranslate(1.6f, 1.4f); + break; + + case 2: + // Even path masks were invalidated last iteration by a subpixel translate. They + // should have been re-rendered this time and stashed away in the CCPR atlas. + REPORTER_ASSERT(reporter, stashedAtlasKey.isValid()); + + // 'firstAtlasID' should be kept as a scratch texture in the resource cache. + REPORTER_ASSERT(reporter, stashedAtlasInfo.fID == firstAtlasID); + + // Invalidate odd path masks. + matrices[1].preTranslate(-1.4f, -1.6f); + break; + + case 0: + // Odd path masks were invalidated last iteration by a subpixel translate. They + // should have been re-rendered this time and stashed away in the CCPR atlas. + REPORTER_ASSERT(reporter, stashedAtlasKey.isValid()); + + // 'firstAtlasID' is the same texture that got stashed away last time (assuming + // no assertion failures). So if it also got stashed this time, it means we + // first copied the even paths out of it, then recycled the exact same texture + // to render the odd paths. This is the expected behavior. + REPORTER_ASSERT(reporter, stashedAtlasInfo.fID == firstAtlasID); + + // Integer translates: all path masks stay valid. + matrices[0].preTranslate(-1, -1); + matrices[1].preTranslate(1, 1); + break; + } + } + } +}; +DEF_CCPR_TEST(GrCCPRTest_cache) + class CCPRRenderingTest { public: void run(skiatest::Reporter* reporter, GrContext* ctx) const { |