From 658d55cd6121c67488aaf5d0832c9712737f26a5 Mon Sep 17 00:00:00 2001 From: joshualitt Date: Tue, 3 Feb 2015 06:56:44 -0800 Subject: [PATCH] Hairline batch BUG=skia: Committed: https://skia.googlesource.com/skia/+/6eff8701f027016fbb3147412ec2292dcec2b7f5 Review URL: https://codereview.chromium.org/876673002 --- src/gpu/GrAAHairLinePathRenderer.cpp | 739 +++++++++++++++++---------- src/gpu/GrAAHairLinePathRenderer.h | 25 - src/gpu/GrAARectRenderer.cpp | 5 +- src/gpu/GrBatch.h | 8 +- src/gpu/GrBatchTarget.cpp | 25 +- src/gpu/GrBatchTarget.h | 18 +- src/gpu/GrInOrderDrawBuffer.cpp | 5 +- 7 files changed, 503 insertions(+), 322 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(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(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,13 +699,444 @@ bool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* ver return true; } +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)); + } + + const char* name() const SK_OVERRIDE { return "AAHairlineBatch"; } + + 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;) + } + + 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 PtArray; + typedef SkTArray IntArray; + typedef SkTArray FloatArray; + + AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer, + const GrIndexBuffer* quadsIndexBuffer) + : fLinesIndexBuffer(linesIndexBuffer) + , fQuadsIndexBuffer(quadsIndexBuffer) { + SkASSERT(linesIndexBuffer && quadsIndexBuffer); + this->initClassID(); + fGeoData.push_back(geometry); + } + + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE { + AAHairlineBatch* that = t->cast(); + + // 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 gp(GrDefaultGeoProcFactory::Create(gpFlags, + args.fColor, + viewMatrix, + invert, + 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(vertices); + for (int i = 0; i < lineCnt; ++i) { + add_line(&lines[2*i], toSrc, args.fCoverage, &verts); + } + + // Check devBounds + SkASSERT(check_bounds(viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I(), + args.fDevBounds, + vertices, + kLineSegNumVertices * lineCnt)); + + { + 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); + + info.setStartVertex(kLineSegNumVertices*lines + firstVertex); + info.setVertexCount(kLineSegNumVertices*n); + info.setIndexCount(kIdxsPerLineSeg*n); + batchTarget->draw(info); + + lines += n; + } + } + } + + 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, + quadCount, + conics, + conicCount, + qSubdivs, + cWeights, + vertexStride)) { + SkDebugf("Couldn't create bezier geometry\n"); + return; + } + + // Check devBounds + SkASSERT(check_bounds(vm, + args.fDevBounds, + vertices, + kQuadNumVertices * quadCount + + kQuadNumVertices * conicCount)); + + if (quadCount > 0) { + SkAutoTUnref hairQuadProcessor( + GrQuadEffect::Create(args.fColor, + vm, + kHairlineAA_GrProcessorEdgeType, + batchTarget->caps(), + invert, + 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 (conicCount > 0) { + SkAutoTUnref hairConicProcessor( + 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(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; + } + } + + 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 antiAlias) { + bool) { SkScalar hairlineCoverage; uint8_t newCoverage = 0xff; if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { @@ -816,163 +1146,22 @@ bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, SkIRect devClipBounds; target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(), &devClipBounds); - 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; + // 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); - // 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; - } - } + AAHairlineBatch::Geometry geometry; + geometry.fColor = color; + geometry.fCoverage = newCoverage; + geometry.fViewMatrix = viewMatrix; + geometry.fPath = path; + SkDEBUGCODE(geometry.fDevBounds = devRect;) + geometry.fDevClipBounds = devClipBounds; - // do lines first - if (lineCnt) { - GrDrawTarget::AutoReleaseGeometry arg; - SkRect devBounds; - - GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); - uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType | - GrDefaultGeoProcFactory::kCoverage_GPType; - SkAutoTUnref gp(GrDefaultGeoProcFactory::Create(gpFlags, - color, - vm, - invert, - false, - newCoverage)); - - if (!this->createLineGeom(target, - pipelineBuilder, - viewMatrix, - newCoverage, - gp->getVertexStride(), - &arg, - &devBounds, - path, - lines, - lineCnt)) { - return false; - } - - // Check devBounds - SkASSERT(check_bounds(viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I(), - devBounds, - arg.vertices(), - kLineSegNumVertices * lineCnt)); - - { - target->setIndexSourceToBuffer(fLinesIndexBuffer); - 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); - lines += n; - } - } - } - - // then quadratics/conics - if (quadCnt || conicCnt) { - GrDrawTarget::AutoReleaseGeometry arg; - SkRect devBounds; - - if (!this->createBezierGeom(target, - pipelineBuilder, - viewMatrix, - &arg, - &devBounds, - path, - quads, - quadCnt, - conics, - conicCnt, - qSubdivs, - cWeights, - sizeof(BezierVertex))) { - return false; - } - - // Check devBounds - SkASSERT(check_bounds(viewMatrix.hasPerspective() ? viewMatrix : - SkMatrix::I(), - devBounds, - arg.vertices(), - kQuadNumVertices * quadCnt + - kQuadNumVertices * conicCnt)); - - if (quadCnt > 0) { - SkAutoTUnref hairQuadProcessor( - GrQuadEffect::Create(color, - vm, - kHairlineAA_GrProcessorEdgeType, - *target->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; - } - } - - if (conicCnt > 0) { - SkAutoTUnref 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; - } - } - } - - target->resetIndexSource(); + 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 ProgramPrimitiveProcessor; ProgramPrimitiveProcessor fPrimitiveProcessor; const GrPipeline* fPipeline; @@ -73,7 +81,6 @@ private: enum { kFlushBufferInitialSizeInBytes = 8 * sizeof(BufferedFlush), - kDrawRecorderInitialSizeInBytes = 8 * sizeof(DrawInfo), }; typedef GrTRecorder 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(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; } }