Chromium Code Reviews| Index: src/gpu/GrAAHairLinePathRenderer.cpp |
| diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp |
| index ce24cf8c26a80d5411f36c205d38bf406638068c..5be504f2ca6478c00af77f968c063edb5c76e853 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" |
| @@ -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,478 @@ 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; |
| + }; |
| + |
| + static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer, |
|
bsalomon
2015/01/26 19:07:48
I think we should come up with a way for these to
|
| + 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"; } |
| + |
| + void getInvariantOutputColor(GrInitInvariantOutput* out, |
| + const GrBatchOpt& batchOpt) 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 GrBatchOpt& batchOpt) 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; |
| + SkDEBUGCODE(fBatch.fDevBounds = fGeoData[0].fDevBounds;) |
| + } |
| + |
| + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE { |
|
bsalomon
2015/01/26 19:07:48
private?
|
| + 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; |
| + } |
| - 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)) { |
| + if (this->devClipBounds() != this->devClipBounds()) { |
| return false; |
| } |
| + |
| + if (this->usesLocalCoords() != that->usesLocalCoords()) { |
| + return false; |
| + } |
| + |
| + if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
| + return false; |
| + } |
| + |
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); |
| + return true; |
| + } |
| + |
| + 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 = generate_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); |
| + } |
| + } |
| } |
| - // do lines first |
| - if (lineCnt) { |
| - GrDrawTarget::AutoReleaseGeometry arg; |
| - SkRect devBounds; |
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
| + |
| +private: |
| + typedef SkTArray<SkPoint, true> PtArray; |
| + typedef SkTArray<int, true> IntArray; |
| + typedef SkTArray<float, true> FloatArray; |
| + |
| + AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer, |
| + const GrIndexBuffer* quadsIndexBuffer) |
| + : fLinesIndexBuffer(linesIndexBuffer) |
| + , fQuadsIndexBuffer(quadsIndexBuffer) { |
| + SkASSERT(linesIndexBuffer && quadsIndexBuffer); |
| + this->initClassID<AAHairlineBatch>(); |
| + fGeoData.push_back(geometry); |
| + } |
| - GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); |
| + 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; } |
| + const SkIRect& devClipBounds() const { return fBatch.fDevClipBounds; } |
| + |
| + 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; |
| + } |
| + } |
| + |
| + struct BatchTracker { |
| + GrColor fColor; |
| + uint8_t fCoverage; |
| + SkRect fDevBounds; |
| + SkIRect fDevClipBounds; |
| + 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); |
| } |
| - target->resetIndexSource(); |
| + 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(3, 3); |
| + viewMatrix.mapRect(&devRect); |
| + |
| + // NOTE we don't currently do anything with the strokerec. |
|
bsalomon
2015/01/26 19:07:47
didn't we already respect it above (if IsStrokeHai
|
| + 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; |
| } |