diff options
-rw-r--r-- | include/gpu/GrShaderCaps.h | 1 | ||||
-rw-r--r-- | include/gpu/mock/GrMockTypes.h | 10 | ||||
-rw-r--r-- | src/core/SkPathPriv.h | 6 | ||||
-rw-r--r-- | src/gpu/GrDrawingManager.cpp | 7 | ||||
-rw-r--r-- | src/gpu/GrDrawingManager.h | 5 | ||||
-rw-r--r-- | src/gpu/GrPathRendererChain.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrPathRendererChain.h | 8 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp | 1 | ||||
-rw-r--r-- | src/gpu/mock/GrMockBuffer.h | 9 | ||||
-rw-r--r-- | src/gpu/mock/GrMockCaps.h | 11 | ||||
-rw-r--r-- | tests/GrCCPRTest.cpp | 181 |
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 |