| Index: src/gpu/GrAAHairLinePathRenderer.cpp
|
| diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
|
| index ce24cf8c26a80d5411f36c205d38bf406638068c..d2113cacc2d49f451b97052cf5770aef3d294660 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,367 @@ 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"; }
|
| +
|
| + 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;
|
| +
|
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| +
|
| +private:
|
| + typedef SkTArray<SkPoint, true> PtArray;
|
| + typedef SkTArray<int, true> IntArray;
|
| + typedef SkTArray<float, true> FloatArray;
|
|
|
| - int lineCnt;
|
| - int quadCnt;
|
| - int conicCnt;
|
| + 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>();
|
| +
|
| + if (this->viewMatrix().hasPerspective() != that->viewMatrix().hasPerspective()) {
|
| + return false;
|
| + }
|
| +
|
| + // 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; }
|
| +
|
| + 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;
|
| +};
|
| +
|
| +void AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) {
|
| + // Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
|
| + SkMatrix invert;
|
| + if (!this->viewMatrix().invert(&invert)) {
|
| + return;
|
| + }
|
| +
|
| + // we will transform to identity space if the viewmatrix does not have perspective
|
| + bool hasPerspective = this->viewMatrix().hasPerspective();
|
| + const SkMatrix* geometryProcessorViewM = &SkMatrix::I();
|
| + const SkMatrix* geometryProcessorLocalM = &invert;
|
| + const SkMatrix* toDevice = NULL;
|
| + const SkMatrix* toSrc = NULL;
|
| + if (hasPerspective) {
|
| + geometryProcessorViewM = &this->viewMatrix();
|
| + geometryProcessorLocalM = &SkMatrix::I();
|
| + toDevice = &this->viewMatrix();
|
| + toSrc = &invert;
|
| + }
|
| +
|
| + // Setup geometry processors for worst case
|
| + uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
|
| + GrDefaultGeoProcFactory::kCoverage_GPType;
|
| +
|
| + SkAutoTUnref<const GrGeometryProcessor> lineGP(
|
| + GrDefaultGeoProcFactory::Create(gpFlags,
|
| + this->color(),
|
| + *geometryProcessorViewM,
|
| + *geometryProcessorLocalM,
|
| + false,
|
| + this->coverage()));
|
| +
|
| + SkAutoTUnref<const GrGeometryProcessor> quadGP(
|
| + GrQuadEffect::Create(this->color(),
|
| + *geometryProcessorViewM,
|
| + kHairlineAA_GrProcessorEdgeType,
|
| + batchTarget->caps(),
|
| + *geometryProcessorLocalM,
|
| + this->coverage()));
|
| +
|
| + SkAutoTUnref<const GrGeometryProcessor> conicGP(
|
| + GrConicEffect::Create(this->color(),
|
| + *geometryProcessorViewM,
|
| + kHairlineAA_GrProcessorEdgeType,
|
| + batchTarget->caps(),
|
| + *geometryProcessorLocalM,
|
| + this->coverage()));
|
| +
|
| + // This is hand inlined for maximum performance.
|
| 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;
|
| - }
|
| +
|
| + int instanceCount = fGeoData.count();
|
| + for (int i = 0; i < instanceCount; i++) {
|
| + const Geometry& args = fGeoData[i];
|
| + gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds,
|
| + &lines, &quads, &conics, &qSubdivs, &cWeights);
|
| }
|
|
|
| + int quadCount = quads.count() / 3;
|
| + int lineCount = lines.count() / 2;
|
| + int conicCount = conics.count() / 3;
|
| +
|
| // do lines first
|
| - if (lineCnt) {
|
| - GrDrawTarget::AutoReleaseGeometry arg;
|
| - SkRect devBounds;
|
| -
|
| - GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
|
| - uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
|
| - GrDefaultGeoProcFactory::kCoverage_GPType;
|
| - SkAutoTUnref<const GrGeometryProcessor> 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;
|
| + if (lineCount) {
|
| + batchTarget->initDraw(lineGP, 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();
|
| + lineGP->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + const GrVertexBuffer* vertexBuffer;
|
| + int firstVertex;
|
| +
|
| + size_t vertexStride = lineGP->getVertexStride();
|
| + int vertexCount = kLineSegNumVertices * lineCount;
|
| + void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
| + vertexCount,
|
| + &vertexBuffer,
|
| + &firstVertex);
|
| +
|
| + SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex));
|
| +
|
| + LineVertex* verts = reinterpret_cast<LineVertex*>(vertices);
|
| + for (int i = 0; i < lineCount; ++i) {
|
| + add_line(&lines[2*i], toSrc, this->coverage(), &verts);
|
| }
|
|
|
| - // Check devBounds
|
| - SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I(),
|
| - devBounds,
|
| - arg.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);
|
| + while (lines < lineCount) {
|
| + int n = SkTMin(lineCount - lines, kLineSegsNumInIdxBuffer);
|
| +
|
| + 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,
|
| - quads,
|
| - quadCnt,
|
| - conics,
|
| - conicCnt,
|
| - qSubdivs,
|
| - cWeights,
|
| - sizeof(BezierVertex))) {
|
| - return false;
|
| + if (quadCount || conicCount) {
|
| + 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);
|
| +
|
| + // Setup vertices
|
| + BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices);
|
| +
|
| + // is this the same as quadcount? TODO
|
| + 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);
|
| }
|
|
|
| - // Check devBounds
|
| - SkASSERT(check_bounds<BezierVertex>(viewMatrix.hasPerspective() ? viewMatrix :
|
| - SkMatrix::I(),
|
| - devBounds,
|
| - arg.vertices(),
|
| - kQuadNumVertices * quadCnt +
|
| - kQuadNumVertices * conicCnt));
|
| -
|
| - if (quadCnt > 0) {
|
| - SkAutoTUnref<GrGeometryProcessor> 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;
|
| - }
|
| + // Start Conics
|
| + for (int i = 0; i < conicCount; ++i) {
|
| + add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts);
|
| }
|
|
|
| - if (conicCnt > 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;
|
| + if (quadCount > 0) {
|
| + batchTarget->initDraw(quadGP, 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();
|
| + quadGP->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + {
|
| + 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;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (conicCount > 0) {
|
| + batchTarget->initDraw(conicGP, 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();
|
| + conicGP->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| +
|
| + {
|
| + 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;
|
| + }
|
| }
|
| }
|
| }
|
| +}
|
| +
|
| +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);
|
|
|
| - target->resetIndexSource();
|
| + // This outset was determined experimentally by running skps and gms. It probably could be a
|
| + // bit tighter
|
| + SkRect devRect = path.getBounds();
|
| + viewMatrix.mapRect(&devRect);
|
| + devRect.outset(2, 2);
|
| +
|
| + 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;
|
| }
|
|
|