diff options
Diffstat (limited to 'tests/GrCCPRTest.cpp')
-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 { |