aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar joshualitt <joshualitt@chromium.org>2015-02-03 06:56:44 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-02-03 06:56:44 -0800
commit658d55cd6121c67488aaf5d0832c9712737f26a5 (patch)
treeaadccf0de00d90f95404d002a93950506e310c11
parent532faa9021cde714bc1fcc5650257fd7310f9712 (diff)
Hairline batch
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.cpp683
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.h25
-rw-r--r--src/gpu/GrAARectRenderer.cpp5
-rw-r--r--src/gpu/GrBatch.h8
-rw-r--r--src/gpu/GrBatchTarget.cpp25
-rw-r--r--src/gpu/GrBatchTarget.h18
-rw-r--r--src/gpu/GrInOrderDrawBuffer.cpp5
7 files changed, 475 insertions, 294 deletions
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index ce24cf8c26..6ecaa2eba4 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -7,6 +7,9 @@
#include "GrAAHairLinePathRenderer.h"
+#include "GrBatch.h"
+#include "GrBatchTarget.h"
+#include "GrBufferAllocPool.h"
#include "GrContext.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawTargetCaps.h"
@@ -253,14 +256,14 @@ int num_quad_subdivs(const SkPoint p[3]) {
* subdivide large quads to reduce over-fill. This subdivision has to be
* performed before applying the perspective matrix.
*/
-int generate_lines_and_quads(const SkPath& path,
- const SkMatrix& m,
- const SkIRect& devClipBounds,
- GrAAHairLinePathRenderer::PtArray* lines,
- GrAAHairLinePathRenderer::PtArray* quads,
- GrAAHairLinePathRenderer::PtArray* conics,
- GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
- GrAAHairLinePathRenderer::FloatArray* conicWeights) {
+int gather_lines_and_quads(const SkPath& path,
+ const SkMatrix& m,
+ const SkIRect& devClipBounds,
+ GrAAHairLinePathRenderer::PtArray* lines,
+ GrAAHairLinePathRenderer::PtArray* quads,
+ GrAAHairLinePathRenderer::PtArray* conics,
+ GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
+ GrAAHairLinePathRenderer::FloatArray* conicWeights) {
SkPath::Iter iter(path, false);
int totalQuadCount = 0;
@@ -469,8 +472,7 @@ void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
}
void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
- const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices],
- SkRect* devBounds) {
+ const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) {
SkASSERT(!toDevice == !toSrc);
// original quad is specified by tri a,b,c
SkPoint a = qpts[0];
@@ -535,7 +537,6 @@ void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
c1.fPos -= cbN;
intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
- devBounds->growToInclude(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices);
if (toSrc) {
toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices);
@@ -567,9 +568,8 @@ void add_conics(const SkPoint p[3],
const SkScalar weight,
const SkMatrix* toDevice,
const SkMatrix* toSrc,
- BezierVertex** vert,
- SkRect* devBounds) {
- bloat_quad(p, toDevice, toSrc, *vert, devBounds);
+ BezierVertex** vert) {
+ bloat_quad(p, toDevice, toSrc, *vert);
set_conic_coeffs(p, *vert, weight);
*vert += kQuadNumVertices;
}
@@ -578,16 +578,15 @@ void add_quads(const SkPoint p[3],
int subdiv,
const SkMatrix* toDevice,
const SkMatrix* toSrc,
- BezierVertex** vert,
- SkRect* devBounds) {
+ BezierVertex** vert) {
SkASSERT(subdiv >= 0);
if (subdiv) {
SkPoint newP[5];
SkChopQuadAtHalf(p, newP);
- add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds);
- add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds);
+ add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
+ add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
} else {
- bloat_quad(p, toDevice, toSrc, *vert, devBounds);
+ bloat_quad(p, toDevice, toSrc, *vert);
set_uv_quad(p, *vert);
*vert += kQuadNumVertices;
}
@@ -642,106 +641,6 @@ void add_line(const SkPoint p[2],
///////////////////////////////////////////////////////////////////////////////
-bool GrAAHairLinePathRenderer::createLineGeom(GrDrawTarget* target,
- GrPipelineBuilder* pipelineBuilder,
- const SkMatrix& viewMatrix,
- uint8_t coverage,
- size_t vertexStride,
- GrDrawTarget::AutoReleaseGeometry* arg,
- SkRect* devBounds,
- const SkPath& path,
- const PtArray& lines,
- int lineCnt) {
- int vertCnt = kLineSegNumVertices * lineCnt;
-
- SkASSERT(vertexStride == sizeof(LineVertex));
- if (!arg->set(target, vertCnt, vertexStride, 0)) {
- return false;
- }
-
- LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices());
-
- const SkMatrix* toSrc = NULL;
- SkMatrix ivm;
-
- if (viewMatrix.hasPerspective()) {
- if (viewMatrix.invert(&ivm)) {
- toSrc = &ivm;
- }
- }
- devBounds->set(lines.begin(), lines.count());
- for (int i = 0; i < lineCnt; ++i) {
- add_line(&lines[2*i], toSrc, coverage, &verts);
- }
- // All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the end points.
- static const SkScalar kSqrtOfOneAndAQuarter = 1.118f;
- // Add a little extra to account for vector normalization precision.
- static const SkScalar kOutset = kSqrtOfOneAndAQuarter + SK_Scalar1 / 20;
- devBounds->outset(kOutset, kOutset);
-
- return true;
-}
-
-bool GrAAHairLinePathRenderer::createBezierGeom(GrDrawTarget* target,
- GrPipelineBuilder* pipelineBuilder,
- const SkMatrix& viewMatrix,
- GrDrawTarget::AutoReleaseGeometry* arg,
- SkRect* devBounds,
- const SkPath& path,
- const PtArray& quads,
- int quadCnt,
- const PtArray& conics,
- int conicCnt,
- const IntArray& qSubdivs,
- const FloatArray& cWeights,
- size_t vertexStride) {
- int vertCnt = kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt;
-
- if (!arg->set(target, vertCnt, vertexStride, 0)) {
- return false;
- }
-
- BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices());
-
- const SkMatrix* toDevice = NULL;
- const SkMatrix* toSrc = NULL;
- SkMatrix ivm;
-
- if (viewMatrix.hasPerspective()) {
- if (viewMatrix.invert(&ivm)) {
- toDevice = &viewMatrix;
- toSrc = &ivm;
- }
- }
-
- // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding
- // box to include its vertices.
- SkPoint seedPts[2];
- if (quadCnt) {
- seedPts[0] = quads[0];
- seedPts[1] = quads[2];
- } else if (conicCnt) {
- seedPts[0] = conics[0];
- seedPts[1] = conics[2];
- }
- if (toDevice) {
- toDevice->mapPoints(seedPts, 2);
- }
- devBounds->set(seedPts[0], seedPts[1]);
-
- int unsubdivQuadCnt = quads.count() / 3;
- for (int i = 0; i < unsubdivQuadCnt; ++i) {
- SkASSERT(qSubdivs[i] >= 0);
- add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds);
- }
-
- // Start Conics
- for (int i = 0; i < conicCnt; ++i) {
- add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds);
- }
- return true;
-}
-
bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target,
const GrPipelineBuilder* pipelineBuilder,
const SkMatrix& viewMatrix,
@@ -800,179 +699,469 @@ bool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* ver
return true;
}
-bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
- GrPipelineBuilder* pipelineBuilder,
- GrColor color,
- const SkMatrix& viewMatrix,
- const SkPath& path,
- const SkStrokeRec& stroke,
- bool antiAlias) {
- SkScalar hairlineCoverage;
- uint8_t newCoverage = 0xff;
- if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
- newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
+class AAHairlineBatch : public GrBatch {
+public:
+ struct Geometry {
+ GrColor fColor;
+ uint8_t fCoverage;
+ SkMatrix fViewMatrix;
+ SkPath fPath;
+ SkDEBUGCODE(SkRect fDevBounds;)
+ SkIRect fDevClipBounds;
+ };
+
+ // TODO Batch itself should not hold on to index buffers. Instead, these should live in the
+ // cache.
+ static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer,
+ const GrIndexBuffer* quadsIndexBuffer) {
+ return SkNEW_ARGS(AAHairlineBatch, (geometry, linesIndexBuffer, quadsIndexBuffer));
}
- SkIRect devClipBounds;
- target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(), &devClipBounds);
+ const char* name() const SK_OVERRIDE { return "AAHairlineBatch"; }
- int lineCnt;
- int quadCnt;
- int conicCnt;
- PREALLOC_PTARRAY(128) lines;
- PREALLOC_PTARRAY(128) quads;
- PREALLOC_PTARRAY(128) conics;
- IntArray qSubdivs;
- FloatArray cWeights;
- quadCnt = generate_lines_and_quads(path, viewMatrix, devClipBounds,
- &lines, &quads, &conics, &qSubdivs, &cWeights);
- lineCnt = lines.count() / 2;
- conicCnt = conics.count() / 3;
-
- // createGeom transforms the geometry to device space when the matrix does not have
- // perspective.
- SkMatrix vm = viewMatrix;
- SkMatrix invert = SkMatrix::I();
- if (!viewMatrix.hasPerspective()) {
- vm = SkMatrix::I();
- if (!viewMatrix.invert(&invert)) {
- return false;
+ 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.fUsesLocalCoords = init.fUsesLocalCoords;
+ fBatch.fCoverageIgnored = init.fCoverageIgnored;
+ fBatch.fCoverage = fGeoData[0].fCoverage;
+ SkDEBUGCODE(fBatch.fDevBounds = fGeoData[0].fDevBounds;)
}
- // do lines first
- if (lineCnt) {
- GrDrawTarget::AutoReleaseGeometry arg;
- SkRect devBounds;
+ void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
+ int instanceCount = fGeoData.count();
+ for (int i = 0; i < instanceCount; i++) {
+ const Geometry& args = fGeoData[i];
+
+ // createGeom transforms the geometry to device space when the matrix does not have
+ // perspective.
+ SkMatrix vm = args.fViewMatrix;
+ SkMatrix invert = SkMatrix::I();
+ if (!args.fViewMatrix.hasPerspective()) {
+ vm = SkMatrix::I();
+ if (!args.fViewMatrix.invert(&invert)) {
+ return;
+ }
+ }
+
+ int lineCount;
+ int quadCount;
+ int conicCount;
+ PREALLOC_PTARRAY(128) lines;
+ PREALLOC_PTARRAY(128) quads;
+ PREALLOC_PTARRAY(128) conics;
+ IntArray qSubdivs;
+ FloatArray cWeights;
+ quadCount = gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds,
+ &lines, &quads, &conics, &qSubdivs, &cWeights);
+
+ lineCount = lines.count() / 2;
+ conicCount = conics.count() / 3;
+
+ // do lines first
+ if (lineCount) {
+ this->generateLines(batchTarget, pipeline, args, vm, invert, lines, lineCount);
+ }
+
+ if (quadCount || conicCount) {
+ this->generateQuadsAndConics(batchTarget,
+ pipeline,
+ args,
+ quads,
+ quadCount,
+ conics,
+ conicCount,
+ qSubdivs,
+ cWeights,
+ vm,
+ invert);
+ }
+ }
+ }
+
+ SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
+
+private:
+ typedef SkTArray<SkPoint, true> PtArray;
+ typedef SkTArray<int, true> IntArray;
+ typedef SkTArray<float, true> FloatArray;
- GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
+ AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer,
+ const GrIndexBuffer* quadsIndexBuffer)
+ : fLinesIndexBuffer(linesIndexBuffer)
+ , fQuadsIndexBuffer(quadsIndexBuffer) {
+ SkASSERT(linesIndexBuffer && quadsIndexBuffer);
+ this->initClassID<AAHairlineBatch>();
+ fGeoData.push_back(geometry);
+ }
+
+ bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
+ AAHairlineBatch* that = t->cast<AAHairlineBatch>();
+
+ // We go to identity if we don't have perspective
+ if (this->viewMatrix().hasPerspective() &&
+ !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
+ return false;
+ }
+
+ // TODO we can actually batch hairlines if they are the same color in a kind of bulk method
+ // but we haven't implemented this yet
+ // TODO investigate going to vertex color and coverage?
+ if (this->coverage() != that->coverage()) {
+ return false;
+ }
+
+ if (this->color() != that->color()) {
+ 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; }
+ uint8_t coverage() const { return fBatch.fCoverage; }
+ bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
+ const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
+
+ void generateLines(GrBatchTarget* batchTarget,
+ const GrPipeline* pipeline,
+ const Geometry& args,
+ const SkMatrix& viewMatrix,
+ const SkMatrix& invert,
+ const PtArray& lines,
+ int lineCnt) {
uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
GrDefaultGeoProcFactory::kCoverage_GPType;
SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Create(gpFlags,
- color,
- vm,
+ args.fColor,
+ viewMatrix,
invert,
false,
- newCoverage));
-
- if (!this->createLineGeom(target,
- pipelineBuilder,
- viewMatrix,
- newCoverage,
- gp->getVertexStride(),
- &arg,
- &devBounds,
- path,
- lines,
- lineCnt)) {
- return false;
+ args.fCoverage));
+
+ batchTarget->initDraw(gp, pipeline);
+
+ // TODO remove this when batch is everywhere
+ GrPipelineInfo init;
+ init.fColorIgnored = fBatch.fColorIgnored;
+ init.fOverrideColor = GrColor_ILLEGAL;
+ init.fCoverageIgnored = fBatch.fCoverageIgnored;
+ init.fUsesLocalCoords = this->usesLocalCoords();
+ gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
+
+ const GrVertexBuffer* vertexBuffer;
+ int firstVertex;
+
+ size_t vertexStride = gp->getVertexStride();
+ int vertexCount = kLineSegNumVertices * lineCnt;
+ void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
+ vertexCount,
+ &vertexBuffer,
+ &firstVertex);
+
+ SkASSERT(gp->getVertexStride() == sizeof(LineVertex));
+
+ // generate lines
+ const SkMatrix* toSrc = NULL;
+ if (args.fViewMatrix.hasPerspective()) {
+ SkMatrix perspectiveInvert;
+ if (!args.fViewMatrix.invert(&perspectiveInvert)) {
+ return;
+ }
+ toSrc = &perspectiveInvert;
+ }
+
+ LineVertex* verts = reinterpret_cast<LineVertex*>(vertices);
+ for (int i = 0; i < lineCnt; ++i) {
+ add_line(&lines[2*i], toSrc, args.fCoverage, &verts);
}
// Check devBounds
SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I(),
- devBounds,
- arg.vertices(),
+ args.fDevBounds,
+ vertices,
kLineSegNumVertices * lineCnt));
{
- target->setIndexSourceToBuffer(fLinesIndexBuffer);
+ GrDrawTarget::DrawInfo info;
+ info.setVertexBuffer(vertexBuffer);
+ info.setIndexBuffer(fLinesIndexBuffer);
+ info.setPrimitiveType(kTriangles_GrPrimitiveType);
+ info.setStartIndex(0);
+
int lines = 0;
while (lines < lineCnt) {
int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer);
- target->drawIndexed(pipelineBuilder,
- gp,
- kTriangles_GrPrimitiveType,
- kLineSegNumVertices*lines, // startV
- 0, // startI
- kLineSegNumVertices*n, // vCount
- kIdxsPerLineSeg*n, // iCount
- &devBounds);
+
+ info.setStartVertex(kLineSegNumVertices*lines + firstVertex);
+ info.setVertexCount(kLineSegNumVertices*n);
+ info.setIndexCount(kIdxsPerLineSeg*n);
+ batchTarget->draw(info);
+
lines += n;
}
}
}
- // then quadratics/conics
- if (quadCnt || conicCnt) {
- GrDrawTarget::AutoReleaseGeometry arg;
- SkRect devBounds;
-
- if (!this->createBezierGeom(target,
- pipelineBuilder,
- viewMatrix,
- &arg,
- &devBounds,
- path,
+ void generateQuadsAndConics(GrBatchTarget* batchTarget,
+ const GrPipeline* pipeline,
+ const Geometry& args,
+ const PREALLOC_PTARRAY(128)& quads,
+ int quadCount,
+ const PREALLOC_PTARRAY(128)& conics,
+ int conicCount,
+ const IntArray& qSubdivs,
+ const FloatArray& cWeights,
+ const SkMatrix& vm,
+ const SkMatrix& invert) {
+ const GrVertexBuffer* vertexBuffer;
+ int firstVertex;
+
+ size_t vertexStride = sizeof(BezierVertex);
+ int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount;
+ void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
+ vertexCount,
+ &vertexBuffer,
+ &firstVertex);
+
+ if (!this->createBezierGeom(vertices,
+ args.fViewMatrix,
+ args.fPath,
quads,
- quadCnt,
+ quadCount,
conics,
- conicCnt,
+ conicCount,
qSubdivs,
cWeights,
- sizeof(BezierVertex))) {
- return false;
+ vertexStride)) {
+ SkDebugf("Couldn't create bezier geometry\n");
+ return;
}
// Check devBounds
- SkASSERT(check_bounds<BezierVertex>(viewMatrix.hasPerspective() ? viewMatrix :
- SkMatrix::I(),
- devBounds,
- arg.vertices(),
- kQuadNumVertices * quadCnt +
- kQuadNumVertices * conicCnt));
-
- if (quadCnt > 0) {
+ SkASSERT(check_bounds<BezierVertex>(vm,
+ args.fDevBounds,
+ vertices,
+ kQuadNumVertices * quadCount +
+ kQuadNumVertices * conicCount));
+
+ if (quadCount > 0) {
SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor(
- GrQuadEffect::Create(color,
+ GrQuadEffect::Create(args.fColor,
vm,
kHairlineAA_GrProcessorEdgeType,
- *target->caps(),
+ batchTarget->caps(),
invert,
- newCoverage));
- SkASSERT(hairQuadProcessor);
- GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
- target->setIndexSourceToBuffer(fQuadsIndexBuffer);
-
- int quads = 0;
- while (quads < quadCnt) {
- int n = SkTMin(quadCnt - quads, kQuadsNumInIdxBuffer);
- target->drawIndexed(pipelineBuilder,
- hairQuadProcessor,
- kTriangles_GrPrimitiveType,
- kQuadNumVertices*quads, // startV
- 0, // startI
- kQuadNumVertices*n, // vCount
- kIdxsPerQuad*n, // iCount
- &devBounds);
- quads += n;
- }
+ args.fCoverage));
+
+ batchTarget->initDraw(hairQuadProcessor, pipeline);
+
+ // TODO remove this when batch is everywhere
+ GrPipelineInfo init;
+ init.fColorIgnored = fBatch.fColorIgnored;
+ init.fOverrideColor = GrColor_ILLEGAL;
+ init.fCoverageIgnored = fBatch.fCoverageIgnored;
+ init.fUsesLocalCoords = this->usesLocalCoords();
+ hairQuadProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
+
+ this->drawBeziers(batchTarget,
+ hairQuadProcessor,
+ pipeline,
+ vertexBuffer,
+ firstVertex,
+ quadCount);
}
- if (conicCnt > 0) {
+ if (conicCount > 0) {
SkAutoTUnref<GrGeometryProcessor> hairConicProcessor(
- GrConicEffect::Create(color, vm, kHairlineAA_GrProcessorEdgeType,
- *target->caps(), invert, newCoverage));
- SkASSERT(hairConicProcessor);
- GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
- target->setIndexSourceToBuffer(fQuadsIndexBuffer);
-
- int conics = 0;
- while (conics < conicCnt) {
- int n = SkTMin(conicCnt - conics, kQuadsNumInIdxBuffer);
- target->drawIndexed(pipelineBuilder,
- hairConicProcessor,
- kTriangles_GrPrimitiveType,
- kQuadNumVertices*(quadCnt + conics), // startV
- 0, // startI
- kQuadNumVertices*n, // vCount
- kIdxsPerQuad*n, // iCount
- &devBounds);
- conics += n;
+ GrConicEffect::Create(args.fColor,
+ vm,
+ kHairlineAA_GrProcessorEdgeType,
+ batchTarget->caps(),
+ invert,
+ args.fCoverage));
+
+ batchTarget->initDraw(hairConicProcessor, pipeline);
+
+ // TODO remove this when batch is everywhere
+ GrPipelineInfo init;
+ init.fColorIgnored = fBatch.fColorIgnored;
+ init.fOverrideColor = GrColor_ILLEGAL;
+ init.fCoverageIgnored = fBatch.fCoverageIgnored;
+ init.fUsesLocalCoords = this->usesLocalCoords();
+ hairConicProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
+
+ this->drawConics(batchTarget,
+ hairConicProcessor,
+ pipeline,
+ vertexBuffer,
+ firstVertex,
+ conicCount,
+ quadCount);
+ }
+ }
+
+ bool createBezierGeom(void* vertices,
+ const SkMatrix& viewMatrix,
+ const SkPath& path,
+ const PtArray& quads,
+ int quadCnt,
+ const PtArray& conics,
+ int conicCnt,
+ const IntArray& qSubdivs,
+ const FloatArray& cWeights,
+ size_t vertexStride) {
+ BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices);
+
+ const SkMatrix* toDevice = NULL;
+ const SkMatrix* toSrc = NULL;
+ SkMatrix ivm;
+
+ if (viewMatrix.hasPerspective()) {
+ if (viewMatrix.invert(&ivm)) {
+ toDevice = &viewMatrix;
+ toSrc = &ivm;
}
}
+
+ int unsubdivQuadCnt = quads.count() / 3;
+ for (int i = 0; i < unsubdivQuadCnt; ++i) {
+ SkASSERT(qSubdivs[i] >= 0);
+ add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
+ }
+
+ // Start Conics
+ for (int i = 0; i < conicCnt; ++i) {
+ add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts);
+ }
+ return true;
+ }
+
+ void drawBeziers(GrBatchTarget* batchTarget,
+ const GrGeometryProcessor* hairQuadProcessor,
+ const GrPipeline* pipeline,
+ const GrVertexBuffer* vertexBuffer,
+ int firstVertex,
+ int quadCount) {
+ GrDrawTarget::DrawInfo info;
+ info.setVertexBuffer(vertexBuffer);
+ info.setIndexBuffer(fQuadsIndexBuffer);
+ info.setPrimitiveType(kTriangles_GrPrimitiveType);
+ info.setStartIndex(0);
+
+ int quads = 0;
+ while (quads < quadCount) {
+ int n = SkTMin(quadCount - quads, kQuadsNumInIdxBuffer);
+
+ info.setStartVertex(kQuadNumVertices*quads + firstVertex);
+ info.setVertexCount(kQuadNumVertices*n);
+ info.setIndexCount(kIdxsPerQuad*n);
+ batchTarget->draw(info);
+
+ quads += n;
+ }
+ }
+
+ void drawConics(GrBatchTarget* batchTarget,
+ const GrGeometryProcessor* hairConicProcessor,
+ const GrPipeline* pipeline,
+ const GrVertexBuffer* vertexBuffer,
+ int firstVertex,
+ int conicCount,
+ int quadCount) {
+ GrDrawTarget::DrawInfo info;
+ info.setVertexBuffer(vertexBuffer);
+ info.setIndexBuffer(fQuadsIndexBuffer);
+ info.setPrimitiveType(kTriangles_GrPrimitiveType);
+ info.setStartIndex(0);
+
+ int conics = 0;
+ while (conics < conicCount) {
+ int n = SkTMin(conicCount - conics, kQuadsNumInIdxBuffer);
+
+ info.setStartVertex(kQuadNumVertices*(quadCount + conics) + firstVertex);
+ info.setVertexCount(kQuadNumVertices*n);
+ info.setIndexCount(kIdxsPerQuad*n);
+ batchTarget->draw(info);
+
+ conics += n;
+ }
}
- target->resetIndexSource();
+ struct BatchTracker {
+ GrColor fColor;
+ uint8_t fCoverage;
+ SkRect fDevBounds;
+ bool fUsesLocalCoords;
+ bool fColorIgnored;
+ bool fCoverageIgnored;
+ };
+
+ GrBatchOpt fBatchOpt;
+ BatchTracker fBatch;
+ SkSTArray<1, Geometry, true> fGeoData;
+ const GrIndexBuffer* fLinesIndexBuffer;
+ const GrIndexBuffer* fQuadsIndexBuffer;
+};
+
+bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
+ GrPipelineBuilder* pipelineBuilder,
+ GrColor color,
+ const SkMatrix& viewMatrix,
+ const SkPath& path,
+ const SkStrokeRec& stroke,
+ bool) {
+ SkScalar hairlineCoverage;
+ uint8_t newCoverage = 0xff;
+ if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
+ newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
+ }
+
+ SkIRect devClipBounds;
+ target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(), &devClipBounds);
+
+ // This outset was determined experimentally by running skps and gms. It probably could be a
+ // bit tighter
+ SkRect devRect = path.getBounds();
+ devRect.outset(7, 7);
+ viewMatrix.mapRect(&devRect);
+
+ AAHairlineBatch::Geometry geometry;
+ geometry.fColor = color;
+ geometry.fCoverage = newCoverage;
+ geometry.fViewMatrix = viewMatrix;
+ geometry.fPath = path;
+ SkDEBUGCODE(geometry.fDevBounds = devRect;)
+ geometry.fDevClipBounds = devClipBounds;
+
+ GrBatch* batch = AAHairlineBatch::Create(geometry, fLinesIndexBuffer, fQuadsIndexBuffer);
+ target->drawBatch(pipelineBuilder, batch, &devRect);
return true;
}
diff --git a/src/gpu/GrAAHairLinePathRenderer.h b/src/gpu/GrAAHairLinePathRenderer.h
index 91c00d78c3..ea1d8edd65 100644
--- a/src/gpu/GrAAHairLinePathRenderer.h
+++ b/src/gpu/GrAAHairLinePathRenderer.h
@@ -42,31 +42,6 @@ private:
const GrIndexBuffer* fLinesIndexBuffer,
const GrIndexBuffer* fQuadsIndexBuffer);
- bool createLineGeom(GrDrawTarget* target,
- GrPipelineBuilder*,
- const SkMatrix& viewMatrix,
- uint8_t coverage,
- size_t vertexStride,
- GrDrawTarget::AutoReleaseGeometry* arg,
- SkRect* devBounds,
- const SkPath& path,
- const PtArray& lines,
- int lineCnt);
-
- bool createBezierGeom(GrDrawTarget* target,
- GrPipelineBuilder*,
- const SkMatrix& viewMatrix,
- GrDrawTarget::AutoReleaseGeometry* arg,
- SkRect* devBounds,
- const SkPath& path,
- const PtArray& quads,
- int quadCnt,
- const PtArray& conics,
- int conicCnt,
- const IntArray& qSubdivs,
- const FloatArray& cWeights,
- size_t vertexStride);
-
const GrIndexBuffer* fLinesIndexBuffer;
const GrIndexBuffer* fQuadsIndexBuffer;
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 48692ebf5e..420c9e7c5a 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -208,10 +208,7 @@ private:
return false;
}
- if (this->usesLocalCoords() != that->usesLocalCoords()) {
- return false;
- }
-
+ SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
// We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
// local coords then we won't be able to batch. We could actually upload the viewmatrix
// using vertex attributes in these cases, but haven't investigated that
diff --git a/src/gpu/GrBatch.h b/src/gpu/GrBatch.h
index ceb2c5cc2a..2f1afee1e4 100644
--- a/src/gpu/GrBatch.h
+++ b/src/gpu/GrBatch.h
@@ -46,7 +46,7 @@ struct GrBatchOpt {
class GrBatch : public SkRefCnt {
public:
SK_DECLARE_INST_COUNT(GrBatch)
- GrBatch() { SkDEBUGCODE(fUsed = false;) }
+ GrBatch() : fNumberOfDraws(0) { SkDEBUGCODE(fUsed = false;) }
virtual ~GrBatch() {}
virtual const char* name() const = 0;
@@ -75,6 +75,10 @@ public:
virtual void generateGeometry(GrBatchTarget*, const GrPipeline*) = 0;
+ // TODO this goes away when batches are everywhere
+ void setNumberOfDraws(int numberOfDraws) { fNumberOfDraws = numberOfDraws; }
+ int numberOfDraws() const { return fNumberOfDraws; }
+
void* operator new(size_t size);
void operator delete(void* target);
@@ -126,6 +130,8 @@ private:
SkDEBUGCODE(bool fUsed;)
+ int fNumberOfDraws;
+
typedef SkRefCnt INHERITED;
};
diff --git a/src/gpu/GrBatchTarget.cpp b/src/gpu/GrBatchTarget.cpp
index 6a3135310a..1b68923472 100644
--- a/src/gpu/GrBatchTarget.cpp
+++ b/src/gpu/GrBatchTarget.cpp
@@ -32,17 +32,20 @@ void GrBatchTarget::flush() {
fFlushBuffer.reset();
}*/
-void GrBatchTarget::flushNext() {
- fIter.next();
- GrProgramDesc desc;
- BufferedFlush* bf = fIter.get();
- const GrPipeline* pipeline = bf->fPipeline;
- const GrPrimitiveProcessor* primProc = bf->fPrimitiveProcessor.get();
- fGpu->buildProgramDesc(&desc, *primProc, *pipeline, pipeline->descInfo(),
- bf->fBatchTracker);
+void GrBatchTarget::flushNext(int n) {
+ for (; n > 0; n--) {
+ SkDEBUGCODE(bool verify =) fIter.next();
+ SkASSERT(verify);
+ GrProgramDesc desc;
+ BufferedFlush* bf = fIter.get();
+ const GrPipeline* pipeline = bf->fPipeline;
+ const GrPrimitiveProcessor* primProc = bf->fPrimitiveProcessor.get();
+ fGpu->buildProgramDesc(&desc, *primProc, *pipeline, pipeline->descInfo(),
+ bf->fBatchTracker);
- GrGpu::DrawArgs args(primProc, pipeline, &desc, &bf->fBatchTracker);
- for (int i = 0; i < bf->fDraws.count(); i++) {
- fGpu->draw(args, bf->fDraws[i]);
+ GrGpu::DrawArgs args(primProc, pipeline, &desc, &bf->fBatchTracker);
+ for (int i = 0; i < bf->fDraws.count(); i++) {
+ fGpu->draw(args, bf->fDraws[i]);
+ }
}
}
diff --git a/src/gpu/GrBatchTarget.h b/src/gpu/GrBatchTarget.h
index b73907746f..37f5c9b142 100644
--- a/src/gpu/GrBatchTarget.h
+++ b/src/gpu/GrBatchTarget.h
@@ -17,6 +17,9 @@
* that render their batch.
*/
+class GrIndexBufferAllocPool;
+class GrVertexBufferAllocPool;
+
class GrBatchTarget : public SkNoncopyable {
public:
GrBatchTarget(GrGpu* gpu,
@@ -26,11 +29,13 @@ public:
, fVertexPool(vpool)
, fIndexPool(ipool)
, fFlushBuffer(kFlushBufferInitialSizeInBytes)
- , fIter(fFlushBuffer) {}
+ , fIter(fFlushBuffer)
+ , fNumberOfDraws(0) {}
typedef GrDrawTarget::DrawInfo DrawInfo;
void initDraw(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline) {
GrNEW_APPEND_TO_RECORDER(fFlushBuffer, BufferedFlush, (primProc, pipeline));
+ fNumberOfDraws++;
}
void draw(const GrDrawTarget::DrawInfo& draw) {
@@ -39,8 +44,10 @@ public:
// TODO this is temporary until batch is everywhere
//void flush();
+ void resetNumberOfDraws() { fNumberOfDraws = 0; }
+ int numberOfDraws() const { return fNumberOfDraws; }
void preFlush() { fIter = FlushBuffer::Iter(fFlushBuffer); }
- void flushNext();
+ void flushNext(int n);
void postFlush() { SkASSERT(!fIter.next()); fFlushBuffer.reset(); }
// TODO This goes away when everything uses batch
@@ -49,6 +56,8 @@ public:
return &fFlushBuffer.back().fBatchTracker;
}
+ const GrDrawTargetCaps& caps() const { return *fGpu->caps(); }
+
GrVertexBufferAllocPool* vertexPool() { return fVertexPool; }
GrIndexBufferAllocPool* indexPool() { return fIndexPool; }
@@ -62,8 +71,7 @@ private:
struct BufferedFlush {
BufferedFlush(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline)
: fPrimitiveProcessor(primProc)
- , fPipeline(pipeline)
- , fDraws(kDrawRecorderInitialSizeInBytes) {}
+ , fPipeline(pipeline) {}
typedef GrPendingProgramElement<const GrPrimitiveProcessor> ProgramPrimitiveProcessor;
ProgramPrimitiveProcessor fPrimitiveProcessor;
const GrPipeline* fPipeline;
@@ -73,7 +81,6 @@ private:
enum {
kFlushBufferInitialSizeInBytes = 8 * sizeof(BufferedFlush),
- kDrawRecorderInitialSizeInBytes = 8 * sizeof(DrawInfo),
};
typedef GrTRecorder<BufferedFlush, TBufferAlign> FlushBuffer;
@@ -81,6 +88,7 @@ private:
FlushBuffer fFlushBuffer;
// TODO this is temporary
FlushBuffer::Iter fIter;
+ int fNumberOfDraws;
};
#endif
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index a760dcbf6f..8805711bb9 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -473,7 +473,8 @@ void GrInOrderDrawBuffer::onFlush() {
// TODO temporary hack
if (kDrawBatch_Cmd == strip_trace_bit(iter->fType)) {
- fBatchTarget.flushNext();
+ DrawBatch* db = reinterpret_cast<DrawBatch*>(iter.get());
+ fBatchTarget.flushNext(db->fBatch->numberOfDraws());
continue;
}
@@ -646,7 +647,9 @@ void GrInOrderDrawBuffer::recordTraceMarkersIfNecessary() {
void GrInOrderDrawBuffer::closeBatch() {
if (fDrawBatch) {
+ fBatchTarget.resetNumberOfDraws();
fDrawBatch->execute(this, fPrevState);
+ fDrawBatch->fBatch->setNumberOfDraws(fBatchTarget.numberOfDraws());
fDrawBatch = NULL;
}
}