aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/gpu/GrCaps.h6
-rw-r--r--samplecode/SampleCCPRGeometry.cpp9
-rw-r--r--src/gpu/GrCaps.cpp2
-rw-r--r--src/gpu/GrGpuCommandBuffer.cpp1
-rw-r--r--src/gpu/GrPrimitiveProcessor.h11
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.h23
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp109
-rw-r--r--src/gpu/ccpr/GrCCPathParser.cpp5
-rw-r--r--src/gpu/ccpr/GrCCPathProcessor.cpp43
-rw-r--r--src/gpu/ccpr/GrCCPathProcessor.h16
-rw-r--r--src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp11
-rw-r--r--src/gpu/gl/GrGLCaps.cpp11
-rw-r--r--src/gpu/gl/GrGLDefines.h1
-rw-r--r--src/gpu/gl/GrGLGpu.cpp5
-rw-r--r--src/gpu/gl/GrGLVertexArray.cpp39
-rw-r--r--src/gpu/gl/GrGLVertexArray.h17
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;
};
/**