aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests/GrCCPRTest.cpp
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2018-06-18 09:51:36 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-06-18 16:14:28 +0000
commit4da70190aadd8a346ea967a3c435d20a80a5cccd (patch)
treef986a7da77639a58363a0e840833fd1c090744b7 /tests/GrCCPRTest.cpp
parentddc0c6006c44bd31ef0adc9eb06e68b17218198f (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/GrCCPRTest.cpp')
-rw-r--r--tests/GrCCPRTest.cpp130
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 {