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; |
} |