Index: src/gpu/GrDefaultPathRenderer.cpp |
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp |
deleted file mode 100644 |
index f4ce7c85a52bfc9ca818dad8f87e477e35033f2e..0000000000000000000000000000000000000000 |
--- a/src/gpu/GrDefaultPathRenderer.cpp |
+++ /dev/null |
@@ -1,761 +0,0 @@ |
-/* |
- * Copyright 2011 Google Inc. |
- * |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
- |
-#include "GrDefaultPathRenderer.h" |
- |
-#include "GrBatchFlushState.h" |
-#include "GrBatchTest.h" |
-#include "GrContext.h" |
-#include "GrDefaultGeoProcFactory.h" |
-#include "GrPathUtils.h" |
-#include "GrPipelineBuilder.h" |
-#include "GrVertices.h" |
-#include "SkGeometry.h" |
-#include "SkString.h" |
-#include "SkStrokeRec.h" |
-#include "SkTLazy.h" |
-#include "SkTraceEvent.h" |
- |
-#include "batches/GrVertexBatch.h" |
- |
-GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport, |
- bool stencilWrapOpsSupport) |
- : fSeparateStencil(separateStencilSupport) |
- , fStencilWrapOps(stencilWrapOpsSupport) { |
-} |
- |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// Stencil rules for paths |
- |
-////// Even/Odd |
- |
-GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass, |
- kInvert_StencilOp, |
- kKeep_StencilOp, |
- kAlwaysIfInClip_StencilFunc, |
- 0xffff, |
- 0xffff, |
- 0xffff); |
- |
-// ok not to check clip b/c stencil pass only wrote inside clip |
-GR_STATIC_CONST_SAME_STENCIL(gEOColorPass, |
- kZero_StencilOp, |
- kZero_StencilOp, |
- kNotEqual_StencilFunc, |
- 0xffff, |
- 0x0000, |
- 0xffff); |
- |
-// have to check clip b/c outside clip will always be zero. |
-GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass, |
- kZero_StencilOp, |
- kZero_StencilOp, |
- kEqualIfInClip_StencilFunc, |
- 0xffff, |
- 0x0000, |
- 0xffff); |
- |
-////// Winding |
- |
-// when we have separate stencil we increment front faces / decrement back faces |
-// when we don't have wrap incr and decr we use the stencil test to simulate |
-// them. |
- |
-GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap, |
- kIncWrap_StencilOp, kDecWrap_StencilOp, |
- kKeep_StencilOp, kKeep_StencilOp, |
- kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc, |
- 0xffff, 0xffff, |
- 0xffff, 0xffff, |
- 0xffff, 0xffff); |
- |
-// if inc'ing the max value, invert to make 0 |
-// if dec'ing zero invert to make all ones. |
-// we can't avoid touching the stencil on both passing and |
-// failing, so we can't resctrict ourselves to the clip. |
-GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap, |
- kInvert_StencilOp, kInvert_StencilOp, |
- kIncClamp_StencilOp, kDecClamp_StencilOp, |
- kEqual_StencilFunc, kEqual_StencilFunc, |
- 0xffff, 0xffff, |
- 0xffff, 0x0000, |
- 0xffff, 0xffff); |
- |
-// When there are no separate faces we do two passes to setup the winding rule |
-// stencil. First we draw the front faces and inc, then we draw the back faces |
-// and dec. These are same as the above two split into the incrementing and |
-// decrementing passes. |
-GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc, |
- kIncWrap_StencilOp, |
- kKeep_StencilOp, |
- kAlwaysIfInClip_StencilFunc, |
- 0xffff, |
- 0xffff, |
- 0xffff); |
- |
-GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec, |
- kDecWrap_StencilOp, |
- kKeep_StencilOp, |
- kAlwaysIfInClip_StencilFunc, |
- 0xffff, |
- 0xffff, |
- 0xffff); |
- |
-GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc, |
- kInvert_StencilOp, |
- kIncClamp_StencilOp, |
- kEqual_StencilFunc, |
- 0xffff, |
- 0xffff, |
- 0xffff); |
- |
-GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec, |
- kInvert_StencilOp, |
- kDecClamp_StencilOp, |
- kEqual_StencilFunc, |
- 0xffff, |
- 0x0000, |
- 0xffff); |
- |
-// Color passes are the same whether we use the two-sided stencil or two passes |
- |
-GR_STATIC_CONST_SAME_STENCIL(gWindColorPass, |
- kZero_StencilOp, |
- kZero_StencilOp, |
- kNonZeroIfInClip_StencilFunc, |
- 0xffff, |
- 0x0000, |
- 0xffff); |
- |
-GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass, |
- kZero_StencilOp, |
- kZero_StencilOp, |
- kEqualIfInClip_StencilFunc, |
- 0xffff, |
- 0x0000, |
- 0xffff); |
- |
-////// Normal render to stencil |
- |
-// Sometimes the default path renderer can draw a path directly to the stencil |
-// buffer without having to first resolve the interior / exterior. |
-GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil, |
- kZero_StencilOp, |
- kIncClamp_StencilOp, |
- kAlwaysIfInClip_StencilFunc, |
- 0xffff, |
- 0x0000, |
- 0xffff); |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// Helpers for drawPath |
- |
-#define STENCIL_OFF 0 // Always disable stencil (even when needed) |
- |
-static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) { |
-#if STENCIL_OFF |
- return true; |
-#else |
- if (!stroke.isHairlineStyle() && !path.isInverseFillType()) { |
- return path.isConvex(); |
- } |
- return false; |
-#endif |
-} |
- |
-GrPathRenderer::StencilSupport |
-GrDefaultPathRenderer::onGetStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const { |
- if (single_pass_path(path, stroke)) { |
- return GrPathRenderer::kNoRestriction_StencilSupport; |
- } else { |
- return GrPathRenderer::kStencilOnly_StencilSupport; |
- } |
-} |
- |
-static inline void append_countour_edge_indices(bool hairLine, |
- uint16_t fanCenterIdx, |
- uint16_t edgeV0Idx, |
- uint16_t** indices) { |
- // when drawing lines we're appending line segments along |
- // the contour. When applying the other fill rules we're |
- // drawing triangle fans around fanCenterIdx. |
- if (!hairLine) { |
- *((*indices)++) = fanCenterIdx; |
- } |
- *((*indices)++) = edgeV0Idx; |
- *((*indices)++) = edgeV0Idx + 1; |
-} |
- |
-static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[], |
- SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed, |
- 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 + offset; |
- uint16_t numPts = (uint16_t) |
- GrPathUtils::generateQuadraticPoints( |
- pts[0], pts[1], pts[2], |
- srcSpaceTolSqd, vert, |
- GrPathUtils::quadraticPointCount(pts, srcSpaceTol)); |
- if (indexed) { |
- for (uint16_t i = 0; i < numPts; ++i) { |
- append_countour_edge_indices(isHairline, subpathIdxStart, |
- firstQPtIdx + i, idx); |
- } |
- } |
-} |
- |
-class DefaultPathBatch : public GrVertexBatch { |
-public: |
- struct Geometry { |
- GrColor fColor; |
- SkPath fPath; |
- SkScalar fTolerance; |
- }; |
- |
- static GrDrawBatch* Create(const Geometry& geometry, uint8_t coverage, |
- const SkMatrix& viewMatrix, bool isHairline, |
- const SkRect& devBounds) { |
- return new DefaultPathBatch(geometry, coverage, viewMatrix, isHairline, devBounds); |
- } |
- |
- const char* name() const override { return "DefaultPathBatch"; } |
- |
- void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
- // When this is called on a batch, there is only one geometry bundle |
- out->setKnownFourComponents(fGeoData[0].fColor); |
- } |
- void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { |
- out->setKnownSingleComponent(this->coverage()); |
- } |
- |
-private: |
- void initBatchTracker(const GrPipelineOptimizations& opt) override { |
- // Handle any color overrides |
- if (!opt.readsColor()) { |
- fGeoData[0].fColor = GrColor_ILLEGAL; |
- } |
- opt.getOverrideColorIfSet(&fGeoData[0].fColor); |
- |
- // setup batch properties |
- fBatch.fColorIgnored = !opt.readsColor(); |
- fBatch.fColor = fGeoData[0].fColor; |
- fBatch.fUsesLocalCoords = opt.readsLocalCoords(); |
- fBatch.fCoverageIgnored = !opt.readsCoverage(); |
- } |
- |
- void onPrepareDraws(Target* target) override { |
- SkAutoTUnref<const GrGeometryProcessor> gp; |
- { |
- using namespace GrDefaultGeoProcFactory; |
- Color color(this->color()); |
- Coverage coverage(this->coverage()); |
- if (this->coverageIgnored()) { |
- coverage.fType = Coverage::kNone_Type; |
- } |
- LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : |
- LocalCoords::kUnused_Type); |
- gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, |
- this->viewMatrix())); |
- } |
- |
- size_t vertexStride = gp->getVertexStride(); |
- SkASSERT(vertexStride == sizeof(SkPoint)); |
- |
- target->initDraw(gp, this->pipeline()); |
- |
- 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; |
- } |
- |
- if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) { |
- SkDebugf("Cannot render path (%d)\n", maxVertices); |
- return; |
- } |
- |
- // determine primitiveType |
- int maxIndices = 0; |
- GrPrimitiveType primitiveType; |
- if (this->isHairline()) { |
- if (isIndexed) { |
- maxIndices = 2 * maxVertices; |
- primitiveType = kLines_GrPrimitiveType; |
- } else { |
- primitiveType = kLineStrip_GrPrimitiveType; |
- } |
- } else { |
- if (isIndexed) { |
- maxIndices = 3 * maxVertices; |
- primitiveType = kTriangles_GrPrimitiveType; |
- } else { |
- primitiveType = kTriangleFan_GrPrimitiveType; |
- } |
- } |
- |
- // allocate vertex / index buffers |
- const GrVertexBuffer* vertexBuffer; |
- int firstVertex; |
- |
- void* verts = target->makeVertexSpace(vertexStride, maxVertices, |
- &vertexBuffer, &firstVertex); |
- |
- if (!verts) { |
- SkDebugf("Could not allocate vertices\n"); |
- return; |
- } |
- |
- const GrIndexBuffer* indexBuffer = nullptr; |
- int firstIndex = 0; |
- |
- void* indices = nullptr; |
- if (isIndexed) { |
- indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex); |
- |
- if (!indices) { |
- SkDebugf("Could not allocate indices\n"); |
- return; |
- } |
- } |
- |
- // 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(verts, |
- vertexOffset, |
- indices, |
- indexOffset, |
- &vertexCnt, |
- &indexCnt, |
- args.fPath, |
- args.fTolerance, |
- isIndexed)) { |
- return; |
- } |
- |
- vertexOffset += vertexCnt; |
- indexOffset += indexCnt; |
- SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices); |
- } |
- |
- GrVertices vertices; |
- if (isIndexed) { |
- vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, |
- vertexOffset, indexOffset); |
- } else { |
- vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset); |
- } |
- target->draw(vertices); |
- |
- // put back reserves |
- target->putBackIndices((size_t)(maxIndices - indexOffset)); |
- target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride); |
- } |
- |
- SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
- |
- DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix, |
- bool isHairline, const SkRect& devBounds) { |
- this->initClassID<DefaultPathBatch>(); |
- fBatch.fCoverage = coverage; |
- fBatch.fIsHairline = isHairline; |
- fBatch.fViewMatrix = viewMatrix; |
- fGeoData.push_back(geometry); |
- |
- this->setBounds(devBounds); |
- } |
- |
- bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
- DefaultPathBatch* that = t->cast<DefaultPathBatch>(); |
- if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), |
- that->bounds(), caps)) { |
- return false; |
- } |
- |
- if (this->color() != that->color()) { |
- return false; |
- } |
- |
- if (this->coverage() != that->coverage()) { |
- return false; |
- } |
- |
- if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
- return false; |
- } |
- |
- if (this->isHairline() != that->isHairline()) { |
- return false; |
- } |
- |
- fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); |
- this->joinBounds(that->bounds()); |
- 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; |
- } |
- first = false; |
- } |
- |
- *vertexCnt = static_cast<int>(vert - base); |
- *indexCnt = static_cast<int>(idx - idxBase); |
- |
- } |
- 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; } |
- bool coverageIgnored() const { return fBatch.fCoverageIgnored; } |
- |
- 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, |
- GrColor color, |
- const SkMatrix& viewMatrix, |
- const SkPath& path, |
- const GrStrokeInfo& origStroke, |
- bool stencilOnly) { |
- SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke); |
- |
- SkScalar hairlineCoverage; |
- uint8_t newCoverage = 0xff; |
- if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) { |
- newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); |
- |
- if (!stroke->isHairlineStyle()) { |
- stroke.writable()->setHairlineStyle(); |
- } |
- } |
- |
- 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 |
- SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace()); |
- |
- int passCount = 0; |
- const GrStencilSettings* passes[3]; |
- GrPipelineBuilder::DrawFace drawFace[3]; |
- bool reverse = false; |
- bool lastPassIsBounds; |
- |
- if (isHairline) { |
- passCount = 1; |
- if (stencilOnly) { |
- passes[0] = &gDirectToStencil; |
- } else { |
- passes[0] = nullptr; |
- } |
- lastPassIsBounds = false; |
- drawFace[0] = GrPipelineBuilder::kBoth_DrawFace; |
- } else { |
- if (single_pass_path(path, *stroke)) { |
- passCount = 1; |
- if (stencilOnly) { |
- passes[0] = &gDirectToStencil; |
- } else { |
- passes[0] = nullptr; |
- } |
- drawFace[0] = GrPipelineBuilder::kBoth_DrawFace; |
- lastPassIsBounds = false; |
- } else { |
- switch (path.getFillType()) { |
- case SkPath::kInverseEvenOdd_FillType: |
- reverse = true; |
- // fallthrough |
- case SkPath::kEvenOdd_FillType: |
- passes[0] = &gEOStencilPass; |
- if (stencilOnly) { |
- passCount = 1; |
- lastPassIsBounds = false; |
- } else { |
- passCount = 2; |
- lastPassIsBounds = true; |
- if (reverse) { |
- passes[1] = &gInvEOColorPass; |
- } else { |
- passes[1] = &gEOColorPass; |
- } |
- } |
- drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace; |
- break; |
- |
- case SkPath::kInverseWinding_FillType: |
- reverse = true; |
- // fallthrough |
- case SkPath::kWinding_FillType: |
- if (fSeparateStencil) { |
- if (fStencilWrapOps) { |
- passes[0] = &gWindStencilSeparateWithWrap; |
- } else { |
- passes[0] = &gWindStencilSeparateNoWrap; |
- } |
- passCount = 2; |
- drawFace[0] = GrPipelineBuilder::kBoth_DrawFace; |
- } else { |
- if (fStencilWrapOps) { |
- passes[0] = &gWindSingleStencilWithWrapInc; |
- passes[1] = &gWindSingleStencilWithWrapDec; |
- } else { |
- passes[0] = &gWindSingleStencilNoWrapInc; |
- passes[1] = &gWindSingleStencilNoWrapDec; |
- } |
- // which is cw and which is ccw is arbitrary. |
- drawFace[0] = GrPipelineBuilder::kCW_DrawFace; |
- drawFace[1] = GrPipelineBuilder::kCCW_DrawFace; |
- passCount = 3; |
- } |
- if (stencilOnly) { |
- lastPassIsBounds = false; |
- --passCount; |
- } else { |
- lastPassIsBounds = true; |
- drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace; |
- if (reverse) { |
- passes[passCount-1] = &gInvWindColorPass; |
- } else { |
- passes[passCount-1] = &gWindColorPass; |
- } |
- } |
- break; |
- default: |
- SkDEBUGFAIL("Unknown path fFill!"); |
- return false; |
- } |
- } |
- } |
- |
- SkScalar tol = GrPathUtils::kDefaultTolerance; |
- SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds()); |
- |
- SkRect devBounds; |
- GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds); |
- |
- for (int p = 0; p < passCount; ++p) { |
- pipelineBuilder->setDrawFace(drawFace[p]); |
- if (passes[p]) { |
- *pipelineBuilder->stencil() = *passes[p]; |
- } |
- |
- if (lastPassIsBounds && (p == passCount-1)) { |
- // Reset the XP Factory on pipelineBuilder |
- pipelineBuilder->setXPFactory(backupXPFactory); |
- SkRect bounds; |
- SkMatrix localMatrix = SkMatrix::I(); |
- if (reverse) { |
- SkASSERT(pipelineBuilder->getRenderTarget()); |
- // draw over the dev bounds (which will be the whole dst surface for inv fill). |
- bounds = devBounds; |
- SkMatrix vmi; |
- // mapRect through persp matrix may not be correct |
- if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { |
- vmi.mapRect(&bounds); |
- } else { |
- if (!viewMatrix.invert(&localMatrix)) { |
- return false; |
- } |
- } |
- } else { |
- bounds = path.getBounds(); |
- } |
- const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : |
- viewMatrix; |
- target->drawNonAARect(*pipelineBuilder, color, viewM, bounds, localMatrix); |
- } else { |
- if (passCount > 1) { |
- pipelineBuilder->setDisableColorXPFactory(); |
- } |
- |
- DefaultPathBatch::Geometry geometry; |
- geometry.fColor = color; |
- geometry.fPath = path; |
- geometry.fTolerance = srcSpaceTol; |
- |
- SkAutoTUnref<GrDrawBatch> batch(DefaultPathBatch::Create(geometry, newCoverage, |
- viewMatrix, isHairline, |
- devBounds)); |
- |
- target->drawBatch(*pipelineBuilder, batch); |
- } |
- } |
- return true; |
-} |
- |
-bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { |
- // this class can draw any path with any fill but doesn't do any anti-aliasing. |
- return !args.fAntiAlias && (args.fStroke->isFillStyle() || |
- IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, |
- nullptr)); |
-} |
- |
-bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { |
- return this->internalDrawPath(args.fTarget, |
- args.fPipelineBuilder, |
- args.fColor, |
- *args.fViewMatrix, |
- *args.fPath, |
- *args.fStroke, |
- false); |
-} |
- |
-void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { |
- SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType()); |
- SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType()); |
- this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix, |
- *args.fPath, *args.fStroke, true); |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////////////////////////// |
- |
-#ifdef GR_TEST_UTILS |
- |
-DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) { |
- GrColor color = GrRandomColor(random); |
- SkMatrix viewMatrix = GrTest::TestMatrix(random); |
- |
- // For now just hairlines because the other types of draws require two batches. |
- // TODO we should figure out a way to combine the stencil and cover steps into one batch |
- GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle); |
- SkPath path = GrTest::TestPath(random); |
- |
- // Compute srcSpaceTol |
- SkRect bounds = path.getBounds(); |
- SkScalar tol = GrPathUtils::kDefaultTolerance; |
- SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds); |
- |
- DefaultPathBatch::Geometry geometry; |
- geometry.fColor = color; |
- geometry.fPath = path; |
- geometry.fTolerance = srcSpaceTol; |
- |
- viewMatrix.mapRect(&bounds); |
- uint8_t coverage = GrRandomCoverage(random); |
- return DefaultPathBatch::Create(geometry, coverage, viewMatrix, true, bounds); |
-} |
- |
-#endif |