aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/gpu/GrShaderCaps.h1
-rw-r--r--include/gpu/mock/GrMockTypes.h10
-rw-r--r--src/core/SkPathPriv.h6
-rw-r--r--src/gpu/GrDrawingManager.cpp7
-rw-r--r--src/gpu/GrDrawingManager.h5
-rw-r--r--src/gpu/GrPathRendererChain.cpp3
-rw-r--r--src/gpu/GrPathRendererChain.h8
-rw-r--r--src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp1
-rw-r--r--src/gpu/mock/GrMockBuffer.h9
-rw-r--r--src/gpu/mock/GrMockCaps.h11
-rw-r--r--tests/GrCCPRTest.cpp181
11 files changed, 198 insertions, 44 deletions
diff --git a/include/gpu/GrShaderCaps.h b/include/gpu/GrShaderCaps.h
index b093f37f28..9779a4a570 100644
--- a/include/gpu/GrShaderCaps.h
+++ b/include/gpu/GrShaderCaps.h
@@ -355,6 +355,7 @@ private:
uint8_t fSamplerPrecisions[(1 << kGrShaderTypeCount)][kGrPixelConfigCnt];
friend class GrGLCaps; // For initialization.
+ friend class GrMockCaps;
friend class GrMtlCaps;
friend class GrVkCaps;
friend class SkSL::ShaderCapsFactory;
diff --git a/include/gpu/mock/GrMockTypes.h b/include/gpu/mock/GrMockTypes.h
index c8c2a5a8cd..81eeaba8b6 100644
--- a/include/gpu/mock/GrMockTypes.h
+++ b/include/gpu/mock/GrMockTypes.h
@@ -34,10 +34,20 @@ struct GrMockOptions {
bool fTexturable = false;
};
+ // GPU options.
+ bool fInstanceAttribSupport = false;
+ uint32_t fMapBufferFlags = 0;
int fMaxTextureSize = 2048;
int fMaxRenderTargetSize = 2048;
int fMaxVertexAttributes = 16;
ConfigOptions fConfigOptions[kGrPixelConfigCnt];
+
+ // Shader options.
+ bool fGeometryShaderSupport = false;
+ bool fTexelBufferSupport = false;
+ bool fIntegerSupport = false;
+ bool fFlatInterpolationSupport = false;
+ int fMaxVertexSamplers = 0;
};
#endif
diff --git a/src/core/SkPathPriv.h b/src/core/SkPathPriv.h
index 89c1e6572f..ec748a9e36 100644
--- a/src/core/SkPathPriv.h
+++ b/src/core/SkPathPriv.h
@@ -151,6 +151,12 @@ public:
static const SkScalar* ConicWeightData(const SkPath& path) {
return path.fPathRef->conicWeights();
}
+
+ /** Returns true if the underlying SkPathRef has one single owner. */
+ static bool TestingOnly_unique(const SkPath& path) {
+ return path.fPathRef->unique();
+ }
+
};
#endif
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 66cb6cc1bb..21223c51b6 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -361,6 +361,13 @@ GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawP
return pr;
}
+GrCoverageCountingPathRenderer* GrDrawingManager::getCoverageCountingPathRenderer() {
+ if (!fPathRendererChain) {
+ fPathRendererChain = new GrPathRendererChain(fContext, fOptionsForPathRendererChain);
+ }
+ return fPathRendererChain->getCoverageCountingPathRenderer();
+}
+
sk_sp<GrRenderTargetContext> GrDrawingManager::makeRenderTargetContext(
sk_sp<GrSurfaceProxy> sProxy,
sk_sp<SkColorSpace> colorSpace,
diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h
index 38d234900a..f78229fd0e 100644
--- a/src/gpu/GrDrawingManager.h
+++ b/src/gpu/GrDrawingManager.h
@@ -18,6 +18,7 @@
#include "text/GrAtlasTextContext.h"
class GrContext;
+class GrCoverageCountingPathRenderer;
class GrOnFlushCallbackObject;
class GrRenderTargetContext;
class GrRenderTargetProxy;
@@ -62,6 +63,10 @@ public:
GrPathRendererChain::DrawType drawType,
GrPathRenderer::StencilSupport* stencilSupport = nullptr);
+ // Returns a direct pointer to the coverage counting path renderer, or null if it is not
+ // supported and turned on.
+ GrCoverageCountingPathRenderer* getCoverageCountingPathRenderer();
+
void flushIfNecessary() {
if (fContext->getResourceCache()->requestsFlush()) {
this->internalFlush(nullptr, GrResourceCache::kCacheRequested, 0, nullptr);
diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp
index 3bb744afab..393823ca1b 100644
--- a/src/gpu/GrPathRendererChain.cpp
+++ b/src/gpu/GrPathRendererChain.cpp
@@ -54,7 +54,8 @@ GrPathRendererChain::GrPathRendererChain(GrContext* context, const Options& opti
bool drawCachablePaths = !options.fAllowPathMaskCaching;
if (auto ccpr = GrCoverageCountingPathRenderer::CreateIfSupported(*context->caps(),
drawCachablePaths)) {
- context->contextPriv().addOnFlushCallbackObject(ccpr.get());
+ fCoverageCountingPathRenderer = ccpr.get();
+ context->contextPriv().addOnFlushCallbackObject(fCoverageCountingPathRenderer);
fChain.push_back(std::move(ccpr));
}
}
diff --git a/src/gpu/GrPathRendererChain.h b/src/gpu/GrPathRendererChain.h
index 7d2c56ea8c..de17e53d81 100644
--- a/src/gpu/GrPathRendererChain.h
+++ b/src/gpu/GrPathRendererChain.h
@@ -15,6 +15,7 @@
#include "SkTArray.h"
class GrContext;
+class GrCoverageCountingPathRenderer;
/**
* Keeps track of an ordered list of path renderers. When a path needs to be
@@ -46,11 +47,18 @@ public:
DrawType drawType,
GrPathRenderer::StencilSupport* stencilSupport);
+ /** Returns a direct pointer to the coverage counting path renderer, or null if it is not in the
+ chain. */
+ GrCoverageCountingPathRenderer* getCoverageCountingPathRenderer() {
+ return fCoverageCountingPathRenderer;
+ }
+
private:
enum {
kPreAllocCount = 8,
};
SkSTArray<kPreAllocCount, sk_sp<GrPathRenderer>> fChain;
+ GrCoverageCountingPathRenderer* fCoverageCountingPathRenderer = nullptr;
};
#endif
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
index 73b7e75307..c6e5a0ecf2 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
@@ -30,6 +30,7 @@ bool GrCoverageCountingPathRenderer::IsSupported(const GrCaps& caps) {
shaderCaps.flatInterpolationSupport() &&
shaderCaps.maxVertexSamplers() >= 1 &&
caps.instanceAttribSupport() &&
+ GrCaps::kNone_MapFlags != caps.mapBufferFlags() &&
caps.isConfigTexturable(kAlpha_half_GrPixelConfig) &&
caps.isConfigRenderable(kAlpha_half_GrPixelConfig, /*withMSAA=*/false) &&
GrCaps::kNone_MapFlags != caps.mapBufferFlags() &&
diff --git a/src/gpu/mock/GrMockBuffer.h b/src/gpu/mock/GrMockBuffer.h
index fdb812d30d..fa3e712c6d 100644
--- a/src/gpu/mock/GrMockBuffer.h
+++ b/src/gpu/mock/GrMockBuffer.h
@@ -9,6 +9,7 @@
#define GrMockBuffer_DEFINED
#include "GrBuffer.h"
+#include "GrCaps.h"
#include "GrMockGpu.h"
class GrMockBuffer : public GrBuffer {
@@ -20,8 +21,12 @@ public:
}
private:
- void onMap() override {}
- void onUnmap() override {}
+ void onMap() override {
+ if (GrCaps::kNone_MapFlags != this->getGpu()->caps()->mapBufferFlags()) {
+ fMapPtr = sk_malloc_throw(this->sizeInBytes());
+ }
+ }
+ void onUnmap() override { sk_free(fMapPtr); }
bool onUpdateData(const void* src, size_t srcSizeInBytes) override { return true; }
typedef GrBuffer INHERITED;
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
index 90cc8243cc..e1dd80dcc7 100644
--- a/src/gpu/mock/GrMockCaps.h
+++ b/src/gpu/mock/GrMockCaps.h
@@ -15,11 +15,20 @@ class GrMockCaps : public GrCaps {
public:
GrMockCaps(const GrContextOptions& contextOptions, const GrMockOptions& options)
: INHERITED(contextOptions), fOptions(options) {
- fBufferMapThreshold = SK_MaxS32;
+ fInstanceAttribSupport = options.fInstanceAttribSupport;
+ fMapBufferFlags = options.fMapBufferFlags;
+ fBufferMapThreshold = SK_MaxS32; // Overridable in GrContextOptions.
fMaxTextureSize = options.fMaxTextureSize;
fMaxRenderTargetSize = SkTMin(options.fMaxRenderTargetSize, fMaxTextureSize);
fMaxVertexAttributes = options.fMaxVertexAttributes;
+
fShaderCaps.reset(new GrShaderCaps(contextOptions));
+ fShaderCaps->fGeometryShaderSupport = options.fGeometryShaderSupport;
+ fShaderCaps->fTexelBufferSupport = options.fTexelBufferSupport;
+ fShaderCaps->fIntegerSupport = options.fIntegerSupport;
+ fShaderCaps->fFlatInterpolationSupport = options.fFlatInterpolationSupport;
+ fShaderCaps->fMaxVertexSamplers = options.fMaxVertexSamplers;
+
this->applyOptionsOverrides(contextOptions);
}
int getSampleCount(int /*requestCount*/, GrPixelConfig /*config*/) const override {
diff --git a/tests/GrCCPRTest.cpp b/tests/GrCCPRTest.cpp
index d685b1094b..f56298be5a 100644
--- a/tests/GrCCPRTest.cpp
+++ b/tests/GrCCPRTest.cpp
@@ -13,89 +13,190 @@
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrClip.h"
+#include "GrDrawingManager.h"
+#include "GrPathRenderer.h"
+#include "GrPaint.h"
#include "GrRenderTargetContext.h"
#include "GrRenderTargetContextPriv.h"
#include "GrShape.h"
-#include "GrPathRenderer.h"
-#include "GrPaint.h"
#include "SkMatrix.h"
+#include "SkPathPriv.h"
#include "SkRect.h"
#include "ccpr/GrCoverageCountingPathRenderer.h"
+#include "mock/GrMockTypes.h"
#include <cmath>
static constexpr int kCanvasSize = 100;
class CCPRPathDrawer {
public:
- CCPRPathDrawer(GrContext* ctx)
+ CCPRPathDrawer(GrContext* ctx, skiatest::Reporter* reporter)
: fCtx(ctx)
- , fCCPR(GrCoverageCountingPathRenderer::CreateIfSupported(*fCtx->caps(), true))
+ , fCCPR(fCtx->contextPriv().drawingManager()->getCoverageCountingPathRenderer())
, fRTC(fCtx->makeDeferredRenderTargetContext(SkBackingFit::kExact, kCanvasSize,
kCanvasSize, kRGBA_8888_GrPixelConfig,
nullptr)) {
- if (fCCPR) {
- fCtx->contextPriv().addOnFlushCallbackObject(fCCPR.get());
+ if (!fCCPR) {
+ ERRORF(reporter, "ccpr not enabled in GrContext for ccpr tests");
}
- }
-
- ~CCPRPathDrawer() {
- if (fCCPR) {
- fCtx->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(fCCPR.get());
+ if (!fRTC) {
+ ERRORF(reporter, "failed to create GrRenderTargetContext for ccpr tests");
}
}
- bool valid() { return fCCPR && fRTC; }
+ bool valid() const { return fCCPR && fRTC; }
+ void clear() const { fRTC->clear(nullptr, 0, true); }
+ void abandonGrContext() { fCtx = nullptr; fCCPR = nullptr; fRTC = nullptr; }
- void clear() { fRTC->clear(nullptr, 0, true); }
+ void drawPath(SkPath path, GrColor4f color = GrColor4f(0, 1, 0, 1)) const {
+ SkASSERT(this->valid());
- void drawPath(const SkPath& path, GrColor4f color = GrColor4f(0, 1, 0, 1)) {
GrPaint paint;
paint.setColor4f(color);
+
GrNoClip noClip;
SkIRect clipBounds = SkIRect::MakeWH(kCanvasSize, kCanvasSize);
+
SkMatrix matrix = SkMatrix::I();
+
+ path.setIsVolatile(true);
GrShape shape(path);
+
fCCPR->drawPath({fCtx, std::move(paint), &GrUserStencilSettings::kUnused, fRTC.get(),
&noClip, &clipBounds, &matrix, &shape, GrAAType::kCoverage, false});
}
- void flush() {
+ void flush() const {
+ SkASSERT(this->valid());
fCtx->flush();
}
private:
- GrContext* const fCtx;
- sk_sp<GrCoverageCountingPathRenderer> fCCPR;
- sk_sp<GrRenderTargetContext> fRTC;
+ GrContext* fCtx;
+ GrCoverageCountingPathRenderer* fCCPR;
+ sk_sp<GrRenderTargetContext> fRTC;
};
-DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrCCPRTest, reporter, ctxInfo) {
- GrContext* const ctx = ctxInfo.grContext();
- if (!GrCoverageCountingPathRenderer::IsSupported(*ctx->caps())) {
- return;
+class CCPRTest {
+public:
+ void run(skiatest::Reporter* reporter) {
+ GrMockOptions mockOptions;
+ mockOptions.fInstanceAttribSupport = true;
+ mockOptions.fMapBufferFlags = GrCaps::kCanMap_MapFlag;
+ mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true;
+ mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
+ mockOptions.fGeometryShaderSupport = true;
+ mockOptions.fTexelBufferSupport = true;
+ mockOptions.fIntegerSupport = true;
+ mockOptions.fFlatInterpolationSupport = true;
+ mockOptions.fMaxVertexSamplers = 1;
+
+ GrContextOptions ctxOptions;
+ ctxOptions.fAllowPathMaskCaching = false;
+ ctxOptions.fGpuPathRenderers = GpuPathRenderers::kCoverageCounting;
+
+ fMockContext = GrContext::MakeMock(&mockOptions, ctxOptions);
+ if (!fMockContext) {
+ ERRORF(reporter, "could not create mock context");
+ return;
+ }
+ if (!fMockContext->unique()) {
+ ERRORF(reporter, "mock context is not unique");
+ return;
+ }
+
+ CCPRPathDrawer ccpr(fMockContext.get(), reporter);
+ if (!ccpr.valid()) {
+ return;
+ }
+
+ fPath.moveTo(0, 0);
+ fPath.cubicTo(50, 50, 0, 50, 50, 0);
+ this->onRun(reporter, ccpr);
}
- CCPRPathDrawer ccpr(ctx);
- if (!ccpr.valid()) {
- ERRORF(reporter, "could not create render target context for ccpr.");
- return;
+ virtual ~CCPRTest() {}
+
+protected:
+ virtual void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) = 0;
+
+ sk_sp<GrContext> fMockContext;
+ SkPath fPath;
+};
+
+#define DEF_CCPR_TEST(name) \
+ DEF_GPUTEST(name, reporter, factory) { \
+ name test; \
+ test.run(reporter); \
}
- // Test very busy paths.
- static constexpr int kNumBusyVerbs = 1 << 17;
- ccpr.clear();
- SkPath busyPath;
- busyPath.moveTo(0, 0); // top left
- busyPath.lineTo(kCanvasSize, kCanvasSize); // bottom right
- for (int i = 2; i < kNumBusyVerbs; ++i) {
- float offset = i * ((float)kCanvasSize / kNumBusyVerbs);
- busyPath.lineTo(kCanvasSize - offset, kCanvasSize + offset); // offscreen
+class GrCCPRTest_cleanup : public CCPRTest {
+ void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) override {
+ REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
+
+ // Ensure paths get unreffed.
+ for (int i = 0; i < 10; ++i) {
+ ccpr.drawPath(fPath);
+ }
+ REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
+ ccpr.flush();
+ REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
+
+ // Ensure paths get unreffed when we delete the context without flushing.
+ for (int i = 0; i < 10; ++i) {
+ ccpr.drawPath(fPath);
+ }
+ ccpr.abandonGrContext();
+ REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
+ fMockContext.reset();
+ REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
+ }
+};
+DEF_CCPR_TEST(GrCCPRTest_cleanup)
+
+class CCPRRenderingTest {
+public:
+ void run(skiatest::Reporter* reporter, GrContext* ctx) const {
+ if (!ctx->contextPriv().drawingManager()->getCoverageCountingPathRenderer()) {
+ return; // CCPR is not enabled on this GPU.
+ }
+ CCPRPathDrawer ccpr(ctx, reporter);
+ if (!ccpr.valid()) {
+ return;
+ }
+ this->onRun(reporter, ccpr);
}
- ccpr.drawPath(busyPath);
- ccpr.flush(); // If this doesn't crash, the test passed.
- // If it does, maybe fiddle with fMaxInstancesPerDrawArraysWithoutCrashing in your
- // platform's GrGLCaps.
-}
+ virtual ~CCPRRenderingTest() {}
+
+protected:
+ virtual void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const = 0;
+};
+
+#define DEF_CCPR_RENDERING_TEST(name) \
+ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, ctxInfo) { \
+ name test; \
+ test.run(reporter, ctxInfo.grContext()); \
+ }
+
+class GrCCPRTest_busyPath : public CCPRRenderingTest {
+ void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const override {
+ static constexpr int kNumBusyVerbs = 1 << 17;
+ ccpr.clear();
+ SkPath busyPath;
+ busyPath.moveTo(0, 0); // top left
+ busyPath.lineTo(kCanvasSize, kCanvasSize); // bottom right
+ for (int i = 2; i < kNumBusyVerbs; ++i) {
+ float offset = i * ((float)kCanvasSize / kNumBusyVerbs);
+ busyPath.lineTo(kCanvasSize - offset, kCanvasSize + offset); // offscreen
+ }
+ ccpr.drawPath(busyPath);
+
+ ccpr.flush(); // If this doesn't crash, the test passed.
+ // If it does, maybe fiddle with fMaxInstancesPerDrawArraysWithoutCrashing in
+ // your platform's GrGLCaps.
+ }
+};
+DEF_CCPR_RENDERING_TEST(GrCCPRTest_busyPath)
#endif