diff options
-rw-r--r-- | src/gpu/GrAARectRenderer.cpp | 4 | ||||
-rw-r--r-- | src/gpu/GrDefaultPathRenderer.cpp | 460 |
2 files changed, 311 insertions, 153 deletions
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp index fa755dce5d..2cc8f95add 100644 --- a/src/gpu/GrAARectRenderer.cpp +++ b/src/gpu/GrAARectRenderer.cpp @@ -588,8 +588,8 @@ public: return; } - SkAutoTUnref<const GrGeometryProcessor>gp(create_fill_rect_gp(canTweakAlphaForCoverage, - localMatrix)); + SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage, + localMatrix)); batchTarget->initDraw(gp, pipeline); diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp index 7b9817484f..792b76c8f7 100644 --- a/src/gpu/GrDefaultPathRenderer.cpp +++ b/src/gpu/GrDefaultPathRenderer.cpp @@ -7,6 +7,9 @@ #include "GrDefaultPathRenderer.h" +#include "GrBatch.h" +#include "GrBatchTarget.h" +#include "GrBufferAllocPool.h" #include "GrContext.h" #include "GrDefaultGeoProcFactory.h" #include "GrPathUtils.h" @@ -191,9 +194,9 @@ static inline void append_countour_edge_indices(bool hairLine, static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed, - bool isHairline, uint16_t subpathIdxStart, uint16_t** idx) { + bool isHairline, uint16_t subpathIdxStart, int offset, uint16_t** idx) { // first pt of quad is the pt we ended on in previous step - uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1; + uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset; uint16_t numPts = (uint16_t) GrPathUtils::generateQuadraticPoints( pts[0], pts[1], pts[2], @@ -207,139 +210,316 @@ static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint p } } -bool GrDefaultPathRenderer::createGeom(GrDrawTarget* target, - GrPipelineBuilder* pipelineBuilder, - GrPrimitiveType* primType, - int* vertexCnt, - int* indexCnt, - GrDrawTarget::AutoReleaseGeometry* arg, - const SkPath& path, - const SkStrokeRec& stroke, - SkScalar srcSpaceTol) { - { - SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol); - int contourCnt; - int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, - srcSpaceTol); - - if (maxPts <= 0) { - return false; +class DefaultPathBatch : public GrBatch { +public: + struct Geometry { + GrColor fColor; + SkPath fPath; + SkScalar fTolerance; + SkDEBUGCODE(SkRect fDevBounds;) + }; + + static GrBatch* Create(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix, + bool isHairline) { + return SkNEW_ARGS(DefaultPathBatch, (geometry, coverage, viewMatrix, isHairline)); + } + + const char* name() const SK_OVERRIDE { return "DefaultPathBatch"; } + + 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); } - if (maxPts > ((int)SK_MaxU16 + 1)) { - SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); - return false; + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE { + out->setUnknownSingleComponent(); } - bool indexed = contourCnt > 1; + 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; + } - const bool isHairline = stroke.isHairlineStyle(); + // setup batch properties + fBatch.fColorIgnored = init.fColorIgnored; + fBatch.fColor = fGeoData[0].fColor; + fBatch.fUsesLocalCoords = init.fUsesLocalCoords; + fBatch.fCoverageIgnored = init.fCoverageIgnored; + } - int maxIdxs = 0; - if (isHairline) { - if (indexed) { - maxIdxs = 2 * maxPts; - *primType = kLines_GrPrimitiveType; + void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE { + SkAutoTUnref<const GrGeometryProcessor> gp( + GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, + this->color(), + this->viewMatrix(), + SkMatrix::I(), + false, + this->coverage())); + + size_t vertexStride = gp->getVertexStride(); + SkASSERT(vertexStride == sizeof(SkPoint)); + + batchTarget->initDraw(gp, pipeline); + + // TODO this is hacky, but the only way we have to initialize the GP is to use the + // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch + // everywhere we can remove this nastiness + GrPipelineInfo init; + init.fColorIgnored = fBatch.fColorIgnored; + init.fOverrideColor = GrColor_ILLEGAL; + init.fCoverageIgnored = fBatch.fCoverageIgnored; + init.fUsesLocalCoords = this->usesLocalCoords(); + gp->initBatchTracker(batchTarget->currentBatchTracker(), init); + + int instanceCount = fGeoData.count(); + + // compute number of vertices + int maxVertices = 0; + + // We will use index buffers if we have multiple paths or one path with multiple contours + bool isIndexed = instanceCount > 1; + for (int i = 0; i < instanceCount; i++) { + Geometry& args = fGeoData[i]; + + int contourCount; + maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount, + args.fTolerance); + + isIndexed = isIndexed || contourCount > 1; + } + + // determine primitiveType + int maxIndices = 0; + GrPrimitiveType primitiveType; + if (this->isHairline()) { + if (isIndexed) { + maxIndices = 2 * maxVertices; + primitiveType = kLines_GrPrimitiveType; + } else { + primitiveType = kLineStrip_GrPrimitiveType; + } } else { - *primType = kLineStrip_GrPrimitiveType; + if (isIndexed) { + maxIndices = 3 * maxVertices; + primitiveType = kTriangles_GrPrimitiveType; + } else { + primitiveType = kTriangleFan_GrPrimitiveType; + } } - } else { - if (indexed) { - maxIdxs = 3 * maxPts; - *primType = kTriangles_GrPrimitiveType; + + // allocate vertex / index buffers + const GrVertexBuffer* vertexBuffer; + int firstVertex; + + void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, + maxVertices, + &vertexBuffer, + &firstVertex); + + const GrIndexBuffer* indexBuffer; + int firstIndex; + + void* indices = NULL; + if (isIndexed) { + indices = batchTarget->indexPool()->makeSpace(maxIndices, + &indexBuffer, + &firstIndex); + } + + // fill buffers + int vertexOffset = 0; + int indexOffset = 0; + for (int i = 0; i < instanceCount; i++) { + Geometry& args = fGeoData[i]; + + int vertexCnt = 0; + int indexCnt = 0; + if (!this->createGeom(vertices, + vertexOffset, + indices, + indexOffset, + &vertexCnt, + &indexCnt, + args.fPath, + args.fTolerance, + isIndexed)) { + return; + } + + vertexOffset += vertexCnt; + indexOffset += indexCnt; + SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices); + } + + GrDrawTarget::DrawInfo drawInfo; + drawInfo.setPrimitiveType(primitiveType); + drawInfo.setVertexBuffer(vertexBuffer); + drawInfo.setStartVertex(firstVertex); + drawInfo.setVertexCount(vertexOffset); + if (isIndexed) { + drawInfo.setIndexBuffer(indexBuffer); + drawInfo.setStartIndex(firstIndex); + drawInfo.setIndexCount(indexOffset); } else { - *primType = kTriangleFan_GrPrimitiveType; + drawInfo.setStartIndex(0); + drawInfo.setIndexCount(0); } + batchTarget->draw(drawInfo); } - if (!arg->set(target, maxPts, GrDefaultGeoProcFactory::DefaultVertexStride(), maxIdxs)) { - return false; + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } + +private: + DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix, + bool isHairline) { + this->initClassID<DefaultPathBatch>(); + fBatch.fCoverage = coverage; + fBatch.fIsHairline = isHairline; + fBatch.fViewMatrix = viewMatrix; + fGeoData.push_back(geometry); } - SkASSERT(GrDefaultGeoProcFactory::DefaultVertexStride() == sizeof(SkPoint)); - uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices()); - uint16_t* idx = idxBase; - uint16_t subpathIdxStart = 0; + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE { + DefaultPathBatch* that = t->cast<DefaultPathBatch>(); - SkPoint* base = reinterpret_cast<SkPoint*>(arg->vertices()); - SkASSERT(base); - SkPoint* vert = base; + if (this->color() != that->color()) { + return false; + } - SkPoint pts[4]; + if (this->coverage() != that->coverage()) { + return false; + } - bool first = true; - int subpath = 0; + if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { + return false; + } - SkPath::Iter iter(path, false); + if (this->isHairline() != that->isHairline()) { + return false; + } - for (;;) { - SkPath::Verb verb = iter.next(pts); - switch (verb) { - case SkPath::kMove_Verb: - if (!first) { - uint16_t currIdx = (uint16_t) (vert - base); - subpathIdxStart = currIdx; - ++subpath; - } - *vert = pts[0]; - vert++; - break; - case SkPath::kLine_Verb: - if (indexed) { - uint16_t prevIdx = (uint16_t)(vert - base) - 1; - append_countour_edge_indices(isHairline, subpathIdxStart, - prevIdx, &idx); - } - *(vert++) = pts[1]; - break; - case SkPath::kConic_Verb: { - SkScalar weight = iter.conicWeight(); - SkAutoConicToQuads converter; - // Converting in src-space, hance the finer tolerance (0.25) - // TODO: find a way to do this in dev-space so the tolerance means something - const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f); - for (int i = 0; i < converter.countQuads(); ++i) { - add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol, indexed, - isHairline, subpathIdxStart, &idx); - } - break; - } - case SkPath::kQuad_Verb: - add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, indexed, - isHairline, subpathIdxStart, &idx); - break; - case SkPath::kCubic_Verb: { - // first pt of cubic is the pt we ended on in previous step - uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1; - uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints( - pts[0], pts[1], pts[2], pts[3], - srcSpaceTolSqd, &vert, - GrPathUtils::cubicPointCount(pts, srcSpaceTol)); - if (indexed) { - for (uint16_t i = 0; i < numPts; ++i) { - append_countour_edge_indices(isHairline, subpathIdxStart, - firstCPtIdx + i, &idx); + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); + return true; + } + + bool createGeom(void* vertices, + size_t vertexOffset, + void* indices, + size_t indexOffset, + int* vertexCnt, + int* indexCnt, + const SkPath& path, + SkScalar srcSpaceTol, + bool isIndexed) { + { + SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol); + + uint16_t indexOffsetU16 = (uint16_t)indexOffset; + uint16_t vertexOffsetU16 = (uint16_t)vertexOffset; + + uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffsetU16; + uint16_t* idx = idxBase; + uint16_t subpathIdxStart = vertexOffsetU16; + + SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset; + SkPoint* vert = base; + + SkPoint pts[4]; + + bool first = true; + int subpath = 0; + + SkPath::Iter iter(path, false); + + bool done = false; + while (!done) { + SkPath::Verb verb = iter.next(pts); + switch (verb) { + case SkPath::kMove_Verb: + if (!first) { + uint16_t currIdx = (uint16_t) (vert - base) + vertexOffsetU16; + subpathIdxStart = currIdx; + ++subpath; + } + *vert = pts[0]; + vert++; + break; + case SkPath::kLine_Verb: + if (isIndexed) { + uint16_t prevIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16; + append_countour_edge_indices(this->isHairline(), subpathIdxStart, + prevIdx, &idx); + } + *(vert++) = pts[1]; + break; + case SkPath::kConic_Verb: { + SkScalar weight = iter.conicWeight(); + SkAutoConicToQuads converter; + // Converting in src-space, hance the finer tolerance (0.25) + // TODO: find a way to do this in dev-space so the tolerance means something + const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f); + for (int i = 0; i < converter.countQuads(); ++i) { + add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol, + isIndexed, this->isHairline(), subpathIdxStart, + (int)vertexOffset, &idx); + } + break; + } + case SkPath::kQuad_Verb: + add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed, + this->isHairline(), subpathIdxStart, (int)vertexOffset, &idx); + break; + case SkPath::kCubic_Verb: { + // first pt of cubic is the pt we ended on in previous step + uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16; + uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints( + pts[0], pts[1], pts[2], pts[3], + srcSpaceTolSqd, &vert, + GrPathUtils::cubicPointCount(pts, srcSpaceTol)); + if (isIndexed) { + for (uint16_t i = 0; i < numPts; ++i) { + append_countour_edge_indices(this->isHairline(), subpathIdxStart, + firstCPtIdx + i, &idx); + } + } + break; } + case SkPath::kClose_Verb: + break; + case SkPath::kDone_Verb: + done = true; } - break; + first = false; } - case SkPath::kClose_Verb: - break; - case SkPath::kDone_Verb: - // uint16_t currIdx = (uint16_t) (vert - base); - goto FINISHED; - } - first = false; - } -FINISHED: - SkASSERT((vert - base) <= maxPts); - SkASSERT((idx - idxBase) <= maxIdxs); - *vertexCnt = static_cast<int>(vert - base); - *indexCnt = static_cast<int>(idx - idxBase); + *vertexCnt = static_cast<int>(vert - base); + *indexCnt = static_cast<int>(idx - idxBase); + } + return true; } - 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 fBatch.fViewMatrix; } + bool isHairline() const { return fBatch.fIsHairline; } + + struct BatchTracker { + GrColor fColor; + uint8_t fCoverage; + SkMatrix fViewMatrix; + bool fUsesLocalCoords; + bool fColorIgnored; + bool fCoverageIgnored; + bool fIsHairline; + }; + + BatchTracker fBatch; + SkSTArray<1, Geometry, true> fGeoData; +}; bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder, @@ -360,24 +540,8 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, } } - SkScalar tol = SK_Scalar1; - tol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds()); - - int vertexCnt; - int indexCnt; - GrPrimitiveType primType; - GrDrawTarget::AutoReleaseGeometry arg; - if (!this->createGeom(target, - pipelineBuilder, - &primType, - &vertexCnt, - &indexCnt, - &arg, - path, - *stroke, - tol)) { - return false; - } + const bool isHairline = stroke->isHairlineStyle(); + // Save the current xp on the draw state so we can reset it if needed SkAutoTUnref<const GrXPFactory> backupXPFactory(SkRef(pipelineBuilder->getXPFactory())); // face culling doesn't make sense here @@ -385,11 +549,11 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, int passCount = 0; const GrStencilSettings* passes[3]; - GrPipelineBuilder::DrawFace drawFace[3]; + GrPipelineBuilder::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; - if (stroke->isHairlineStyle()) { + if (isHairline) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; @@ -475,6 +639,9 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, } } + SkScalar tol = SK_Scalar1; + SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds()); + SkRect devBounds; GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds); @@ -513,26 +680,17 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, if (passCount > 1) { pipelineBuilder->setDisableColorXPFactory(); } - GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); - SkAutoTUnref<const GrGeometryProcessor> gp( - GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, - color, - viewMatrix, - SkMatrix::I(), - false, - newCoverage)); - if (indexCnt) { - target->drawIndexed(pipelineBuilder, - gp, - primType, - 0, - 0, - vertexCnt, - indexCnt, - &devBounds); - } else { - target->drawNonIndexed(pipelineBuilder, gp, primType, 0, vertexCnt, &devBounds); - } + + DefaultPathBatch::Geometry geometry; + geometry.fColor = color; + geometry.fPath = path; + geometry.fTolerance = srcSpaceTol; + SkDEBUGCODE(geometry.fDevBounds = devBounds;) + + SkAutoTUnref<GrBatch> batch(DefaultPathBatch::Create(geometry, newCoverage, viewMatrix, + isHairline)); + + target->drawBatch(pipelineBuilder, batch, &devBounds); } } return true; |