| Index: src/gpu/GrAAHairLinePathRenderer.cpp
|
| diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
|
| index 6ecaa2eba4653f99d81aaff087c07b4faaee56c8..ce24cf8c26a80d5411f36c205d38bf406638068c 100644
|
| --- a/src/gpu/GrAAHairLinePathRenderer.cpp
|
| +++ b/src/gpu/GrAAHairLinePathRenderer.cpp
|
| @@ -7,9 +7,6 @@
|
|
|
| #include "GrAAHairLinePathRenderer.h"
|
|
|
| -#include "GrBatch.h"
|
| -#include "GrBatchTarget.h"
|
| -#include "GrBufferAllocPool.h"
|
| #include "GrContext.h"
|
| #include "GrDefaultGeoProcFactory.h"
|
| #include "GrDrawTargetCaps.h"
|
| @@ -256,14 +253,14 @@
|
| * subdivide large quads to reduce over-fill. This subdivision has to be
|
| * performed before applying the perspective matrix.
|
| */
|
| -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) {
|
| +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) {
|
| SkPath::Iter iter(path, false);
|
|
|
| int totalQuadCount = 0;
|
| @@ -472,7 +469,8 @@
|
| }
|
|
|
| void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
|
| - const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) {
|
| + const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices],
|
| + SkRect* devBounds) {
|
| SkASSERT(!toDevice == !toSrc);
|
| // original quad is specified by tri a,b,c
|
| SkPoint a = qpts[0];
|
| @@ -537,6 +535,7 @@
|
| 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);
|
| @@ -568,8 +567,9 @@
|
| const SkScalar weight,
|
| const SkMatrix* toDevice,
|
| const SkMatrix* toSrc,
|
| - BezierVertex** vert) {
|
| - bloat_quad(p, toDevice, toSrc, *vert);
|
| + BezierVertex** vert,
|
| + SkRect* devBounds) {
|
| + bloat_quad(p, toDevice, toSrc, *vert, devBounds);
|
| set_conic_coeffs(p, *vert, weight);
|
| *vert += kQuadNumVertices;
|
| }
|
| @@ -578,15 +578,16 @@
|
| int subdiv,
|
| const SkMatrix* toDevice,
|
| const SkMatrix* toSrc,
|
| - BezierVertex** vert) {
|
| + BezierVertex** vert,
|
| + SkRect* devBounds) {
|
| SkASSERT(subdiv >= 0);
|
| if (subdiv) {
|
| SkPoint newP[5];
|
| SkChopQuadAtHalf(p, newP);
|
| - add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
|
| - add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
|
| + add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds);
|
| + add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds);
|
| } else {
|
| - bloat_quad(p, toDevice, toSrc, *vert);
|
| + bloat_quad(p, toDevice, toSrc, *vert, devBounds);
|
| set_uv_quad(p, *vert);
|
| *vert += kQuadNumVertices;
|
| }
|
| @@ -641,6 +642,106 @@
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +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,
|
| @@ -699,444 +800,13 @@
|
| 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<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);
|
| - }
|
| -
|
| - 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,
|
| - 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<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(),
|
| - 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<BezierVertex>(vm,
|
| - args.fDevBounds,
|
| - vertices,
|
| - kQuadNumVertices * quadCount +
|
| - kQuadNumVertices * conicCount));
|
| -
|
| - if (quadCount > 0) {
|
| - SkAutoTUnref<GrGeometryProcessor> 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<GrGeometryProcessor> 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<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;
|
| - 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) {
|
| + bool antiAlias) {
|
| SkScalar hairlineCoverage;
|
| uint8_t newCoverage = 0xff;
|
| if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
|
| @@ -1146,22 +816,163 @@
|
| 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);
|
| + 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;
|
| + }
|
| + }
|
| +
|
| + // 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;
|
| + }
|
| +
|
| + // Check devBounds
|
| + SkASSERT(check_bounds<LineVertex>(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<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;
|
| + }
|
| + }
|
| +
|
| + 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;
|
| + }
|
| + }
|
| + }
|
| +
|
| + target->resetIndexSource();
|
|
|
| return true;
|
| }
|
|
|