//
// 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,
// 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];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
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;
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;
// 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"; }
}
// 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;
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];
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;
//
// 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;
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 {
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;
}
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