Index: src/gpu/GrOvalRenderer.cpp |
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp |
index b8c3d3eeb8fc3f9972db37d41284c0959985d8b5..35f86603ff56c52909c2761faef8fb67c7b3494c 100644 |
--- a/src/gpu/GrOvalRenderer.cpp |
+++ b/src/gpu/GrOvalRenderer.cpp |
@@ -1362,7 +1362,7 @@ private: |
// |
// We don't draw the center quad from the fill rect in this case. |
-static const uint16_t gRRectOverstrokeIndices[] = { |
+static const uint16_t gOverstrokeRRectIndices[] = { |
// overstroke quads |
// we place this at the beginning so that we can skip these indices when rendering normally |
16, 17, 19, 16, 19, 18, |
@@ -1386,46 +1386,52 @@ static const uint16_t gRRectOverstrokeIndices[] = { |
// we place this at the end so that we can ignore these indices when not rendering as filled |
5, 6, 10, 5, 10, 9, |
}; |
+// fill and standard stroke indices skip the overstroke "ring" |
+static const uint16_t* gStandardRRectIndices = gOverstrokeRRectIndices + 6*4; |
-static const uint16_t* gRRectIndices = gRRectOverstrokeIndices + 6*4; |
- |
-// overstroke count is arraysize |
-static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectOverstrokeIndices) - 6; |
+// overstroke count is arraysize minus the center indices |
+static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gOverstrokeRRectIndices) - 6; |
+// fill count skips overstroke indices and includes center |
static const int kIndicesPerFillRRect = kIndicesPerOverstrokeRRect - 6*4 + 6; |
+// stroke count is fill count minus center indices |
static const int kIndicesPerStrokeRRect = kIndicesPerFillRRect - 6; |
static const int kVertsPerStandardRRect = 16; |
static const int kVertsPerOverstrokeRRect = 24; |
-static const int kNumRRectsInIndexBuffer = 256; |
enum RRectType { |
kFill_RRectType, |
kStroke_RRectType, |
- kOverstroke_RRectType |
+ kOverstroke_RRectType, |
}; |
-GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey); |
-GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey); |
-GR_DECLARE_STATIC_UNIQUE_KEY(gOverstrokeRRectOnlyIndexBufferKey); |
-static const GrBuffer* ref_rrect_index_buffer(RRectType type, |
- GrResourceProvider* resourceProvider) { |
- GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey); |
- GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey); |
- GR_DEFINE_STATIC_UNIQUE_KEY(gOverstrokeRRectOnlyIndexBufferKey); |
- switch (type) { |
- case kFill_RRectType: |
- default: |
- return resourceProvider->findOrCreateInstancedIndexBuffer( |
- gRRectIndices, kIndicesPerFillRRect, kNumRRectsInIndexBuffer, |
- kVertsPerStandardRRect, gRRectOnlyIndexBufferKey); |
- case kStroke_RRectType: |
- return resourceProvider->findOrCreateInstancedIndexBuffer( |
- gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, |
- kVertsPerStandardRRect, gStrokeRRectOnlyIndexBufferKey); |
- case kOverstroke_RRectType: |
- return resourceProvider->findOrCreateInstancedIndexBuffer( |
- gRRectOverstrokeIndices, kIndicesPerOverstrokeRRect, kNumRRectsInIndexBuffer, |
- kVertsPerOverstrokeRRect, gOverstrokeRRectOnlyIndexBufferKey); |
+static int rrect_type_to_vert_count(RRectType type) { |
+ static const int kTypeToVertCount[] = { |
+ kVertsPerStandardRRect, |
+ kVertsPerStandardRRect, |
+ kVertsPerOverstrokeRRect, |
}; |
+ |
+ return kTypeToVertCount[type]; |
+} |
+ |
+static int rrect_type_to_index_count(RRectType type) { |
+ static const int kTypeToIndexCount[] = { |
+ kIndicesPerFillRRect, |
+ kIndicesPerStrokeRRect, |
+ kIndicesPerOverstrokeRRect, |
+ }; |
+ |
+ return kTypeToIndexCount[type]; |
+} |
+ |
+static const uint16_t* rrect_type_to_indices(RRectType type) { |
+ static const uint16_t* kTypeToIndices[] = { |
+ gStandardRRectIndices, |
+ gStandardRRectIndices, |
+ gOverstrokeRRectIndices, |
+ }; |
+ |
+ return kTypeToIndices[type]; |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
@@ -1445,7 +1451,7 @@ public: |
SkScalar innerRadius = 0.0f; |
SkScalar outerRadius = devRadius; |
SkScalar halfWidth = 0; |
- fType = kFill_RRectType; |
+ RRectType type = kFill_RRectType; |
if (devStrokeWidth > 0) { |
if (SkScalarNearlyZero(devStrokeWidth)) { |
halfWidth = SK_ScalarHalf; |
@@ -1461,7 +1467,7 @@ public: |
if (devStrokeWidth <= devRect.width() && |
devStrokeWidth <= devRect.height()) { |
innerRadius = devRadius - halfWidth; |
- fType = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRectType; |
+ type = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRectType; |
} |
} |
outerRadius += halfWidth; |
@@ -1481,7 +1487,10 @@ public: |
// Expand the rect for aa to generate correct vertices. |
bounds.outset(SK_ScalarHalf, SK_ScalarHalf); |
- fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds }); |
+ fGeoData.emplace_back(Geometry{ color, innerRadius, outerRadius, bounds, type }); |
+ fVertCount = rrect_type_to_vert_count(type); |
+ fIndexCount = rrect_type_to_index_count(type); |
+ fAllFill = (kFill_RRectType == type); |
} |
const char* name() const override { return "RRectCircleBatch"; } |
@@ -1526,10 +1535,9 @@ private: |
} |
// Setup geometry processor |
- SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(kFill_RRectType != fType, |
+ SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fAllFill, |
false, false, |
false, localMatrix)); |
- |
struct CircleVertex { |
SkPoint fPos; |
GrColor fColor; |
@@ -1541,29 +1549,27 @@ private: |
int instanceCount = fGeoData.count(); |
size_t vertexStride = gp->getVertexStride(); |
- SkASSERT(vertexStride == sizeof(CircleVertex)); |
+ SkASSERT(sizeof(CircleVertex) == vertexStride); |
- // drop out the middle quad if we're stroked |
- int indicesPerInstance = kIndicesPerFillRRect; |
- if (kStroke_RRectType == fType) { |
- indicesPerInstance = kIndicesPerStrokeRRect; |
- } else if (kOverstroke_RRectType == fType) { |
- indicesPerInstance = kIndicesPerOverstrokeRRect; |
- } |
- SkAutoTUnref<const GrBuffer> indexBuffer( |
- ref_rrect_index_buffer(fType, target->resourceProvider())); |
+ const GrBuffer* vertexBuffer; |
+ int firstVertex; |
- InstancedHelper helper; |
- int vertexCount = (kOverstroke_RRectType == fType) ? kVertsPerOverstrokeRRect |
- : kVertsPerStandardRRect; |
- CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target, |
- kTriangles_GrPrimitiveType, vertexStride, indexBuffer, vertexCount, |
- indicesPerInstance, instanceCount)); |
- if (!verts || !indexBuffer) { |
+ CircleVertex* verts = (CircleVertex*) target->makeVertexSpace(vertexStride, fVertCount, |
+ &vertexBuffer, &firstVertex); |
+ if (!verts) { |
SkDebugf("Could not allocate vertices\n"); |
return; |
} |
+ const GrBuffer* indexBuffer = nullptr; |
+ int firstIndex = 0; |
+ uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); |
+ if (!indices) { |
+ SkDebugf("Could not allocate indices\n"); |
+ return; |
+ } |
+ |
+ int currStartVertex = 0; |
for (int i = 0; i < instanceCount; i++) { |
const Geometry& args = fGeoData[i]; |
@@ -1581,7 +1587,10 @@ private: |
SkScalar yOuterRadii[4] = {-1, 0, 0, 1 }; |
// The inner radius in the vertex data must be specified in normalized space. |
- SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius; |
+ // For fills, specifying -1/outerRadius guarantees an alpha of 1.0 at the inner radius. |
+ SkScalar innerRadius = args.fType != kFill_RRectType |
+ ? args.fInnerRadius / args.fOuterRadius |
+ : -1.0f / args.fOuterRadius; |
for (int i = 0; i < 4; ++i) { |
verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); |
verts->fColor = color; |
@@ -1619,11 +1628,11 @@ private: |
// |
// Also, the outer offset is a constant vector pointing to the right, which |
// guarantees that the distance value along the outer rectangle is constant. |
- if (kOverstroke_RRectType == fType) { |
+ if (kOverstroke_RRectType == args.fType) { |
SkScalar overstrokeOuterRadius = outerRadius - args.fInnerRadius; |
// this is the normalized distance from the outer rectangle of this |
// geometry to the outer edge |
- SkScalar maxOffset = -args.fInnerRadius/overstrokeOuterRadius; |
+ SkScalar maxOffset = -args.fInnerRadius / overstrokeOuterRadius; |
verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[1]); |
verts->fColor = color; |
@@ -1685,9 +1694,20 @@ private: |
verts->fInnerRadius = 0; |
verts++; |
} |
+ |
+ const uint16_t* primIndices = rrect_type_to_indices(args.fType); |
+ const int primIndexCount = rrect_type_to_index_count(args.fType); |
+ for (int i = 0; i < primIndexCount; ++i) { |
+ *indices++ = primIndices[i] + currStartVertex; |
+ } |
+ |
+ currStartVertex += rrect_type_to_vert_count(args.fType); |
} |
- helper.recordDraw(target, gp); |
+ GrMesh mesh; |
+ mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, |
+ firstIndex, fVertCount, fIndexCount); |
+ target->draw(gp.get(), mesh); |
} |
bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
@@ -1697,16 +1717,15 @@ private: |
return false; |
} |
- if (fType != that->fType) { |
- return false; |
- } |
- |
if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) { |
return false; |
} |
fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); |
this->joinBounds(*that); |
+ fVertCount += that->fVertCount; |
+ fIndexCount += that->fIndexCount; |
+ fAllFill = fAllFill && that->fAllFill; |
return true; |
} |
@@ -1715,15 +1734,41 @@ private: |
SkScalar fInnerRadius; |
SkScalar fOuterRadius; |
SkRect fDevBounds; |
+ RRectType fType; |
}; |
- RRectType fType; |
- SkMatrix fViewMatrixIfUsingLocalCoords; |
SkSTArray<1, Geometry, true> fGeoData; |
+ SkMatrix fViewMatrixIfUsingLocalCoords; |
+ int fVertCount; |
+ int fIndexCount; |
+ bool fAllFill; |
typedef GrVertexBatch INHERITED; |
}; |
+static const int kNumRRectsInIndexBuffer = 256; |
+ |
+GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey); |
+GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey); |
+static const GrBuffer* ref_rrect_index_buffer(RRectType type, |
+ GrResourceProvider* resourceProvider) { |
+ GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey); |
+ GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey); |
+ switch (type) { |
+ case kFill_RRectType: |
+ return resourceProvider->findOrCreateInstancedIndexBuffer( |
+ gStandardRRectIndices, kIndicesPerFillRRect, kNumRRectsInIndexBuffer, |
+ kVertsPerStandardRRect, gRRectOnlyIndexBufferKey); |
+ case kStroke_RRectType: |
+ return resourceProvider->findOrCreateInstancedIndexBuffer( |
+ gStandardRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, |
+ kVertsPerStandardRRect, gStrokeRRectOnlyIndexBufferKey); |
+ default: |
+ SkASSERT(false); |
+ return nullptr; |
+ }; |
+} |
+ |
class RRectEllipseRendererBatch : public GrVertexBatch { |
public: |
DEFINE_BATCH_CLASS_ID |