diff options
-rw-r--r-- | include/gpu/GrCaps.h | 6 | ||||
-rw-r--r-- | samplecode/SampleCCPRGeometry.cpp | 9 | ||||
-rw-r--r-- | src/gpu/GrCaps.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrGpuCommandBuffer.cpp | 1 | ||||
-rw-r--r-- | src/gpu/GrPrimitiveProcessor.h | 11 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCoverageProcessor.h | 23 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp | 109 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPathParser.cpp | 5 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPathProcessor.cpp | 43 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPathProcessor.h | 16 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp | 11 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 11 | ||||
-rw-r--r-- | src/gpu/gl/GrGLDefines.h | 1 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 5 | ||||
-rw-r--r-- | src/gpu/gl/GrGLVertexArray.cpp | 39 | ||||
-rw-r--r-- | src/gpu/gl/GrGLVertexArray.h | 17 |
16 files changed, 215 insertions, 94 deletions
diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h index 639fe44a81..593f32ab87 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -56,6 +56,11 @@ public: bool multisampleDisableSupport() const { return fMultisampleDisableSupport; } bool instanceAttribSupport() const { return fInstanceAttribSupport; } bool usesMixedSamples() const { return fUsesMixedSamples; } + + // Primitive restart functionality is core in ES 3.0, but using it will cause slowdowns on some + // systems. This cap is only set if primitive restart will improve performance. + bool usePrimitiveRestart() const { return fUsePrimitiveRestart; } + bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; } // On tilers, an initial fullscreen clear is an OPTIMIZATION. It allows the hardware to @@ -206,6 +211,7 @@ protected: bool fMultisampleDisableSupport : 1; bool fInstanceAttribSupport : 1; bool fUsesMixedSamples : 1; + bool fUsePrimitiveRestart : 1; bool fPreferClientSideDynamicBuffers : 1; bool fPreferFullscreenClears : 1; bool fMustClearUploadedBufferData : 1; diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp index 79b857929f..5a2da7f02b 100644 --- a/samplecode/SampleCCPRGeometry.cpp +++ b/samplecode/SampleCCPRGeometry.cpp @@ -249,15 +249,14 @@ void CCPRGeometryView::Op::onExecute(GrOpFlushState* state) { ? static_cast<GrGLGpu*>(state->gpu()) : nullptr; - if (!GrCCCoverageProcessor::DoesRenderPass(fView->fRenderPass, *state->caps().shaderCaps())) { + if (!GrCCCoverageProcessor::DoesRenderPass(fView->fRenderPass, state->caps())) { return; } - GrCCCoverageProcessor proc(rp, fView->fRenderPass, *state->caps().shaderCaps()); - SkDEBUGCODE(proc.enableDebugVisualizations(kDebugBloat);) + GrCCCoverageProcessor proc(rp, fView->fRenderPass, state->caps()); + SkDEBUGCODE(proc.enableDebugVisualizations(kDebugBloat)); - SkSTArray<1, GrMesh> - mesh; + SkSTArray<1, GrMesh> mesh; if (GrCCCoverageProcessor::RenderPassIsCubic(fView->fRenderPass)) { sk_sp<GrBuffer> instBuff(rp->createBuffer( fView->fCubicInstances.count() * sizeof(CubicInstance), kVertex_GrBufferType, diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 78789a1f34..4a7dae65b6 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -54,6 +54,7 @@ GrCaps::GrCaps(const GrContextOptions& options) { fMultisampleDisableSupport = false; fInstanceAttribSupport = false; fUsesMixedSamples = false; + fUsePrimitiveRestart = false; fPreferClientSideDynamicBuffers = false; fPreferFullscreenClears = false; fMustClearUploadedBufferData = false; @@ -160,6 +161,7 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const { writer->appendBool("Multisample disable support", fMultisampleDisableSupport); writer->appendBool("Instance Attrib Support", fInstanceAttribSupport); writer->appendBool("Uses Mixed Samples", fUsesMixedSamples); + writer->appendBool("Use primitive restart", fUsePrimitiveRestart); writer->appendBool("Prefer client-side dynamic buffers", fPreferClientSideDynamicBuffers); writer->appendBool("Prefer fullscreen clears", fPreferFullscreenClears); writer->appendBool("Must clear buffer memory", fMustClearUploadedBufferData); diff --git a/src/gpu/GrGpuCommandBuffer.cpp b/src/gpu/GrGpuCommandBuffer.cpp index 096c3c4d38..654f7009be 100644 --- a/src/gpu/GrGpuCommandBuffer.cpp +++ b/src/gpu/GrGpuCommandBuffer.cpp @@ -39,6 +39,7 @@ bool GrGpuRTCommandBuffer::draw(const GrPipeline& pipeline, const SkRect& bounds) { #ifdef SK_DEBUG SkASSERT(!primProc.hasInstanceAttribs() || this->gpu()->caps()->instanceAttribSupport()); + SkASSERT(!primProc.willUsePrimitiveRestart() || this->gpu()->caps()->usePrimitiveRestart()); for (int i = 0; i < meshCount; ++i) { SkASSERT(!GrPrimTypeRequiresGeometryShaderSupport(meshes[i].primitiveType()) || this->gpu()->caps()->shaderCaps()->geometryShaderSupport()); diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h index 22c65fa249..d9852c0634 100644 --- a/src/gpu/GrPrimitiveProcessor.h +++ b/src/gpu/GrPrimitiveProcessor.h @@ -89,6 +89,8 @@ public: // we put these calls on the base class to prevent having to cast virtual bool willUseGeoShader() const = 0; + bool willUsePrimitiveRestart() const { return fWillUsePrimitiveRestart; } + /** * Computes a transformKey from an array of coord transforms. Will only look at the first * <numCoords> transforms in the array. @@ -138,6 +140,8 @@ protected: return fAttribs.back(); } + void setWillUsePrimitiveRestart() { fWillUsePrimitiveRestart = true; } + private: void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); } void removeRefs() const override { GrResourceIOProcessor::removeRefs(); } @@ -145,9 +149,10 @@ private: void notifyRefCntIsZero() const final {} virtual bool hasExplicitLocalCoords() const = 0; - SkSTArray<8, Attribute> fAttribs; - int fVertexStride = 0; - int fInstanceStride = 0; + SkSTArray<8, Attribute> fAttribs; + int fVertexStride = 0; + int fInstanceStride = 0; + bool fWillUsePrimitiveRestart = false; typedef GrProcessor INHERITED; }; diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h index 671282787d..eeb2ace60d 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor.h +++ b/src/gpu/ccpr/GrCCCoverageProcessor.h @@ -8,6 +8,7 @@ #ifndef GrCCCoverageProcessor_DEFINED #define GrCCCoverageProcessor_DEFINED +#include "GrCaps.h" #include "GrGeometryProcessor.h" #include "GrShaderCaps.h" #include "SkNx.h" @@ -87,19 +88,21 @@ public: static bool RenderPassIsCubic(RenderPass); static const char* RenderPassName(RenderPass); - constexpr static bool DoesRenderPass(RenderPass renderPass, const GrShaderCaps& caps) { - return RenderPass::kTriangleEdges != renderPass || caps.geometryShaderSupport(); + constexpr static bool DoesRenderPass(RenderPass renderPass, const GrCaps& caps) { + return RenderPass::kTriangleEdges != renderPass || + caps.shaderCaps()->geometryShaderSupport(); } - GrCCCoverageProcessor(GrResourceProvider* rp, RenderPass pass, const GrShaderCaps& caps) + GrCCCoverageProcessor(GrResourceProvider* rp, RenderPass pass, const GrCaps& caps) : INHERITED(kGrCCCoverageProcessor_ClassID) , fRenderPass(pass) - , fImpl(caps.geometryShaderSupport() ? Impl::kGeometryShader : Impl::kVertexShader) { + , fImpl(caps.shaderCaps()->geometryShaderSupport() ? Impl::kGeometryShader + : Impl::kVertexShader) { SkASSERT(DoesRenderPass(pass, caps)); if (Impl::kGeometryShader == fImpl) { this->initGS(); } else { - this->initVS(rp); + this->initVS(rp, caps); } } @@ -232,7 +235,7 @@ private: }; void initGS(); - void initVS(GrResourceProvider*); + void initVS(GrResourceProvider*, const GrCaps&); void appendGSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance, SkTArray<GrMesh>* out) const; @@ -244,10 +247,14 @@ private: const RenderPass fRenderPass; const Impl fImpl; - sk_sp<const GrBuffer> fVertexBuffer; // Used by VSImpl. - sk_sp<const GrBuffer> fIndexBuffer; // Used by VSImpl. SkDEBUGCODE(float fDebugBloat = 0); + // Used by VSImpl. + sk_sp<const GrBuffer> fVertexBuffer; + sk_sp<const GrBuffer> fIndexBuffer; + int fNumIndicesPerInstance; + GrPrimitiveType fPrimitiveType; + typedef GrGeometryProcessor INHERITED; }; diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp index 5caefd748c..8f2884ae75 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp @@ -134,7 +134,17 @@ static constexpr int32_t kHull3AndEdgeVertices[] = { GR_DECLARE_STATIC_UNIQUE_KEY(gHull3AndEdgeVertexBufferKey); -static constexpr uint16_t kHull3AndEdgeIndices[] = { +static constexpr uint16_t kRestartStrip = 0xffff; + +static constexpr uint16_t kHull3AndEdgeIndicesAsStrips[] = { + 1, 2, 0, 3, 8, kRestartStrip, // First corner and main body of the hull. + 4, 5, 3, 6, 8, 7, kRestartStrip, // Opposite side and corners of the hull. + 10, 9, 11, 14, 12, 13, kRestartStrip, // First edge. + 16, 15, 17, 20, 18, 19, kRestartStrip, // Second edge. + 22, 21, 23, 26, 24, 25 // Third edge. +}; + +static constexpr uint16_t kHull3AndEdgeIndicesAsTris[] = { // First corner and main body of the hull. 1, 2, 0, 2, 3, 0, @@ -186,7 +196,12 @@ static constexpr int32_t kHull4Vertices[] = { GR_DECLARE_STATIC_UNIQUE_KEY(gHull4VertexBufferKey); -static constexpr uint16_t kHull4Indices[] = { +static constexpr uint16_t kHull4IndicesAsStrips[] = { + 1, 0, 2, 11, 3, 5, 4, kRestartStrip, // First half of the hull (split diagonally). + 7, 6, 8, 5, 9, 11, 10 // Second half of the hull. +}; + +static constexpr uint16_t kHull4IndicesAsTris[] = { // First half of the hull (split diagonally). 1, 0, 2, 0, 11, 2, @@ -281,7 +296,13 @@ private: const int fNumSides; }; -static constexpr uint16_t kCornerIndices[] = { +static constexpr uint16_t kCornerIndicesAsStrips[] = { + 0, 1, 2, 3, kRestartStrip, // First corner. + 4, 5, 6, 7, kRestartStrip, // Second corner. + 8, 9, 10, 11 // Third corner. +}; + +static constexpr uint16_t kCornerIndicesAsTris[] = { // First corner. 0, 1, 2, 1, 3, 2, @@ -319,7 +340,7 @@ public: } }; -void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) { +void GrCCCoverageProcessor::initVS(GrResourceProvider* rp, const GrCaps& caps) { SkASSERT(Impl::kVertexShader == fImpl); GrVertexAttribType inputPtsType = RenderPassIsCubic(fRenderPass) ? @@ -339,10 +360,19 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) { kHull3AndEdgeVertices, gHull3AndEdgeVertexBufferKey); GR_DEFINE_STATIC_UNIQUE_KEY(gHull3AndEdgeIndexBufferKey); - fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, - sizeof(kHull3AndEdgeIndices), - kHull3AndEdgeIndices, - gHull3AndEdgeIndexBufferKey); + if (caps.usePrimitiveRestart()) { + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, + sizeof(kHull3AndEdgeIndicesAsStrips), + kHull3AndEdgeIndicesAsStrips, + gHull3AndEdgeIndexBufferKey); + fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull3AndEdgeIndicesAsStrips); + } else { + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, + sizeof(kHull3AndEdgeIndicesAsTris), + kHull3AndEdgeIndicesAsTris, + gHull3AndEdgeIndexBufferKey); + fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull3AndEdgeIndicesAsTris); + } SkASSERT(kAttribIdx_VertexData == this->numAttribs()); this->addVertexAttrib("vertexdata", kInt_GrVertexAttribType); break; @@ -353,8 +383,19 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) { fVertexBuffer = rp->findOrMakeStaticBuffer(kVertex_GrBufferType, sizeof(kHull4Vertices), kHull4Vertices, gHull4VertexBufferKey); GR_DEFINE_STATIC_UNIQUE_KEY(gHull4IndexBufferKey); - fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, sizeof(kHull4Indices), - kHull4Indices, gHull4IndexBufferKey); + if (caps.usePrimitiveRestart()) { + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, + sizeof(kHull4IndicesAsStrips), + kHull4IndicesAsStrips, + gHull4IndexBufferKey); + fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull4IndicesAsStrips); + } else { + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, + sizeof(kHull4IndicesAsTris), + kHull4IndicesAsTris, + gHull4IndexBufferKey); + fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull4IndicesAsTris); + } SkASSERT(kAttribIdx_VertexData == this->numAttribs()); this->addVertexAttrib("vertexdata", kInt_GrVertexAttribType); break; @@ -366,8 +407,22 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) { case RenderPass::kQuadraticCorners: case RenderPass::kCubicCorners: { GR_DEFINE_STATIC_UNIQUE_KEY(gCornerIndexBufferKey); - fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, sizeof(kCornerIndices), - kCornerIndices, gCornerIndexBufferKey); + if (caps.usePrimitiveRestart()) { + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, + sizeof(kCornerIndicesAsStrips), + kCornerIndicesAsStrips, + gCornerIndexBufferKey); + fNumIndicesPerInstance = SK_ARRAY_COUNT(kCornerIndicesAsStrips); + } else { + fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType, + sizeof(kCornerIndicesAsTris), + kCornerIndicesAsTris, + gCornerIndexBufferKey); + fNumIndicesPerInstance = SK_ARRAY_COUNT(kCornerIndicesAsTris); + } + if (RenderPass::kTriangleCorners != fRenderPass) { + fNumIndicesPerInstance = fNumIndicesPerInstance * 2/3; + } break; } } @@ -386,35 +441,21 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) { SkASSERT(sizeof(int32_t) == this->getVertexStride()); } #endif -} -static int num_indices_per_instance(GrCCCoverageProcessor::RenderPass pass) { - switch (pass) { - using RenderPass = GrCCCoverageProcessor::RenderPass; - case RenderPass::kTriangleHulls: - return SK_ARRAY_COUNT(kHull3AndEdgeIndices); - case RenderPass::kQuadraticHulls: - case RenderPass::kCubicHulls: - return SK_ARRAY_COUNT(kHull4Indices); - case RenderPass::kTriangleEdges: - SK_ABORT("kTriangleEdges RenderPass is not used by VSImpl."); - return 0; - case RenderPass::kTriangleCorners: - return SK_ARRAY_COUNT(kCornerIndices); - case RenderPass::kQuadraticCorners: - case RenderPass::kCubicCorners: - return SK_ARRAY_COUNT(kCornerIndices) * 2/3; + if (caps.usePrimitiveRestart()) { + this->setWillUsePrimitiveRestart(); + fPrimitiveType = GrPrimitiveType::kTriangleStrip; + } else { + fPrimitiveType = GrPrimitiveType::kTriangles; } - SK_ABORT("Invalid RenderPass"); - return 0; } void GrCCCoverageProcessor::appendVSMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance, SkTArray<GrMesh>* out) const { SkASSERT(Impl::kVertexShader == fImpl); - GrMesh& mesh = out->emplace_back(GrPrimitiveType::kTriangles); - mesh.setIndexedInstanced(fIndexBuffer.get(), num_indices_per_instance(fRenderPass), - instanceBuffer, instanceCount, baseInstance); + GrMesh& mesh = out->emplace_back(fPrimitiveType); + mesh.setIndexedInstanced(fIndexBuffer.get(), fNumIndicesPerInstance, instanceBuffer, + instanceCount, baseInstance); if (fVertexBuffer) { mesh.setVertexData(fVertexBuffer.get(), 0); } diff --git a/src/gpu/ccpr/GrCCPathParser.cpp b/src/gpu/ccpr/GrCCPathParser.cpp index 03fb3d924b..2a632d3bda 100644 --- a/src/gpu/ccpr/GrCCPathParser.cpp +++ b/src/gpu/ccpr/GrCCPathParser.cpp @@ -399,7 +399,7 @@ void GrCCPathParser::drawRenderPass(GrOpFlushState* flushState, const GrPipeline const SkIRect& drawBounds) const { SkASSERT(pipeline.getScissorState().enabled()); - if (!GrCCCoverageProcessor::DoesRenderPass(renderPass, *flushState->caps().shaderCaps())) { + if (!GrCCCoverageProcessor::DoesRenderPass(renderPass, flushState->caps())) { return; } @@ -407,8 +407,7 @@ void GrCCPathParser::drawRenderPass(GrOpFlushState* flushState, const GrPipeline fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count()); fDynamicStatesScratchBuffer.pop_back_n(fDynamicStatesScratchBuffer.count()); - GrCCCoverageProcessor proc(flushState->resourceProvider(), renderPass, - *flushState->caps().shaderCaps()); + GrCCCoverageProcessor proc(flushState->resourceProvider(), renderPass, flushState->caps()); SkASSERT(batchID > 0); SkASSERT(batchID < fCoverageCountBatches.count()); diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp index 568ceb7c69..f93a0bd631 100644 --- a/src/gpu/ccpr/GrCCPathProcessor.cpp +++ b/src/gpu/ccpr/GrCCPathProcessor.cpp @@ -42,13 +42,22 @@ sk_sp<const GrBuffer> GrCCPathProcessor::FindVertexBuffer(GrOnFlushResourceProvi kOctoEdgeNorms, gVertexBufferKey); } -// Index buffer for the octagon defined above. -static uint16_t kOctoIndices[GrCCPathProcessor::kPerInstanceIndexCount] = { +static constexpr uint16_t kRestartStrip = 0xffff; + +static constexpr uint16_t kOctoIndicesAsStrips[] = { + 1, 0, 2, 4, 3, kRestartStrip, // First half. + 5, 4, 6, 0, 7 // Second half. +}; + +static constexpr uint16_t kOctoIndicesAsTris[] = { + // First half. + 1, 0, 2, 0, 4, 2, - 0, 6, 4, - 0, 2, 1, 2, 4, 3, - 4, 6, 5, + + // Second half. + 5, 4, 6, + 4, 0, 6, 6, 0, 7, }; @@ -56,12 +65,22 @@ GR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey); sk_sp<const GrBuffer> GrCCPathProcessor::FindIndexBuffer(GrOnFlushResourceProvider* onFlushRP) { GR_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey); - return onFlushRP->findOrMakeStaticBuffer(kIndex_GrBufferType, sizeof(kOctoIndices), - kOctoIndices, gIndexBufferKey); + if (onFlushRP->caps()->usePrimitiveRestart()) { + return onFlushRP->findOrMakeStaticBuffer(kIndex_GrBufferType, sizeof(kOctoIndicesAsStrips), + kOctoIndicesAsStrips, gIndexBufferKey); + } else { + return onFlushRP->findOrMakeStaticBuffer(kIndex_GrBufferType, sizeof(kOctoIndicesAsTris), + kOctoIndicesAsTris, gIndexBufferKey); + } +} + +int GrCCPathProcessor::NumIndicesPerInstance(const GrCaps& caps) { + return caps.usePrimitiveRestart() ? SK_ARRAY_COUNT(kOctoIndicesAsStrips) + : SK_ARRAY_COUNT(kOctoIndicesAsTris); } -GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* rp, sk_sp<GrTextureProxy> atlas, - SkPath::FillType fillType, const GrShaderCaps& shaderCaps) +GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* resourceProvider, + sk_sp<GrTextureProxy> atlas, SkPath::FillType fillType) : INHERITED(kGrCCPathProcessor_ClassID) , fFillType(fillType) , fAtlasAccess(std::move(atlas), GrSamplerState::Filter::kNearest, @@ -91,8 +110,12 @@ GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* rp, sk_sp<GrTextureProx this->addVertexAttrib("edge_norms", kFloat4_GrVertexAttribType); - fAtlasAccess.instantiate(rp); + fAtlasAccess.instantiate(resourceProvider); this->addTextureSampler(&fAtlasAccess); + + if (resourceProvider->caps()->usePrimitiveRestart()) { + this->setWillUsePrimitiveRestart(); + } } void GrCCPathProcessor::getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { diff --git a/src/gpu/ccpr/GrCCPathProcessor.h b/src/gpu/ccpr/GrCCPathProcessor.h index 0b89358f25..644fbbab2d 100644 --- a/src/gpu/ccpr/GrCCPathProcessor.h +++ b/src/gpu/ccpr/GrCCPathProcessor.h @@ -8,12 +8,12 @@ #ifndef GrCCPathProcessor_DEFINED #define GrCCPathProcessor_DEFINED +#include "GrCaps.h" #include "GrGeometryProcessor.h" #include "SkPath.h" #include <array> class GrOnFlushResourceProvider; -class GrShaderCaps; /** * This class draws AA paths using the coverage count masks produced by GrCCCoverageProcessor. @@ -22,12 +22,10 @@ class GrShaderCaps; * fill rule. * * The caller must set up an instance buffer as detailed below, then draw indexed-instanced - * triangles using the index and vertex buffers provided by this class. + * meshes using the buffers and parameters provided by this class. */ class GrCCPathProcessor : public GrGeometryProcessor { public: - static constexpr int kPerInstanceIndexCount = 6 * 3; - enum class InstanceAttribs { kDevBounds, kDevBounds45, @@ -52,11 +50,15 @@ public: GR_STATIC_ASSERT(4 * 16 == sizeof(Instance)); - static sk_sp<const GrBuffer> FindIndexBuffer(GrOnFlushResourceProvider*); + static GrPrimitiveType MeshPrimitiveType(const GrCaps& caps) { + return caps.usePrimitiveRestart() ? GrPrimitiveType::kTriangleStrip + : GrPrimitiveType::kTriangles; + } static sk_sp<const GrBuffer> FindVertexBuffer(GrOnFlushResourceProvider*); + static sk_sp<const GrBuffer> FindIndexBuffer(GrOnFlushResourceProvider*); + static int NumIndicesPerInstance(const GrCaps&); - GrCCPathProcessor(GrResourceProvider*, sk_sp<GrTextureProxy> atlas, SkPath::FillType, - const GrShaderCaps&); + GrCCPathProcessor(GrResourceProvider*, sk_sp<GrTextureProxy> atlas, SkPath::FillType); const char* name() const override { return "GrCCPathProcessor"; } const GrSurfaceProxy* atlasProxy() const { return fAtlasAccess.proxy(); } diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index d78f28abd0..abe888044e 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -528,18 +528,17 @@ void CCPR::DrawPathsOp::onExecute(GrOpFlushState* flushState) { continue; // Atlas failed to allocate. } - GrCCPathProcessor coverProc(flushState->resourceProvider(), - sk_ref_sp(batch.fAtlas->textureProxy()), this->getFillType(), - *flushState->gpu()->caps()->shaderCaps()); + GrCCPathProcessor pathProc(flushState->resourceProvider(), + sk_ref_sp(batch.fAtlas->textureProxy()), this->getFillType()); - GrMesh mesh(GrPrimitiveType::kTriangles); + GrMesh mesh(GrCCPathProcessor::MeshPrimitiveType(flushState->caps())); mesh.setIndexedInstanced(fCCPR->fPerFlushIndexBuffer.get(), - GrCCPathProcessor::kPerInstanceIndexCount, + GrCCPathProcessor::NumIndicesPerInstance(flushState->caps()), fCCPR->fPerFlushInstanceBuffer.get(), batch.fEndInstanceIdx - baseInstance, baseInstance); mesh.setVertexData(fCCPR->fPerFlushVertexBuffer.get()); - flushState->rtCommandBuffer()->draw(pipeline, coverProc, &mesh, nullptr, 1, this->bounds()); + flushState->rtCommandBuffer()->draw(pipeline, pathProc, &mesh, nullptr, 1, this->bounds()); } SkASSERT(baseInstance == fBaseInstance + fInstanceCount - fNumSkippedInstances); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 4c1137eae1..6cacb1af9a 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -137,6 +137,17 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fInvalidateFBType = kDiscard_InvalidateFBType; } + // For future reference on Desktop GL, GL_PRIMITIVE_RESTART_FIXED_INDEX appears in 4.3, and + // GL_PRIMITIVE_RESTART (where the client must call glPrimitiveRestartIndex) appears in 3.1. + if (kGLES_GrGLStandard == standard) { + // Primitive restart can cause a 3x slowdown on Adreno. Enable conservatively. + // TODO: Evaluate on PowerVR. + // FIXME: Primitive restart would likely be a win on iOS if we had an enum value for it. + if (kARM_GrGLVendor == ctxInfo.vendor()) { + fUsePrimitiveRestart = version >= GR_GL_VER(3,0); + } + } + if (kARM_GrGLVendor == ctxInfo.vendor() || kImagination_GrGLVendor == ctxInfo.vendor() || kQualcomm_GrGLVendor == ctxInfo.vendor() ) { diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h index db6abd482f..51ab7fb300 100644 --- a/src/gpu/gl/GrGLDefines.h +++ b/src/gpu/gl/GrGLDefines.h @@ -832,6 +832,7 @@ #define GR_GL_T2F_N3F_V3F 0x2A2B #define GR_GL_T2F_C4F_N3F_V3F 0x2A2C #define GR_GL_T4F_C4F_N3F_V4F 0x2A2D +#define GR_GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 /* Buffer Object */ #define GR_GL_READ_ONLY 0x88B8 diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 212826d0dd..0037ca1681 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -1865,6 +1865,8 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc, int baseVertex, const GrBuffer* instanceBuffer, int baseInstance) { + using EnablePrimitiveRestart = GrGLAttribArrayState::EnablePrimitiveRestart; + GrGLAttribArrayState* attribState; if (indexBuffer) { SkASSERT(indexBuffer && !indexBuffer->isMapped()); @@ -1893,7 +1895,8 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc, } int numAttribs = primProc.numAttribs(); - attribState->enableVertexArrays(this, numAttribs); + auto enableRestart = EnablePrimitiveRestart(primProc.willUsePrimitiveRestart() && indexBuffer); + attribState->enableVertexArrays(this, numAttribs, enableRestart); for (int i = 0; i < numAttribs; ++i) { using InputRate = GrPrimitiveProcessor::Attribute::InputRate; diff --git a/src/gpu/gl/GrGLVertexArray.cpp b/src/gpu/gl/GrGLVertexArray.cpp index fa318c58bf..dbfa0f4f4a 100644 --- a/src/gpu/gl/GrGLVertexArray.cpp +++ b/src/gpu/gl/GrGLVertexArray.cpp @@ -149,24 +149,39 @@ void GrGLAttribArrayState::set(GrGLGpu* gpu, } } -void GrGLAttribArrayState::enableVertexArrays(const GrGLGpu* gpu, int enabledCount) { +void GrGLAttribArrayState::enableVertexArrays(const GrGLGpu* gpu, int enabledCount, + EnablePrimitiveRestart enablePrimitiveRestart) { SkASSERT(enabledCount <= fAttribArrayStates.count()); - if (fEnabledCountIsValid && enabledCount == fNumEnabledArrays) { - return; - } - int firstIdxToEnable = fEnabledCountIsValid ? fNumEnabledArrays : 0; - for (int i = firstIdxToEnable; i < enabledCount; ++i) { - GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(i)); + if (!fEnableStateIsValid || enabledCount != fNumEnabledArrays) { + int firstIdxToEnable = fEnableStateIsValid ? fNumEnabledArrays : 0; + for (int i = firstIdxToEnable; i < enabledCount; ++i) { + GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(i)); + } + + int endIdxToDisable = fEnableStateIsValid ? fNumEnabledArrays : fAttribArrayStates.count(); + for (int i = enabledCount; i < endIdxToDisable; ++i) { + GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i)); + } + + fNumEnabledArrays = enabledCount; } - int endIdxToDisable = fEnabledCountIsValid ? fNumEnabledArrays : fAttribArrayStates.count(); - for (int i = enabledCount; i < endIdxToDisable; ++i) { - GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i)); + SkASSERT(EnablePrimitiveRestart::kNo == enablePrimitiveRestart || + gpu->caps()->usePrimitiveRestart()); + + if (gpu->caps()->usePrimitiveRestart() && + (!fEnableStateIsValid || enablePrimitiveRestart != fPrimitiveRestartEnabled)) { + if (EnablePrimitiveRestart::kYes == enablePrimitiveRestart) { + GR_GL_CALL(gpu->glInterface(), Enable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX)); + } else { + GR_GL_CALL(gpu->glInterface(), Disable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX)); + } + + fPrimitiveRestartEnabled = enablePrimitiveRestart; } - fNumEnabledArrays = enabledCount; - fEnabledCountIsValid = true; + fEnableStateIsValid = true; } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h index 553df4f3fd..20b21ae47b 100644 --- a/src/gpu/gl/GrGLVertexArray.h +++ b/src/gpu/gl/GrGLVertexArray.h @@ -45,17 +45,23 @@ public: size_t offsetInBytes, int divisor = 0); + enum class EnablePrimitiveRestart : bool { + kYes = true, + kNo = false + }; + /** * This function enables the first 'enabledCount' vertex arrays and disables the rest. */ - void enableVertexArrays(const GrGLGpu*, int enabledCount); + void enableVertexArrays(const GrGLGpu*, int enabledCount, + EnablePrimitiveRestart = EnablePrimitiveRestart::kNo); void invalidate() { int count = fAttribArrayStates.count(); for (int i = 0; i < count; ++i) { fAttribArrayStates[i].invalidate(); } - fEnabledCountIsValid = false; + fEnableStateIsValid = false; } /** @@ -82,9 +88,10 @@ private: int fDivisor; }; - SkSTArray<16, AttribArrayState, true> fAttribArrayStates; - int fNumEnabledArrays; - bool fEnabledCountIsValid; + SkSTArray<16, AttribArrayState, true> fAttribArrayStates; + int fNumEnabledArrays; + EnablePrimitiveRestart fPrimitiveRestartEnabled; + bool fEnableStateIsValid = false; }; /** |