| Index: src/gpu/GrOvalRenderer.cpp
|
| diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
|
| index b1ef8d34bda013eaa2543ed7eb7f36bfd97f7da6..f324018f450fa016d4a6dccf5972ca3fbac464e2 100644
|
| --- a/src/gpu/GrOvalRenderer.cpp
|
| +++ b/src/gpu/GrOvalRenderer.cpp
|
| @@ -7,12 +7,15 @@
|
|
|
| #include "GrOvalRenderer.h"
|
|
|
| -#include "GrProcessor.h"
|
| +#include "GrBatch.h"
|
| +#include "GrBatchTarget.h"
|
| +#include "GrBufferAllocPool.h"
|
| #include "GrDrawTarget.h"
|
| #include "GrGeometryProcessor.h"
|
| #include "GrGpu.h"
|
| #include "GrInvariantOutput.h"
|
| #include "GrPipelineBuilder.h"
|
| +#include "GrProcessor.h"
|
| #include "SkRRect.h"
|
| #include "SkStrokeRec.h"
|
| #include "SkTLazy.h"
|
| @@ -22,6 +25,8 @@
|
| #include "gl/GrGLGeometryProcessor.h"
|
| #include "gl/builders/GrGLProgramBuilder.h"
|
|
|
| +// TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup
|
| +
|
| namespace {
|
| // TODO(joshualitt) add per vertex colors
|
| struct CircleVertex {
|
| @@ -692,6 +697,199 @@ bool GrOvalRenderer::drawOval(GrDrawTarget* target,
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +class CircleBatch : public GrBatch {
|
| +public:
|
| + struct Geometry {
|
| + GrColor fColor;
|
| + SkMatrix fViewMatrix;
|
| + SkScalar fInnerRadius;
|
| + SkScalar fOuterRadius;
|
| + bool fStroke;
|
| + SkRect fDevBounds;
|
| + };
|
| +
|
| + static GrBatch* Create(const Geometry& geometry) {
|
| + return SkNEW_ARGS(CircleBatch, (geometry));
|
| + }
|
| +
|
| + const char* name() const SK_OVERRIDE { return "CircleBatch"; }
|
| +
|
| + void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + // When this is called on a batch, there is only one geometry bundle
|
| + out->setKnownFourComponents(fGeoData[0].fColor);
|
| + }
|
| +
|
| + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + out->setUnknownSingleComponent();
|
| + }
|
| +
|
| + void initBatchOpt(const GrBatchOpt& batchOpt) {
|
| + fBatchOpt = batchOpt;
|
| + }
|
| +
|
| + void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
|
| + // Handle any color overrides
|
| + if (init.fColorIgnored) {
|
| + fGeoData[0].fColor = GrColor_ILLEGAL;
|
| + } else if (GrColor_ILLEGAL != init.fOverrideColor) {
|
| + fGeoData[0].fColor = init.fOverrideColor;
|
| + }
|
| +
|
| + // setup batch properties
|
| + fBatch.fColorIgnored = init.fColorIgnored;
|
| + fBatch.fColor = fGeoData[0].fColor;
|
| + fBatch.fStroke = fGeoData[0].fStroke;
|
| + fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
|
| + fBatch.fCoverageIgnored = init.fCoverageIgnored;
|
| + }
|
| +
|
| + void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
|
| + SkMatrix invert;
|
| + if (!this->viewMatrix().invert(&invert)) {
|
| + return;
|
| + }
|
| +
|
| + // Setup geometry processor
|
| + SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
|
| + this->stroke(),
|
| + invert));
|
| +
|
| + batchTarget->initDraw(gp, pipeline);
|
| +
|
| + // TODO this is hacky, but the only way we have to initialize the GP is to use the
|
| + // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
|
| + // everywhere we can remove this nastiness
|
| + GrPipelineInfo init;
|
| + init.fColorIgnored = fBatch.fColorIgnored;
|
| + init.fOverrideColor = GrColor_ILLEGAL;
|
| + init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
| + init.fUsesLocalCoords = this->usesLocalCoords();
|
| + gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + int instanceCount = fGeoData.count();
|
| + int vertexCount = kVertsPerCircle * instanceCount;
|
| + size_t vertexStride = gp->getVertexStride();
|
| + SkASSERT(vertexStride == sizeof(CircleVertex));
|
| +
|
| + const GrVertexBuffer* vertexBuffer;
|
| + int firstVertex;
|
| +
|
| + void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
| + vertexCount,
|
| + &vertexBuffer,
|
| + &firstVertex);
|
| +
|
| + CircleVertex* verts = reinterpret_cast<CircleVertex*>(vertices);
|
| +
|
| + for (int i = 0; i < instanceCount; i++) {
|
| + Geometry& args = fGeoData[i];
|
| +
|
| + SkScalar innerRadius = args.fInnerRadius;
|
| + SkScalar outerRadius = args.fOuterRadius;
|
| +
|
| + const SkRect& bounds = args.fDevBounds;
|
| +
|
| + // The inner radius in the vertex data must be specified in normalized space.
|
| + innerRadius = innerRadius / outerRadius;
|
| + verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
|
| + verts[0].fOffset = SkPoint::Make(-1, -1);
|
| + verts[0].fOuterRadius = outerRadius;
|
| + verts[0].fInnerRadius = innerRadius;
|
| +
|
| + verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
|
| + verts[1].fOffset = SkPoint::Make(-1, 1);
|
| + verts[1].fOuterRadius = outerRadius;
|
| + verts[1].fInnerRadius = innerRadius;
|
| +
|
| + verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
|
| + verts[2].fOffset = SkPoint::Make(1, 1);
|
| + verts[2].fOuterRadius = outerRadius;
|
| + verts[2].fInnerRadius = innerRadius;
|
| +
|
| + verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
|
| + verts[3].fOffset = SkPoint::Make(1, -1);
|
| + verts[3].fOuterRadius = outerRadius;
|
| + verts[3].fInnerRadius = innerRadius;
|
| +
|
| + verts += kVertsPerCircle;
|
| + }
|
| +
|
| + const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
|
| +
|
| + GrDrawTarget::DrawInfo drawInfo;
|
| + drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
|
| + drawInfo.setStartVertex(0);
|
| + drawInfo.setStartIndex(0);
|
| + drawInfo.setVerticesPerInstance(kVertsPerCircle);
|
| + drawInfo.setIndicesPerInstance(kIndicesPerCircle);
|
| + drawInfo.adjustStartVertex(firstVertex);
|
| + drawInfo.setVertexBuffer(vertexBuffer);
|
| + drawInfo.setIndexBuffer(quadIndexBuffer);
|
| +
|
| + int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
|
| +
|
| + while (instanceCount) {
|
| + drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
|
| + drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
|
| + drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
|
| +
|
| + batchTarget->draw(drawInfo);
|
| +
|
| + drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
|
| + instanceCount -= drawInfo.instanceCount();
|
| + }
|
| + }
|
| +
|
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| +
|
| +private:
|
| + CircleBatch(const Geometry& geometry) {
|
| + this->initClassID<CircleBatch>();
|
| + fGeoData.push_back(geometry);
|
| + }
|
| +
|
| + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
|
| + CircleBatch* that = t->cast<CircleBatch>();
|
| +
|
| + // TODO use vertex color to avoid breaking batches
|
| + if (this->color() != that->color()) {
|
| + return false;
|
| + }
|
| +
|
| + if (this->stroke() != that->stroke()) {
|
| + return false;
|
| + }
|
| +
|
| + SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
| + if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
| + return false;
|
| + }
|
| +
|
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| + return true;
|
| + }
|
| +
|
| + GrColor color() const { return fBatch.fColor; }
|
| + bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| + const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
|
| + bool stroke() const { return fBatch.fStroke; }
|
| +
|
| + struct BatchTracker {
|
| + GrColor fColor;
|
| + bool fStroke;
|
| + bool fUsesLocalCoords;
|
| + bool fColorIgnored;
|
| + bool fCoverageIgnored;
|
| + };
|
| +
|
| + static const int kVertsPerCircle = 4;
|
| + static const int kIndicesPerCircle = 6;
|
| +
|
| + GrBatchOpt fBatchOpt;
|
| + BatchTracker fBatch;
|
| + SkSTArray<1, Geometry, true> fGeoData;
|
| +};
|
| +
|
| void GrOvalRenderer::drawCircle(GrDrawTarget* target,
|
| GrPipelineBuilder* pipelineBuilder,
|
| GrColor color,
|
| @@ -704,11 +902,6 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
|
| SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
|
| SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
|
|
|
| - SkMatrix invert;
|
| - if (!viewMatrix.invert(&invert)) {
|
| - return;
|
| - }
|
| -
|
| SkStrokeRec::Style style = stroke.getStyle();
|
| bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
|
| SkStrokeRec::kHairline_Style == style;
|
| @@ -730,18 +923,6 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
|
| }
|
| }
|
|
|
| - SkAutoTUnref<GrGeometryProcessor> gp(
|
| - CircleEdgeEffect::Create(color, isStrokeOnly && innerRadius > 0,invert));
|
| -
|
| - GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0);
|
| - SkASSERT(gp->getVertexStride() == sizeof(CircleVertex));
|
| - if (!geo.succeeded()) {
|
| - SkDebugf("Failed to get space for vertices!\n");
|
| - return;
|
| - }
|
| -
|
| - CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
|
| -
|
| // The radii are outset for two reasons. First, it allows the shader to simply perform simpler
|
| // computation because the computed alpha is zero, rather than 50%, at the radius.
|
| // Second, the outer radius is used to compute the verts of the bounding box that is rendered
|
| @@ -756,35 +937,220 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
|
| center.fY + outerRadius
|
| );
|
|
|
| - // The inner radius in the vertex data must be specified in normalized space.
|
| - innerRadius = innerRadius / outerRadius;
|
| - verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
|
| - verts[0].fOffset = SkPoint::Make(-1, -1);
|
| - verts[0].fOuterRadius = outerRadius;
|
| - verts[0].fInnerRadius = innerRadius;
|
| -
|
| - verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
|
| - verts[1].fOffset = SkPoint::Make(-1, 1);
|
| - verts[1].fOuterRadius = outerRadius;
|
| - verts[1].fInnerRadius = innerRadius;
|
| -
|
| - verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
|
| - verts[2].fOffset = SkPoint::Make(1, 1);
|
| - verts[2].fOuterRadius = outerRadius;
|
| - verts[2].fInnerRadius = innerRadius;
|
| -
|
| - verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
|
| - verts[3].fOffset = SkPoint::Make(1, -1);
|
| - verts[3].fOuterRadius = outerRadius;
|
| - verts[3].fInnerRadius = innerRadius;
|
| -
|
| - target->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer());
|
| - target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
|
| - target->resetIndexSource();
|
| + CircleBatch::Geometry geometry;
|
| + geometry.fViewMatrix = viewMatrix;
|
| + geometry.fColor = color;
|
| + geometry.fInnerRadius = innerRadius;
|
| + geometry.fOuterRadius = outerRadius;
|
| + geometry.fStroke = isStrokeOnly && innerRadius > 0;
|
| + geometry.fDevBounds = bounds;
|
| +
|
| + SkAutoTUnref<GrBatch> batch(CircleBatch::Create(geometry));
|
| + target->drawBatch(pipelineBuilder, batch, &bounds);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +class EllipseBatch : public GrBatch {
|
| +public:
|
| + struct Geometry {
|
| + GrColor fColor;
|
| + SkMatrix fViewMatrix;
|
| + SkScalar fXRadius;
|
| + SkScalar fYRadius;
|
| + SkScalar fInnerXRadius;
|
| + SkScalar fInnerYRadius;
|
| + bool fStroke;
|
| + SkRect fDevBounds;
|
| + };
|
| +
|
| + static GrBatch* Create(const Geometry& geometry) {
|
| + return SkNEW_ARGS(EllipseBatch, (geometry));
|
| + }
|
| +
|
| + const char* name() const SK_OVERRIDE { return "EllipseBatch"; }
|
| +
|
| + void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + // When this is called on a batch, there is only one geometry bundle
|
| + out->setKnownFourComponents(fGeoData[0].fColor);
|
| + }
|
| + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + out->setUnknownSingleComponent();
|
| + }
|
| +
|
| + void initBatchOpt(const GrBatchOpt& batchOpt) {
|
| + fBatchOpt = batchOpt;
|
| + }
|
| +
|
| + void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
|
| + // Handle any color overrides
|
| + if (init.fColorIgnored) {
|
| + fGeoData[0].fColor = GrColor_ILLEGAL;
|
| + } else if (GrColor_ILLEGAL != init.fOverrideColor) {
|
| + fGeoData[0].fColor = init.fOverrideColor;
|
| + }
|
| +
|
| + // setup batch properties
|
| + fBatch.fColorIgnored = init.fColorIgnored;
|
| + fBatch.fColor = fGeoData[0].fColor;
|
| + fBatch.fStroke = fGeoData[0].fStroke;
|
| + fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
|
| + fBatch.fCoverageIgnored = init.fCoverageIgnored;
|
| + }
|
| +
|
| + void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
|
| + SkMatrix invert;
|
| + if (!this->viewMatrix().invert(&invert)) {
|
| + return;
|
| + }
|
| +
|
| + // Setup geometry processor
|
| + SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
|
| + this->stroke(),
|
| + invert));
|
| + SkASSERT(gp->getVertexStride() == sizeof(EllipseVertex));
|
| +
|
| + batchTarget->initDraw(gp, pipeline);
|
| +
|
| + // TODO this is hacky, but the only way we have to initialize the GP is to use the
|
| + // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
|
| + // everywhere we can remove this nastiness
|
| + GrPipelineInfo init;
|
| + init.fColorIgnored = fBatch.fColorIgnored;
|
| + init.fOverrideColor = GrColor_ILLEGAL;
|
| + init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
| + init.fUsesLocalCoords = this->usesLocalCoords();
|
| + gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + int instanceCount = fGeoData.count();
|
| + int vertexCount = kVertsPerEllipse * instanceCount;
|
| + size_t vertexStride = gp->getVertexStride();
|
| + SkASSERT(vertexStride == sizeof(CircleVertex));
|
| +
|
| + const GrVertexBuffer* vertexBuffer;
|
| + int firstVertex;
|
| +
|
| + void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
| + vertexCount,
|
| + &vertexBuffer,
|
| + &firstVertex);
|
| +
|
| + EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(vertices);
|
| +
|
| + for (int i = 0; i < instanceCount; i++) {
|
| + Geometry& args = fGeoData[i];
|
| +
|
| + SkScalar xRadius = args.fXRadius;
|
| + SkScalar yRadius = args.fYRadius;
|
| +
|
| + // Compute the reciprocals of the radii here to save time in the shader
|
| + SkScalar xRadRecip = SkScalarInvert(xRadius);
|
| + SkScalar yRadRecip = SkScalarInvert(yRadius);
|
| + SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
|
| + SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
|
| +
|
| + const SkRect& bounds = args.fDevBounds;
|
| +
|
| + // The inner radius in the vertex data must be specified in normalized space.
|
| + verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
|
| + verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
|
| + verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| +
|
| + verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
|
| + verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
|
| + verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| +
|
| + verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
|
| + verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
|
| + verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| +
|
| + verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
|
| + verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
|
| + verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| +
|
| + verts += kVertsPerEllipse;
|
| + }
|
| +
|
| + const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
|
| +
|
| + GrDrawTarget::DrawInfo drawInfo;
|
| + drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
|
| + drawInfo.setStartVertex(0);
|
| + drawInfo.setStartIndex(0);
|
| + drawInfo.setVerticesPerInstance(kVertsPerEllipse);
|
| + drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
|
| + drawInfo.adjustStartVertex(firstVertex);
|
| + drawInfo.setVertexBuffer(vertexBuffer);
|
| + drawInfo.setIndexBuffer(quadIndexBuffer);
|
| +
|
| + int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
|
| +
|
| + while (instanceCount) {
|
| + drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
|
| + drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
|
| + drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
|
| +
|
| + batchTarget->draw(drawInfo);
|
| +
|
| + drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
|
| + instanceCount -= drawInfo.instanceCount();
|
| + }
|
| + }
|
| +
|
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| +
|
| +private:
|
| + EllipseBatch(const Geometry& geometry) {
|
| + this->initClassID<EllipseBatch>();
|
| + fGeoData.push_back(geometry);
|
| + }
|
| +
|
| + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
|
| + EllipseBatch* that = t->cast<EllipseBatch>();
|
| +
|
| + // TODO use vertex color to avoid breaking batches
|
| + if (this->color() != that->color()) {
|
| + return false;
|
| + }
|
| +
|
| + if (this->stroke() != that->stroke()) {
|
| + return false;
|
| + }
|
| +
|
| + SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
| + if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
| + return false;
|
| + }
|
| +
|
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| + return true;
|
| + }
|
| +
|
| + GrColor color() const { return fBatch.fColor; }
|
| + bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| + const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
|
| + bool stroke() const { return fBatch.fStroke; }
|
| +
|
| + struct BatchTracker {
|
| + GrColor fColor;
|
| + bool fStroke;
|
| + bool fUsesLocalCoords;
|
| + bool fColorIgnored;
|
| + bool fCoverageIgnored;
|
| + };
|
| +
|
| + static const int kVertsPerEllipse = 4;
|
| + static const int kIndicesPerEllipse = 6;
|
| +
|
| + GrBatchOpt fBatchOpt;
|
| + BatchTracker fBatch;
|
| + SkSTArray<1, Geometry, true> fGeoData;
|
| +};
|
| +
|
| bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
|
| GrPipelineBuilder* pipelineBuilder,
|
| GrColor color,
|
| @@ -854,31 +1220,6 @@ bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
|
| yRadius += scaledStroke.fY;
|
| }
|
|
|
| - SkMatrix invert;
|
| - if (!viewMatrix.invert(&invert)) {
|
| - return false;
|
| - }
|
| -
|
| - SkAutoTUnref<GrGeometryProcessor> gp(
|
| - EllipseEdgeEffect::Create(color,
|
| - isStrokeOnly && innerXRadius > 0 && innerYRadius > 0,
|
| - invert));
|
| -
|
| - GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0);
|
| - SkASSERT(gp->getVertexStride() == sizeof(EllipseVertex));
|
| - if (!geo.succeeded()) {
|
| - SkDebugf("Failed to get space for vertices!\n");
|
| - return false;
|
| - }
|
| -
|
| - EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
|
| -
|
| - // Compute the reciprocals of the radii here to save time in the shader
|
| - SkScalar xRadRecip = SkScalarInvert(xRadius);
|
| - SkScalar yRadRecip = SkScalarInvert(yRadius);
|
| - SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
|
| - SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
|
| -
|
| // We've extended the outer x radius out half a pixel to antialias.
|
| // This will also expand the rect so all the pixels will be captured.
|
| // TODO: Consider if we should use sqrt(2)/2 instead
|
| @@ -892,32 +1233,217 @@ bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
|
| center.fY + yRadius
|
| );
|
|
|
| - verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
|
| - verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
|
| - verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| + EllipseBatch::Geometry geometry;
|
| + geometry.fViewMatrix = viewMatrix;
|
| + geometry.fColor = color;
|
| + geometry.fXRadius = xRadius;
|
| + geometry.fYRadius = yRadius;
|
| + geometry.fInnerXRadius = innerXRadius;
|
| + geometry.fInnerYRadius = innerYRadius;
|
| + geometry.fStroke = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
|
| + geometry.fDevBounds = bounds;
|
|
|
| - verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
|
| - verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
|
| - verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| + SkAutoTUnref<GrBatch> batch(EllipseBatch::Create(geometry));
|
| + target->drawBatch(pipelineBuilder, batch, &bounds);
|
|
|
| - verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
|
| - verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
|
| - verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| + return true;
|
| +}
|
|
|
| - verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
|
| - verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
|
| - verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| +/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
| - target->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer());
|
| - target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
|
| - target->resetIndexSource();
|
| +class DIEllipseBatch : public GrBatch {
|
| +public:
|
| + struct Geometry {
|
| + GrColor fColor;
|
| + SkMatrix fViewMatrix;
|
| + SkScalar fXRadius;
|
| + SkScalar fYRadius;
|
| + SkScalar fInnerXRadius;
|
| + SkScalar fInnerYRadius;
|
| + SkScalar fGeoDx;
|
| + SkScalar fGeoDy;
|
| + DIEllipseEdgeEffect::Mode fMode;
|
| + SkRect fDevBounds;
|
| + };
|
|
|
| - return true;
|
| -}
|
| + static GrBatch* Create(const Geometry& geometry) {
|
| + return SkNEW_ARGS(DIEllipseBatch, (geometry));
|
| + }
|
| +
|
| + const char* name() const SK_OVERRIDE { return "DIEllipseBatch"; }
|
| +
|
| + void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + // When this is called on a batch, there is only one geometry bundle
|
| + out->setKnownFourComponents(fGeoData[0].fColor);
|
| + }
|
| + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + out->setUnknownSingleComponent();
|
| + }
|
| +
|
| + void initBatchOpt(const GrBatchOpt& batchOpt) {
|
| + fBatchOpt = batchOpt;
|
| + }
|
| +
|
| + void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
|
| + // Handle any color overrides
|
| + if (init.fColorIgnored) {
|
| + fGeoData[0].fColor = GrColor_ILLEGAL;
|
| + } else if (GrColor_ILLEGAL != init.fOverrideColor) {
|
| + fGeoData[0].fColor = init.fOverrideColor;
|
| + }
|
| +
|
| + // setup batch properties
|
| + fBatch.fColorIgnored = init.fColorIgnored;
|
| + fBatch.fColor = fGeoData[0].fColor;
|
| + fBatch.fMode = fGeoData[0].fMode;
|
| + fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
|
| + fBatch.fCoverageIgnored = init.fCoverageIgnored;
|
| + }
|
| +
|
| + void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
|
| + // Setup geometry processor
|
| + SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->color(),
|
| + this->viewMatrix(),
|
| + this->mode()));
|
| +
|
| + SkASSERT(gp->getVertexStride() == sizeof(DIEllipseVertex));
|
| +
|
| + batchTarget->initDraw(gp, pipeline);
|
| +
|
| + // TODO this is hacky, but the only way we have to initialize the GP is to use the
|
| + // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
|
| + // everywhere we can remove this nastiness
|
| + GrPipelineInfo init;
|
| + init.fColorIgnored = fBatch.fColorIgnored;
|
| + init.fOverrideColor = GrColor_ILLEGAL;
|
| + init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
| + init.fUsesLocalCoords = this->usesLocalCoords();
|
| + gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + int instanceCount = fGeoData.count();
|
| + int vertexCount = kVertsPerEllipse * instanceCount;
|
| + size_t vertexStride = gp->getVertexStride();
|
| + SkASSERT(vertexStride == sizeof(CircleVertex));
|
| +
|
| + const GrVertexBuffer* vertexBuffer;
|
| + int firstVertex;
|
| +
|
| + void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
| + vertexCount,
|
| + &vertexBuffer,
|
| + &firstVertex);
|
| +
|
| + DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(vertices);
|
| +
|
| + for (int i = 0; i < instanceCount; i++) {
|
| + Geometry& args = fGeoData[i];
|
| +
|
| + SkScalar xRadius = args.fXRadius;
|
| + SkScalar yRadius = args.fYRadius;
|
| +
|
| + const SkRect& bounds = args.fDevBounds;
|
| +
|
| + // This adjusts the "radius" to include the half-pixel border
|
| + SkScalar offsetDx = SkScalarDiv(args.fGeoDx, xRadius);
|
| + SkScalar offsetDy = SkScalarDiv(args.fGeoDy, yRadius);
|
| +
|
| + SkScalar innerRatioX = SkScalarDiv(xRadius, args.fInnerXRadius);
|
| + SkScalar innerRatioY = SkScalarDiv(yRadius, args.fInnerYRadius);
|
| +
|
| + verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
|
| + verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
|
| + verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
|
| +
|
| + verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
|
| + verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
|
| + verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
|
| +
|
| + verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
|
| + verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
|
| + verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
|
| +
|
| + verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
|
| + verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
|
| + verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
|
| +
|
| + verts += kVertsPerEllipse;
|
| + }
|
| +
|
| + const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
|
| +
|
| + GrDrawTarget::DrawInfo drawInfo;
|
| + drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
|
| + drawInfo.setStartVertex(0);
|
| + drawInfo.setStartIndex(0);
|
| + drawInfo.setVerticesPerInstance(kVertsPerEllipse);
|
| + drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
|
| + drawInfo.adjustStartVertex(firstVertex);
|
| + drawInfo.setVertexBuffer(vertexBuffer);
|
| + drawInfo.setIndexBuffer(quadIndexBuffer);
|
| +
|
| + int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
|
| +
|
| + while (instanceCount) {
|
| + drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
|
| + drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
|
| + drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
|
| +
|
| + batchTarget->draw(drawInfo);
|
| +
|
| + drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
|
| + instanceCount -= drawInfo.instanceCount();
|
| + }
|
| + }
|
| +
|
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| +
|
| +private:
|
| + DIEllipseBatch(const Geometry& geometry) {
|
| + this->initClassID<DIEllipseBatch>();
|
| + fGeoData.push_back(geometry);
|
| + }
|
| +
|
| + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
|
| + DIEllipseBatch* that = t->cast<DIEllipseBatch>();
|
| +
|
| + // TODO use vertex color to avoid breaking batches
|
| + if (this->color() != that->color()) {
|
| + return false;
|
| + }
|
| +
|
| + if (this->mode() != that->mode()) {
|
| + return false;
|
| + }
|
| +
|
| + SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
| + if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
| + return false;
|
| + }
|
| +
|
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| + return true;
|
| + }
|
| +
|
| + GrColor color() const { return fBatch.fColor; }
|
| + bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| + const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
|
| + DIEllipseEdgeEffect::Mode mode() const { return fBatch.fMode; }
|
| +
|
| + struct BatchTracker {
|
| + GrColor fColor;
|
| + DIEllipseEdgeEffect::Mode fMode;
|
| + bool fUsesLocalCoords;
|
| + bool fColorIgnored;
|
| + bool fCoverageIgnored;
|
| + };
|
| +
|
| + static const int kVertsPerEllipse = 4;
|
| + static const int kIndicesPerEllipse = 6;
|
| +
|
| + GrBatchOpt fBatchOpt;
|
| + BatchTracker fBatch;
|
| + SkSTArray<1, Geometry, true> fGeoData;
|
| +};
|
|
|
| bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
|
| GrPipelineBuilder* pipelineBuilder,
|
| @@ -972,19 +1498,6 @@ bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
|
| mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke :
|
| DIEllipseEdgeEffect::kFill;
|
| }
|
| - SkScalar innerRatioX = SkScalarDiv(xRadius, innerXRadius);
|
| - SkScalar innerRatioY = SkScalarDiv(yRadius, innerYRadius);
|
| -
|
| - SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(color, viewMatrix, mode));
|
| -
|
| - GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0);
|
| - SkASSERT(gp->getVertexStride() == sizeof(DIEllipseVertex));
|
| - if (!geo.succeeded()) {
|
| - SkDebugf("Failed to get space for vertices!\n");
|
| - return false;
|
| - }
|
| -
|
| - DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(geo.vertices());
|
|
|
| // This expands the outer rect so that after CTM we end up with a half-pixel border
|
| SkScalar a = viewMatrix[SkMatrix::kMScaleX];
|
| @@ -993,9 +1506,6 @@ bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
|
| SkScalar d = viewMatrix[SkMatrix::kMScaleY];
|
| SkScalar geoDx = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(a*a + c*c));
|
| SkScalar geoDy = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(b*b + d*d));
|
| - // This adjusts the "radius" to include the half-pixel border
|
| - SkScalar offsetDx = SkScalarDiv(geoDx, xRadius);
|
| - SkScalar offsetDy = SkScalarDiv(geoDy, yRadius);
|
|
|
| SkRect bounds = SkRect::MakeLTRB(
|
| center.fX - xRadius - geoDx,
|
| @@ -1004,25 +1514,20 @@ bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
|
| center.fY + yRadius + geoDy
|
| );
|
|
|
| - verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
|
| - verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
|
| - verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
|
| -
|
| - verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
|
| - verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
|
| - verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
|
| -
|
| - verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
|
| - verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
|
| - verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
|
| -
|
| - verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
|
| - verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
|
| - verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
|
| -
|
| - target->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer());
|
| - target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
|
| - target->resetIndexSource();
|
| + DIEllipseBatch::Geometry geometry;
|
| + geometry.fViewMatrix = viewMatrix;
|
| + geometry.fColor = color;
|
| + geometry.fXRadius = xRadius;
|
| + geometry.fYRadius = yRadius;
|
| + geometry.fInnerXRadius = innerXRadius;
|
| + geometry.fInnerYRadius = innerYRadius;
|
| + geometry.fGeoDx = geoDx;
|
| + geometry.fGeoDy = geoDy;
|
| + geometry.fMode = mode;
|
| + geometry.fDevBounds = bounds;
|
| +
|
| + SkAutoTUnref<GrBatch> batch(DIEllipseBatch::Create(geometry));
|
| + target->drawBatch(pipelineBuilder, batch, &bounds);
|
|
|
| return true;
|
| }
|
| @@ -1115,7 +1620,7 @@ bool GrOvalRenderer::drawDRRect(GrDrawTarget* target,
|
| }
|
| }
|
| GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType :
|
| - kFillBW_GrProcessorEdgeType;
|
| + kFillBW_GrProcessorEdgeType;
|
| GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer);
|
| if (NULL == effect) {
|
| return false;
|
| @@ -1138,6 +1643,434 @@ bool GrOvalRenderer::drawDRRect(GrDrawTarget* target,
|
| return true;
|
| }
|
|
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +class RRectCircleRendererBatch : public GrBatch {
|
| +public:
|
| + struct Geometry {
|
| + GrColor fColor;
|
| + SkMatrix fViewMatrix;
|
| + SkScalar fInnerRadius;
|
| + SkScalar fOuterRadius;
|
| + bool fStroke;
|
| + SkRect fDevBounds;
|
| + };
|
| +
|
| + static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
|
| + return SkNEW_ARGS(RRectCircleRendererBatch, (geometry, indexBuffer));
|
| + }
|
| +
|
| + const char* name() const SK_OVERRIDE { return "RRectCircleBatch"; }
|
| +
|
| + void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + // When this is called on a batch, there is only one geometry bundle
|
| + out->setKnownFourComponents(fGeoData[0].fColor);
|
| + }
|
| + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + out->setUnknownSingleComponent();
|
| + }
|
| +
|
| + void initBatchOpt(const GrBatchOpt& batchOpt) {
|
| + fBatchOpt = batchOpt;
|
| + }
|
| +
|
| + void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
|
| + // Handle any color overrides
|
| + if (init.fColorIgnored) {
|
| + fGeoData[0].fColor = GrColor_ILLEGAL;
|
| + } else if (GrColor_ILLEGAL != init.fOverrideColor) {
|
| + fGeoData[0].fColor = init.fOverrideColor;
|
| + }
|
| +
|
| + // setup batch properties
|
| + fBatch.fColorIgnored = init.fColorIgnored;
|
| + fBatch.fColor = fGeoData[0].fColor;
|
| + fBatch.fStroke = fGeoData[0].fStroke;
|
| + fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
|
| + fBatch.fCoverageIgnored = init.fCoverageIgnored;
|
| + }
|
| +
|
| + void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
|
| + // reset to device coordinates
|
| + SkMatrix invert;
|
| + if (!this->viewMatrix().invert(&invert)) {
|
| + SkDebugf("Failed to invert\n");
|
| + return;
|
| + }
|
| +
|
| + // Setup geometry processor
|
| + SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
|
| + this->stroke(),
|
| + invert));
|
| +
|
| + batchTarget->initDraw(gp, pipeline);
|
| +
|
| + // TODO this is hacky, but the only way we have to initialize the GP is to use the
|
| + // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
|
| + // everywhere we can remove this nastiness
|
| + GrPipelineInfo init;
|
| + init.fColorIgnored = fBatch.fColorIgnored;
|
| + init.fOverrideColor = GrColor_ILLEGAL;
|
| + init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
| + init.fUsesLocalCoords = this->usesLocalCoords();
|
| + gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + int instanceCount = fGeoData.count();
|
| + int vertexCount = kVertsPerRRect * instanceCount;
|
| + size_t vertexStride = gp->getVertexStride();
|
| + SkASSERT(vertexStride == sizeof(CircleVertex));
|
| +
|
| + const GrVertexBuffer* vertexBuffer;
|
| + int firstVertex;
|
| +
|
| + void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
| + vertexCount,
|
| + &vertexBuffer,
|
| + &firstVertex);
|
| +
|
| + CircleVertex* verts = reinterpret_cast<CircleVertex*>(vertices);
|
| +
|
| + for (int i = 0; i < instanceCount; i++) {
|
| + Geometry& args = fGeoData[i];
|
| +
|
| + SkScalar outerRadius = args.fOuterRadius;
|
| +
|
| + const SkRect& bounds = args.fDevBounds;
|
| +
|
| + SkScalar yCoords[4] = {
|
| + bounds.fTop,
|
| + bounds.fTop + outerRadius,
|
| + bounds.fBottom - outerRadius,
|
| + bounds.fBottom
|
| + };
|
| +
|
| + 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 (int i = 0; i < 4; ++i) {
|
| + verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
|
| + verts->fOuterRadius = outerRadius;
|
| + verts->fInnerRadius = innerRadius;
|
| + verts++;
|
| +
|
| + verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
|
| + verts->fOuterRadius = outerRadius;
|
| + verts->fInnerRadius = innerRadius;
|
| + verts++;
|
| +
|
| + verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
|
| + verts->fOuterRadius = outerRadius;
|
| + verts->fInnerRadius = innerRadius;
|
| + verts++;
|
| +
|
| + verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
|
| + verts->fOuterRadius = outerRadius;
|
| + verts->fInnerRadius = innerRadius;
|
| + verts++;
|
| + }
|
| + }
|
| +
|
| + // drop out the middle quad if we're stroked
|
| + int indexCnt = this->stroke() ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
|
| + SK_ARRAY_COUNT(gRRectIndices);
|
| +
|
| +
|
| + GrDrawTarget::DrawInfo drawInfo;
|
| + drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
|
| + drawInfo.setStartVertex(0);
|
| + drawInfo.setStartIndex(0);
|
| + drawInfo.setVerticesPerInstance(kVertsPerRRect);
|
| + drawInfo.setIndicesPerInstance(indexCnt);
|
| + drawInfo.adjustStartVertex(firstVertex);
|
| + drawInfo.setVertexBuffer(vertexBuffer);
|
| + drawInfo.setIndexBuffer(fIndexBuffer);
|
| +
|
| + int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
|
| +
|
| + while (instanceCount) {
|
| + drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
|
| + drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
|
| + drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
|
| +
|
| + batchTarget->draw(drawInfo);
|
| +
|
| + drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
|
| + instanceCount -= drawInfo.instanceCount();
|
| + }
|
| + }
|
| +
|
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| +
|
| +private:
|
| + RRectCircleRendererBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
|
| + : fIndexBuffer(indexBuffer) {
|
| + this->initClassID<RRectCircleRendererBatch>();
|
| + fGeoData.push_back(geometry);
|
| + }
|
| +
|
| + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
|
| + RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
|
| +
|
| + // TODO use vertex color to avoid breaking batches
|
| + if (this->color() != that->color()) {
|
| + return false;
|
| + }
|
| +
|
| + if (this->stroke() != that->stroke()) {
|
| + return false;
|
| + }
|
| +
|
| + SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
| + if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
| + return false;
|
| + }
|
| +
|
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| + return true;
|
| + }
|
| +
|
| + GrColor color() const { return fBatch.fColor; }
|
| + bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| + const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
|
| + bool stroke() const { return fBatch.fStroke; }
|
| +
|
| + struct BatchTracker {
|
| + GrColor fColor;
|
| + bool fStroke;
|
| + bool fUsesLocalCoords;
|
| + bool fColorIgnored;
|
| + bool fCoverageIgnored;
|
| + };
|
| +
|
| + GrBatchOpt fBatchOpt;
|
| + BatchTracker fBatch;
|
| + SkSTArray<1, Geometry, true> fGeoData;
|
| + const GrIndexBuffer* fIndexBuffer;
|
| +};
|
| +
|
| +class RRectEllipseRendererBatch : public GrBatch {
|
| +public:
|
| + struct Geometry {
|
| + GrColor fColor;
|
| + SkMatrix fViewMatrix;
|
| + SkScalar fXRadius;
|
| + SkScalar fYRadius;
|
| + SkScalar fInnerXRadius;
|
| + SkScalar fInnerYRadius;
|
| + bool fStroke;
|
| + SkRect fDevBounds;
|
| + };
|
| +
|
| + static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
|
| + return SkNEW_ARGS(RRectEllipseRendererBatch, (geometry, indexBuffer));
|
| + }
|
| +
|
| + const char* name() const SK_OVERRIDE { return "RRectEllipseRendererBatch"; }
|
| +
|
| + void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + // When this is called on a batch, there is only one geometry bundle
|
| + out->setKnownFourComponents(fGeoData[0].fColor);
|
| + }
|
| + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
|
| + out->setUnknownSingleComponent();
|
| + }
|
| +
|
| + void initBatchOpt(const GrBatchOpt& batchOpt) {
|
| + fBatchOpt = batchOpt;
|
| + }
|
| +
|
| + void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
|
| + // Handle any color overrides
|
| + if (init.fColorIgnored) {
|
| + fGeoData[0].fColor = GrColor_ILLEGAL;
|
| + } else if (GrColor_ILLEGAL != init.fOverrideColor) {
|
| + fGeoData[0].fColor = init.fOverrideColor;
|
| + }
|
| +
|
| + // setup batch properties
|
| + fBatch.fColorIgnored = init.fColorIgnored;
|
| + fBatch.fColor = fGeoData[0].fColor;
|
| + fBatch.fStroke = fGeoData[0].fStroke;
|
| + fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
|
| + fBatch.fCoverageIgnored = init.fCoverageIgnored;
|
| + }
|
| +
|
| + void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
|
| + // reset to device coordinates
|
| + SkMatrix invert;
|
| + if (!this->viewMatrix().invert(&invert)) {
|
| + SkDebugf("Failed to invert\n");
|
| + return;
|
| + }
|
| +
|
| + // Setup geometry processor
|
| + SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
|
| + this->stroke(),
|
| + invert));
|
| +
|
| + batchTarget->initDraw(gp, pipeline);
|
| +
|
| + // TODO this is hacky, but the only way we have to initialize the GP is to use the
|
| + // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
|
| + // everywhere we can remove this nastiness
|
| + GrPipelineInfo init;
|
| + init.fColorIgnored = fBatch.fColorIgnored;
|
| + init.fOverrideColor = GrColor_ILLEGAL;
|
| + init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
| + init.fUsesLocalCoords = this->usesLocalCoords();
|
| + gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + int instanceCount = fGeoData.count();
|
| + int vertexCount = kVertsPerRRect * instanceCount;
|
| + size_t vertexStride = gp->getVertexStride();
|
| + SkASSERT(vertexStride == sizeof(EllipseVertex));
|
| +
|
| + const GrVertexBuffer* vertexBuffer;
|
| + int firstVertex;
|
| +
|
| + void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
| + vertexCount,
|
| + &vertexBuffer,
|
| + &firstVertex);
|
| +
|
| + EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(vertices);
|
| +
|
| + for (int i = 0; i < instanceCount; i++) {
|
| + Geometry& args = fGeoData[i];
|
| +
|
| + // Compute the reciprocals of the radii here to save time in the shader
|
| + SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
|
| + SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
|
| + SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
|
| + SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
|
| +
|
| + // Extend the radii out half a pixel to antialias.
|
| + SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
|
| + SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
|
| +
|
| + const SkRect& bounds = args.fDevBounds;
|
| +
|
| + SkScalar yCoords[4] = {
|
| + bounds.fTop,
|
| + bounds.fTop + yOuterRadius,
|
| + bounds.fBottom - yOuterRadius,
|
| + bounds.fBottom
|
| + };
|
| + SkScalar yOuterOffsets[4] = {
|
| + yOuterRadius,
|
| + SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
|
| + SK_ScalarNearlyZero,
|
| + yOuterRadius
|
| + };
|
| +
|
| + for (int i = 0; i < 4; ++i) {
|
| + verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
|
| + verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| + verts++;
|
| +
|
| + verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
|
| + verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| + verts++;
|
| +
|
| + verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
|
| + verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| + verts++;
|
| +
|
| + verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
|
| + verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
|
| + verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| + verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| + verts++;
|
| + }
|
| + }
|
| +
|
| + // drop out the middle quad if we're stroked
|
| + int indexCnt = this->stroke() ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
|
| + SK_ARRAY_COUNT(gRRectIndices);
|
| +
|
| + GrDrawTarget::DrawInfo drawInfo;
|
| + drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
|
| + drawInfo.setStartVertex(0);
|
| + drawInfo.setStartIndex(0);
|
| + drawInfo.setVerticesPerInstance(kVertsPerRRect);
|
| + drawInfo.setIndicesPerInstance(indexCnt);
|
| + drawInfo.adjustStartVertex(firstVertex);
|
| + drawInfo.setVertexBuffer(vertexBuffer);
|
| + drawInfo.setIndexBuffer(fIndexBuffer);
|
| +
|
| + int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
|
| +
|
| + while (instanceCount) {
|
| + drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
|
| + drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
|
| + drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
|
| +
|
| + batchTarget->draw(drawInfo);
|
| +
|
| + drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
|
| + instanceCount -= drawInfo.instanceCount();
|
| + }
|
| + }
|
| +
|
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| +
|
| +private:
|
| + RRectEllipseRendererBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
|
| + : fIndexBuffer(indexBuffer) {
|
| + this->initClassID<RRectEllipseRendererBatch>();
|
| + fGeoData.push_back(geometry);
|
| + }
|
| +
|
| + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
|
| + RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
|
| +
|
| + // TODO use vertex color to avoid breaking batches
|
| + if (this->color() != that->color()) {
|
| + return false;
|
| + }
|
| +
|
| + if (this->stroke() != that->stroke()) {
|
| + return false;
|
| + }
|
| +
|
| + SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
|
| + if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
| + return false;
|
| + }
|
| +
|
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| + return true;
|
| + }
|
| +
|
| + GrColor color() const { return fBatch.fColor; }
|
| + bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| + const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
|
| + bool stroke() const { return fBatch.fStroke; }
|
| +
|
| + struct BatchTracker {
|
| + GrColor fColor;
|
| + bool fStroke;
|
| + bool fUsesLocalCoords;
|
| + bool fColorIgnored;
|
| + bool fCoverageIgnored;
|
| + };
|
| +
|
| + GrBatchOpt fBatchOpt;
|
| + BatchTracker fBatch;
|
| + SkSTArray<1, Geometry, true> fGeoData;
|
| + const GrIndexBuffer* fIndexBuffer;
|
| +};
|
| +
|
| bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
|
| GrPipelineBuilder* pipelineBuilder,
|
| GrColor color,
|
| @@ -1209,13 +2142,6 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
|
| return false;
|
| }
|
|
|
| - // reset to device coordinates
|
| - SkMatrix invert;
|
| - if (!viewMatrix.invert(&invert)) {
|
| - SkDebugf("Failed to invert\n");
|
| - return false;
|
| - }
|
| -
|
| GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(isStrokeOnly);
|
| if (NULL == indexBuffer) {
|
| SkDebugf("Failed to create index buffer!\n");
|
| @@ -1243,18 +2169,6 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
|
|
|
| isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
|
|
|
| - SkAutoTUnref<GrGeometryProcessor> effect(CircleEdgeEffect::Create(color,
|
| - isStrokeOnly,
|
| - invert));
|
| -
|
| - GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(), 0);
|
| - SkASSERT(effect->getVertexStride() == sizeof(CircleVertex));
|
| - if (!geo.succeeded()) {
|
| - SkDebugf("Failed to get space for vertices!\n");
|
| - return false;
|
| - }
|
| - CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
|
| -
|
| // The radii are outset for two reasons. First, it allows the shader to simply perform
|
| // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
|
| // Second, the outer radius is used to compute the verts of the bounding box that is
|
| @@ -1266,47 +2180,16 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
|
| // Expand the rect so all the pixels will be captured.
|
| bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
|
|
|
| - SkScalar yCoords[4] = {
|
| - bounds.fTop,
|
| - bounds.fTop + outerRadius,
|
| - bounds.fBottom - outerRadius,
|
| - bounds.fBottom
|
| - };
|
| - SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
|
| - // The inner radius in the vertex data must be specified in normalized space.
|
| - innerRadius = innerRadius / outerRadius;
|
| - for (int i = 0; i < 4; ++i) {
|
| - verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
|
| - verts->fOuterRadius = outerRadius;
|
| - verts->fInnerRadius = innerRadius;
|
| - verts++;
|
| -
|
| - verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
|
| - verts->fOuterRadius = outerRadius;
|
| - verts->fInnerRadius = innerRadius;
|
| - verts++;
|
| -
|
| - verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
|
| - verts->fOuterRadius = outerRadius;
|
| - verts->fInnerRadius = innerRadius;
|
| - verts++;
|
| -
|
| - verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
|
| - verts->fOuterRadius = outerRadius;
|
| - verts->fInnerRadius = innerRadius;
|
| - verts++;
|
| - }
|
| + RRectCircleRendererBatch::Geometry geometry;
|
| + geometry.fViewMatrix = viewMatrix;
|
| + geometry.fColor = color;
|
| + geometry.fInnerRadius = innerRadius;
|
| + geometry.fOuterRadius = outerRadius;
|
| + geometry.fStroke = isStrokeOnly;
|
| + geometry.fDevBounds = bounds;
|
|
|
| - // drop out the middle quad if we're stroked
|
| - int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
|
| - SK_ARRAY_COUNT(gRRectIndices);
|
| - target->setIndexSourceToBuffer(indexBuffer);
|
| - target->drawIndexedInstances(pipelineBuilder, effect, kTriangles_GrPrimitiveType, 1, 16,
|
| - indexCnt, &bounds);
|
| + SkAutoTUnref<GrBatch> batch(RRectCircleRendererBatch::Create(geometry, indexBuffer));
|
| + target->drawBatch(pipelineBuilder, batch, &bounds);
|
|
|
| // otherwise we use the ellipse renderer
|
| } else {
|
| @@ -1344,79 +2227,21 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
|
|
|
| isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
|
|
|
| - SkAutoTUnref<GrGeometryProcessor> effect(EllipseEdgeEffect::Create(color,
|
| - isStrokeOnly,
|
| - invert));
|
| -
|
| - GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(), 0);
|
| - SkASSERT(effect->getVertexStride() == sizeof(EllipseVertex));
|
| - if (!geo.succeeded()) {
|
| - SkDebugf("Failed to get space for vertices!\n");
|
| - return false;
|
| - }
|
| -
|
| - EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
|
| -
|
| - // Compute the reciprocals of the radii here to save time in the shader
|
| - SkScalar xRadRecip = SkScalarInvert(xRadius);
|
| - SkScalar yRadRecip = SkScalarInvert(yRadius);
|
| - SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
|
| - SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
|
| -
|
| - // Extend the radii out half a pixel to antialias.
|
| - SkScalar xOuterRadius = xRadius + SK_ScalarHalf;
|
| - SkScalar yOuterRadius = yRadius + SK_ScalarHalf;
|
| -
|
| // Expand the rect so all the pixels will be captured.
|
| bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
|
|
|
| - SkScalar yCoords[4] = {
|
| - bounds.fTop,
|
| - bounds.fTop + yOuterRadius,
|
| - bounds.fBottom - yOuterRadius,
|
| - bounds.fBottom
|
| - };
|
| - SkScalar yOuterOffsets[4] = {
|
| - yOuterRadius,
|
| - SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0
|
| - SK_ScalarNearlyZero,
|
| - yOuterRadius
|
| - };
|
| -
|
| - for (int i = 0; i < 4; ++i) {
|
| - verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
|
| - verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| - verts++;
|
| -
|
| - verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
|
| - verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| - verts++;
|
| -
|
| - verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
|
| - verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| - verts++;
|
| -
|
| - verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
|
| - verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
|
| - verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
|
| - verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
|
| - verts++;
|
| - }
|
| -
|
| - // drop out the middle quad if we're stroked
|
| - int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
|
| - SK_ARRAY_COUNT(gRRectIndices);
|
| - target->setIndexSourceToBuffer(indexBuffer);
|
| - target->drawIndexedInstances(pipelineBuilder, effect, kTriangles_GrPrimitiveType, 1, 16,
|
| - indexCnt, &bounds);
|
| + RRectEllipseRendererBatch::Geometry geometry;
|
| + geometry.fViewMatrix = viewMatrix;
|
| + geometry.fColor = color;
|
| + geometry.fXRadius = xRadius;
|
| + geometry.fYRadius = yRadius;
|
| + geometry.fInnerXRadius = innerXRadius;
|
| + geometry.fInnerYRadius = innerYRadius;
|
| + geometry.fStroke = isStrokeOnly;
|
| + geometry.fDevBounds = bounds;
|
| +
|
| + SkAutoTUnref<GrBatch> batch(RRectEllipseRendererBatch::Create(geometry, indexBuffer));
|
| + target->drawBatch(pipelineBuilder, batch, &bounds);
|
| }
|
| -
|
| - target->resetIndexSource();
|
| return true;
|
| }
|
|
|