Index: src/gpu/batches/GrPLSPathRenderer.cpp |
diff --git a/src/gpu/batches/GrPLSPathRenderer.cpp b/src/gpu/batches/GrPLSPathRenderer.cpp |
deleted file mode 100644 |
index 7f8eaa4da94ca006bba8c5c2e6df23aa9a8e2ba1..0000000000000000000000000000000000000000 |
--- a/src/gpu/batches/GrPLSPathRenderer.cpp |
+++ /dev/null |
@@ -1,1011 +0,0 @@ |
-/* |
- * Copyright 2015 Google Inc. |
- * |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
- |
-#include "GrPLSPathRenderer.h" |
- |
-#include "SkChunkAlloc.h" |
-#include "SkGeometry.h" |
-#include "SkPathPriv.h" |
-#include "SkString.h" |
-#include "SkTSort.h" |
-#include "SkTraceEvent.h" |
-#include "GrBatchFlushState.h" |
-#include "GrBatchTest.h" |
-#include "GrCaps.h" |
-#include "GrContext.h" |
-#include "GrDefaultGeoProcFactory.h" |
-#include "GrPLSGeometryProcessor.h" |
-#include "GrInvariantOutput.h" |
-#include "GrPathUtils.h" |
-#include "GrProcessor.h" |
-#include "GrPipelineBuilder.h" |
-#include "GrStrokeInfo.h" |
-#include "GrTessellator.h" |
-#include "batches/GrVertexBatch.h" |
-#include "glsl/GrGLSLGeometryProcessor.h" |
-#include "gl/builders/GrGLProgramBuilder.h" |
-#include "glsl/GrGLSLPLSPathRendering.h" |
- |
-GrPLSPathRenderer::GrPLSPathRenderer() { |
-} |
- |
-struct PLSVertex { |
- SkPoint fPos; |
- // for triangles, these are the three triangle vertices |
- // for quads, vert1 is the texture UV coords, and vert2 and vert3 are the line segment |
- // comprising the flat edge of the quad |
- SkPoint fVert1; |
- SkPoint fVert2; |
- SkPoint fVert3; |
- int fWinding; |
-}; |
-typedef SkTArray<PLSVertex, true> PLSVertices; |
- |
-typedef SkTArray<SkPoint, true> FinishVertices; |
- |
-static const float kCubicTolerance = 0.5f; |
-static const float kConicTolerance = 0.5f; |
- |
-static const float kBloatSize = 1.0f; |
- |
-static const float kBloatLimit = 640000.0f; |
- |
-#define kQuadNumVertices 5 |
-static void add_quad(SkPoint pts[3], PLSVertices& vertices) { |
- SkPoint normal = SkPoint::Make(pts[0].fY - pts[2].fY, |
- pts[2].fX - pts[0].fX); |
- normal.setLength(kBloatSize); |
- SkScalar cross = (pts[1] - pts[0]).cross(pts[2] - pts[0]); |
- if (cross < 0) { |
- normal = -normal; |
- } |
- PLSVertex quad[kQuadNumVertices]; |
- quad[0].fPos = pts[0] + normal; |
- quad[1].fPos = pts[0] - normal; |
- quad[2].fPos = pts[1] - normal; |
- quad[3].fPos = pts[2] - normal; |
- quad[4].fPos = pts[2] + normal; |
- for (int i = 0; i < kQuadNumVertices; i++) { |
- quad[i].fWinding = cross < 0 ? 1 : -1; |
- if (cross > 0.0) { |
- quad[i].fVert2 = pts[0]; |
- quad[i].fVert3 = pts[2]; |
- } |
- else { |
- quad[i].fVert2 = pts[2]; |
- quad[i].fVert3 = pts[0]; |
- } |
- } |
- GrPathUtils::QuadUVMatrix DevToUV(pts); |
- DevToUV.apply<kQuadNumVertices, sizeof(PLSVertex), sizeof(SkPoint)>(quad); |
- for (int i = 2; i < kQuadNumVertices; i++) { |
- vertices.push_back(quad[0]); |
- vertices.push_back(quad[i - 1]); |
- vertices.push_back(quad[i]); |
- } |
-} |
- |
-/* Used by bloat_tri; outsets a single point. */ |
-static bool outset(SkPoint* p1, SkPoint line1, SkPoint line2) { |
- // rotate the two line vectors 90 degrees to form the normals, and compute |
- // the dot product of the normals |
- SkScalar dotProd = line1.fY * line2.fY + line1.fX * line2.fX; |
- SkScalar lengthSq = 1.0f / ((1.0f - dotProd) / 2.0f); |
- if (lengthSq > kBloatLimit) { |
- return false; |
- } |
- SkPoint bisector = line1 + line2; |
- bisector.setLength(SkScalarSqrt(lengthSq) * kBloatSize); |
- *p1 += bisector; |
- return true; |
-} |
- |
-/* Bloats a triangle so as to create a border kBloatSize pixels wide all around it. */ |
-static bool bloat_tri(SkPoint pts[3]) { |
- SkPoint line1 = pts[0] - pts[1]; |
- line1.normalize(); |
- SkPoint line2 = pts[0] - pts[2]; |
- line2.normalize(); |
- SkPoint line3 = pts[1] - pts[2]; |
- line3.normalize(); |
- |
- SkPoint result[3]; |
- result[0] = pts[0]; |
- if (!outset(&result[0], line1, line2)) { |
- return false; |
- } |
- result[1] = pts[1]; |
- if (!outset(&result[1], -line1, line3)) { |
- return false; |
- } |
- result[2] = pts[2]; |
- if (!outset(&result[2], -line3, -line2)) { |
- return false; |
- } |
- pts[0] = result[0]; |
- pts[1] = result[1]; |
- pts[2] = result[2]; |
- return true; |
-} |
- |
-static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices, |
- PLSVertices& quadVertices, GrResourceProvider* resourceProvider, |
- SkRect bounds) { |
- SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
- SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, m, bounds); |
- int contourCnt; |
- int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); |
- if (maxPts <= 0) { |
- return 0; |
- } |
- SkPath linesOnlyPath; |
- linesOnlyPath.setFillType(path.getFillType()); |
- SkSTArray<15, SkPoint, true> quadPoints; |
- SkPathPriv::FirstDirection dir = SkPathPriv::FirstDirection::kUnknown_FirstDirection; |
- SkPath::Iter iter(path, true); |
- bool done = false; |
- while (!done) { |
- SkPoint pts[4]; |
- SkPath::Verb verb = iter.next(pts); |
- switch (verb) { |
- case SkPath::kMove_Verb: |
- SkASSERT(quadPoints.count() % 3 == 0); |
- for (int i = 0; i < quadPoints.count(); i += 3) { |
- add_quad(&quadPoints[i], quadVertices); |
- } |
- quadPoints.reset(); |
- m.mapPoints(&pts[0], 1); |
- linesOnlyPath.moveTo(pts[0]); |
- break; |
- case SkPath::kLine_Verb: |
- m.mapPoints(&pts[1], 1); |
- linesOnlyPath.lineTo(pts[1]); |
- break; |
- case SkPath::kQuad_Verb: |
- m.mapPoints(pts, 3); |
- linesOnlyPath.lineTo(pts[2]); |
- quadPoints.push_back(pts[0]); |
- quadPoints.push_back(pts[1]); |
- quadPoints.push_back(pts[2]); |
- break; |
- case SkPath::kCubic_Verb: { |
- m.mapPoints(pts, 4); |
- SkSTArray<15, SkPoint, true> quads; |
- GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, false, dir, &quads); |
- int count = quads.count(); |
- for (int q = 0; q < count; q += 3) { |
- linesOnlyPath.lineTo(quads[q + 2]); |
- quadPoints.push_back(quads[q]); |
- quadPoints.push_back(quads[q + 1]); |
- quadPoints.push_back(quads[q + 2]); |
- } |
- break; |
- } |
- case SkPath::kConic_Verb: { |
- m.mapPoints(pts, 3); |
- SkScalar weight = iter.conicWeight(); |
- SkAutoConicToQuads converter; |
- const SkPoint* quads = converter.computeQuads(pts, weight, kConicTolerance); |
- int count = converter.countQuads(); |
- for (int i = 0; i < count; ++i) { |
- linesOnlyPath.lineTo(quads[2 * i + 2]); |
- quadPoints.push_back(quads[2 * i]); |
- quadPoints.push_back(quads[2 * i + 1]); |
- quadPoints.push_back(quads[2 * i + 2]); |
- } |
- break; |
- } |
- case SkPath::kClose_Verb: |
- linesOnlyPath.close(); |
- break; |
- case SkPath::kDone_Verb: |
- done = true; |
- break; |
- default: SkASSERT(false); |
- } |
- } |
- SkASSERT(quadPoints.count() % 3 == 0); |
- for (int i = 0; i < quadPoints.count(); i += 3) { |
- add_quad(&quadPoints[i], quadVertices); |
- } |
- |
- static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
- GrUniqueKey key; |
- GrUniqueKey::Builder builder(&key, kDomain, 2); |
- builder[0] = path.getGenerationID(); |
- builder[1] = path.getFillType(); |
- builder.finish(); |
- GrTessellator::WindingVertex* windingVertices; |
- int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds, &windingVertices); |
- if (triVertexCount > 0) { |
- for (int i = 0; i < triVertexCount; i += 3) { |
- SkPoint p1 = windingVertices[i].fPos; |
- SkPoint p2 = windingVertices[i + 1].fPos; |
- SkPoint p3 = windingVertices[i + 2].fPos; |
- int winding = windingVertices[i].fWinding; |
- SkASSERT(windingVertices[i + 1].fWinding == winding); |
- SkASSERT(windingVertices[i + 2].fWinding == winding); |
- SkScalar cross = (p2 - p1).cross(p3 - p1); |
- SkPoint bloated[3] = { p1, p2, p3 }; |
- if (cross < 0.0f) { |
- SkTSwap(p1, p3); |
- } |
- if (bloat_tri(bloated)) { |
- triVertices.push_back({ bloated[0], p1, p2, p3, winding }); |
- triVertices.push_back({ bloated[1], p1, p2, p3, winding }); |
- triVertices.push_back({ bloated[2], p1, p2, p3, winding }); |
- } |
- else { |
- SkScalar minX = SkTMin(p1.fX, SkTMin(p2.fX, p3.fX)) - 1.0f; |
- SkScalar minY = SkTMin(p1.fY, SkTMin(p2.fY, p3.fY)) - 1.0f; |
- SkScalar maxX = SkTMax(p1.fX, SkTMax(p2.fX, p3.fX)) + 1.0f; |
- SkScalar maxY = SkTMax(p1.fY, SkTMax(p2.fY, p3.fY)) + 1.0f; |
- triVertices.push_back({ { minX, minY }, p1, p2, p3, winding }); |
- triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); |
- triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); |
- triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); |
- triVertices.push_back({ { maxX, maxY }, p1, p2, p3, winding }); |
- triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); |
- } |
- } |
- delete[] windingVertices; |
- } |
- return triVertexCount > 0 || quadVertices.count() > 0; |
-} |
- |
-class PLSAATriangleEffect : public GrPLSGeometryProcessor { |
-public: |
- |
- static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, |
- bool usesLocalCoords) { |
- return new PLSAATriangleEffect(localMatrix, usesLocalCoords); |
- } |
- |
- virtual ~PLSAATriangleEffect() {} |
- |
- const char* name() const override { return "PLSAATriangle"; } |
- |
- const Attribute* inPosition() const { return fInPosition; } |
- const Attribute* inVertex1() const { return fInVertex1; } |
- const Attribute* inVertex2() const { return fInVertex2; } |
- const Attribute* inVertex3() const { return fInVertex3; } |
- const Attribute* inWindings() const { return fInWindings; } |
- const SkMatrix& localMatrix() const { return fLocalMatrix; } |
- bool usesLocalCoords() const { return fUsesLocalCoords; } |
- |
- class GLSLProcessor : public GrGLSLGeometryProcessor { |
- public: |
- GLSLProcessor(const GrGeometryProcessor&) {} |
- |
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { |
- const PLSAATriangleEffect& te = args.fGP.cast<PLSAATriangleEffect>(); |
- GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; |
- GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
- |
- varyingHandler->emitAttributes(te); |
- |
- this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName); |
- |
- GrGLSLVertToFrag v1(kVec2f_GrSLType); |
- varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", |
- v1.vsOut(), |
- te.inVertex1()->fName, |
- te.inVertex1()->fName); |
- |
- GrGLSLVertToFrag v2(kVec2f_GrSLType); |
- varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", |
- v2.vsOut(), |
- te.inVertex2()->fName, |
- te.inVertex2()->fName); |
- |
- GrGLSLVertToFrag v3(kVec2f_GrSLType); |
- varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", |
- v3.vsOut(), |
- te.inVertex3()->fName, |
- te.inVertex3()->fName); |
- |
- GrGLSLVertToFrag delta1(kVec2f_GrSLType); |
- varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", |
- delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut()); |
- |
- GrGLSLVertToFrag delta2(kVec2f_GrSLType); |
- varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", |
- delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut()); |
- |
- GrGLSLVertToFrag delta3(kVec2f_GrSLType); |
- varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", |
- delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut()); |
- |
- GrGLSLVertToFrag windings(kInt_GrSLType); |
- varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = %s;", |
- windings.vsOut(), te.inWindings()->fName); |
- |
- // emit transforms |
- this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, |
- te.inPosition()->fName, te.localMatrix(), args.fTransformsIn, |
- args.fTransformsOut); |
- |
- GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; |
- SkAssertResult(fsBuilder->enableFeature( |
- GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); |
- SkAssertResult(fsBuilder->enableFeature( |
- GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); |
- fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); |
- // Compute four subsamples, each shifted a quarter pixel along x and y from |
- // gl_FragCoord. The oriented box positioning of the subsamples is of course not |
- // optimal, but it greatly simplifies the math and this simplification is necessary for |
- // performance reasons. |
- fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);", |
- fsBuilder->fragmentPosition()); |
- fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn()); |
- fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn()); |
- fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn()); |
- // Check whether first sample is inside the triangle by computing three dot products. If |
- // all are < 0, we're inside. The first vector in each case is half of what it is |
- // "supposed" to be, because we re-use them later as adjustment factors for which half |
- // is the correct value, so we multiply the dots by two to compensate. |
- fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;", |
- v1.fsIn()); |
- fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;", |
- v2.fsIn()); |
- fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;", |
- v3.fsIn()); |
- fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));"); |
- fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); |
- // for subsequent samples, we don't recalculate the entire dot product -- just adjust it |
- // to the value it would have if we did recompute it. |
- fsBuilder->codeAppend("d1 += delta1.x;"); |
- fsBuilder->codeAppend("d2 += delta2.x;"); |
- fsBuilder->codeAppend("d3 += delta3.x;"); |
- fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); |
- fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); |
- fsBuilder->codeAppend("d1 += delta1.y;"); |
- fsBuilder->codeAppend("d2 += delta2.y;"); |
- fsBuilder->codeAppend("d3 += delta3.y;"); |
- fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); |
- fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); |
- fsBuilder->codeAppend("d1 -= delta1.x;"); |
- fsBuilder->codeAppend("d2 -= delta2.x;"); |
- fsBuilder->codeAppend("d3 -= delta3.x;"); |
- fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); |
- fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); |
- } |
- |
- static inline void GenKey(const GrGeometryProcessor& gp, |
- const GrGLSLCaps&, |
- GrProcessorKeyBuilder* b) { |
- const PLSAATriangleEffect& te = gp.cast<PLSAATriangleEffect>(); |
- uint32_t key = 0; |
- key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0; |
- b->add32(key); |
- } |
- |
- virtual void setData(const GrGLSLProgramDataManager& pdman, |
- const GrPrimitiveProcessor& gp) override { |
- } |
- |
- void setTransformData(const GrPrimitiveProcessor& primProc, |
- const GrGLSLProgramDataManager& pdman, |
- int index, |
- const SkTArray<const GrCoordTransform*, true>& transforms) override { |
- this->setTransformDataHelper<PLSAATriangleEffect>(primProc, pdman, index, transforms); |
- } |
- |
- private: |
- typedef GrGLSLGeometryProcessor INHERITED; |
- }; |
- |
- virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, |
- GrProcessorKeyBuilder* b) const override { |
- GLSLProcessor::GenKey(*this, caps, b); |
- } |
- |
- virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { |
- return new GLSLProcessor(*this); |
- } |
- |
-private: |
- PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords) |
- : fLocalMatrix(localMatrix) |
- , fUsesLocalCoords(usesLocalCoords) { |
- this->initClassID<PLSAATriangleEffect>(); |
- fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInVertex1 = &this->addVertexAttrib(Attribute("inVertex1", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInVertex2 = &this->addVertexAttrib(Attribute("inVertex2", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInVertex3 = &this->addVertexAttrib(Attribute("inVertex3", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType, |
- kLow_GrSLPrecision)); |
- this->setWillReadFragmentPosition(); |
- } |
- |
- const Attribute* fInPosition; |
- const Attribute* fInVertex1; |
- const Attribute* fInVertex2; |
- const Attribute* fInVertex3; |
- const Attribute* fInWindings; |
- SkMatrix fLocalMatrix; |
- bool fUsesLocalCoords; |
- |
- GR_DECLARE_GEOMETRY_PROCESSOR_TEST; |
- |
- typedef GrGeometryProcessor INHERITED; |
-}; |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-/* |
- * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
- * two components of the vertex attribute. Coverage is based on signed |
- * distance with negative being inside, positive outside. The edge is specified in |
- * window space (y-down). If either the third or fourth component of the interpolated |
- * vertex coord is > 0 then the pixel is considered outside the edge. This is used to |
- * attempt to trim to a portion of the infinite quad. |
- * Requires shader derivative instruction support. |
- */ |
- |
-class PLSQuadEdgeEffect : public GrPLSGeometryProcessor { |
-public: |
- |
- static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, |
- bool usesLocalCoords) { |
- return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords); |
- } |
- |
- virtual ~PLSQuadEdgeEffect() {} |
- |
- const char* name() const override { return "PLSQuadEdge"; } |
- |
- const Attribute* inPosition() const { return fInPosition; } |
- const Attribute* inUV() const { return fInUV; } |
- const Attribute* inEndpoint1() const { return fInEndpoint1; } |
- const Attribute* inEndpoint2() const { return fInEndpoint2; } |
- const Attribute* inWindings() const { return fInWindings; } |
- const SkMatrix& localMatrix() const { return fLocalMatrix; } |
- bool usesLocalCoords() const { return fUsesLocalCoords; } |
- |
- class GLSLProcessor : public GrGLSLGeometryProcessor { |
- public: |
- GLSLProcessor(const GrGeometryProcessor&) {} |
- |
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { |
- const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>(); |
- GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; |
- GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
- |
- // emit attributes |
- varyingHandler->emitAttributes(qe); |
- |
- GrGLSLVertToFrag uv(kVec2f_GrSLType); |
- varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName); |
- |
- GrGLSLVertToFrag ep1(kVec2f_GrSLType); |
- varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(), |
- qe.inEndpoint1()->fName, qe.inEndpoint1()->fName); |
- |
- GrGLSLVertToFrag ep2(kVec2f_GrSLType); |
- varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(), |
- qe.inEndpoint2()->fName, qe.inEndpoint2()->fName); |
- |
- GrGLSLVertToFrag delta(kVec2f_GrSLType); |
- varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", |
- delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(), |
- ep1.vsOut()); |
- |
- GrGLSLVertToFrag windings(kInt_GrSLType); |
- varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision); |
- vsBuilder->codeAppendf("%s = %s;", |
- windings.vsOut(), qe.inWindings()->fName); |
- |
- // Setup position |
- this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName); |
- |
- // emit transforms |
- this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, |
- qe.inPosition()->fName, qe.localMatrix(), args.fTransformsIn, |
- args.fTransformsOut); |
- |
- GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; |
- SkAssertResult(fsBuilder->enableFeature( |
- GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); |
- SkAssertResult(fsBuilder->enableFeature( |
- GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); |
- static const int QUAD_ARGS = 2; |
- GrGLSLShaderVar inQuadArgs[QUAD_ARGS] = { |
- GrGLSLShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision), |
- GrGLSLShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision) |
- }; |
- SkString inQuadName; |
- |
- const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {" |
- "return dot >= 0.0;" |
- "} else {" |
- "return false;" |
- "}"; |
- fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode, |
- &inQuadName); |
- fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); |
- // keep the derivative instructions outside the conditional |
- fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn()); |
- fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn()); |
- fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;"); |
- fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;"); |
- fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;", |
- uv.fsIn()); |
- fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);", |
- fsBuilder->fragmentPosition()); |
- fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;", |
- delta.fsIn(), ep1.fsIn()); |
- fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), |
- windings.fsIn()); |
- fsBuilder->codeAppend("uv += uvIncX;"); |
- fsBuilder->codeAppendf("d += %s.x;", delta.fsIn()); |
- fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), |
- windings.fsIn()); |
- fsBuilder->codeAppend("uv += uvIncY;"); |
- fsBuilder->codeAppendf("d += %s.y;", delta.fsIn()); |
- fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), |
- windings.fsIn()); |
- fsBuilder->codeAppend("uv -= uvIncX;"); |
- fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn()); |
- fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), |
- windings.fsIn()); |
- } |
- |
- static inline void GenKey(const GrGeometryProcessor& gp, |
- const GrGLSLCaps&, |
- GrProcessorKeyBuilder* b) { |
- const PLSQuadEdgeEffect& qee = gp.cast<PLSQuadEdgeEffect>(); |
- uint32_t key = 0; |
- key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0; |
- b->add32(key); |
- } |
- |
- virtual void setData(const GrGLSLProgramDataManager& pdman, |
- const GrPrimitiveProcessor& gp) override { |
- } |
- |
- void setTransformData(const GrPrimitiveProcessor& primProc, |
- const GrGLSLProgramDataManager& pdman, |
- int index, |
- const SkTArray<const GrCoordTransform*, true>& transforms) override { |
- this->setTransformDataHelper<PLSQuadEdgeEffect>(primProc, pdman, index, transforms); |
- } |
- |
- private: |
- typedef GrGLSLGeometryProcessor INHERITED; |
- }; |
- |
- virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, |
- GrProcessorKeyBuilder* b) const override { |
- GLSLProcessor::GenKey(*this, caps, b); |
- } |
- |
- virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { |
- return new GLSLProcessor(*this); |
- } |
- |
-private: |
- PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords) |
- : fLocalMatrix(localMatrix) |
- , fUsesLocalCoords(usesLocalCoords) { |
- this->initClassID<PLSQuadEdgeEffect>(); |
- fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInUV = &this->addVertexAttrib(Attribute("inUV", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInEndpoint1 = &this->addVertexAttrib(Attribute("inEndpoint1", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInEndpoint2 = &this->addVertexAttrib(Attribute("inEndpoint2", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType, |
- kLow_GrSLPrecision)); |
- this->setWillReadFragmentPosition(); |
- } |
- |
- const Attribute* fInPosition; |
- const Attribute* fInUV; |
- const Attribute* fInEndpoint1; |
- const Attribute* fInEndpoint2; |
- const Attribute* fInWindings; |
- SkMatrix fLocalMatrix; |
- bool fUsesLocalCoords; |
- |
- GR_DECLARE_GEOMETRY_PROCESSOR_TEST; |
- |
- typedef GrGeometryProcessor INHERITED; |
-}; |
- |
-class PLSFinishEffect : public GrGeometryProcessor { |
-public: |
- |
- static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix, |
- bool usesLocalCoords) { |
- return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords); |
- } |
- |
- virtual ~PLSFinishEffect() {} |
- |
- const char* name() const override { return "PLSFinish"; } |
- |
- const Attribute* inPosition() const { return fInPosition; } |
- GrColor color() const { return fColor; } |
- bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } |
- const SkMatrix& localMatrix() const { return fLocalMatrix; } |
- bool usesLocalCoords() const { return fUsesLocalCoords; } |
- |
- GrPixelLocalStorageState getPixelLocalStorageState() const override { |
- return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState; |
- } |
- |
- const char* getDestColorOverride() const override { |
- return GR_GL_PLS_DSTCOLOR_NAME; |
- } |
- |
- class GLSLProcessor : public GrGLSLGeometryProcessor { |
- public: |
- GLSLProcessor(const GrGeometryProcessor&) {} |
- |
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { |
- const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>(); |
- GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; |
- GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
- |
- fUseEvenOdd = uniformHandler->addUniform(GrGLUniformHandler::kFragment_Visibility, |
- kFloat_GrSLType, kLow_GrSLPrecision, |
- "useEvenOdd"); |
- const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd); |
- |
- varyingHandler->emitAttributes(fe); |
- this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName); |
- this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, |
- fe.inPosition()->fName, fe.localMatrix(), args.fTransformsIn, |
- args.fTransformsOut); |
- |
- GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; |
- SkAssertResult(fsBuilder->enableFeature( |
- GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); |
- fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); |
- fsBuilder->codeAppend("float coverage;"); |
- fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd); |
- fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;"); |
- fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;"); |
- fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;"); |
- fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;"); |
- fsBuilder->codeAppend("} else {"); |
- fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;"); |
- fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;"); |
- fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;"); |
- fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;"); |
- fsBuilder->codeAppend("}"); |
- if (!fe.colorIgnored()) { |
- this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor, |
- &fColorUniform); |
- } |
- fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage); |
- } |
- |
- static inline void GenKey(const GrGeometryProcessor& gp, |
- const GrGLSLCaps&, |
- GrProcessorKeyBuilder* b) { |
- const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>(); |
- uint32_t key = 0; |
- key |= fe.usesLocalCoords() && fe.localMatrix().hasPerspective() ? 0x1 : 0x0; |
- b->add32(key); |
- } |
- |
- virtual void setData(const GrGLSLProgramDataManager& pdman, |
- const GrPrimitiveProcessor& gp) override { |
- const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>(); |
- pdman.set1f(fUseEvenOdd, fe.fUseEvenOdd); |
- if (fe.color() != fColor && !fe.colorIgnored()) { |
- GrGLfloat c[4]; |
- GrColorToRGBAFloat(fe.color(), c); |
- pdman.set4fv(fColorUniform, 1, c); |
- fColor = fe.color(); |
- } |
- } |
- |
- void setTransformData(const GrPrimitiveProcessor& primProc, |
- const GrGLSLProgramDataManager& pdman, |
- int index, |
- const SkTArray<const GrCoordTransform*, true>& transforms) override { |
- this->setTransformDataHelper<PLSFinishEffect>(primProc, pdman, index, transforms); |
- } |
- |
- private: |
- GrColor fColor; |
- UniformHandle fColorUniform; |
- UniformHandle fUseEvenOdd; |
- |
- typedef GrGLSLGeometryProcessor INHERITED; |
- }; |
- |
- virtual void getGLSLProcessorKey(const GrGLSLCaps& caps, |
- GrProcessorKeyBuilder* b) const override { |
- GLSLProcessor::GenKey(*this, caps, b); |
- } |
- |
- virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override { |
- return new GLSLProcessor(*this); |
- } |
- |
-private: |
- PLSFinishEffect(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix, |
- bool usesLocalCoords) |
- : fColor(color) |
- , fUseEvenOdd(useEvenOdd) |
- , fLocalMatrix(localMatrix) |
- , fUsesLocalCoords(usesLocalCoords) { |
- this->initClassID<PLSFinishEffect>(); |
- fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, |
- kHigh_GrSLPrecision)); |
- } |
- |
- const Attribute* fInPosition; |
- GrColor fColor; |
- bool fUseEvenOdd; |
- SkMatrix fLocalMatrix; |
- bool fUsesLocalCoords; |
- |
- typedef GrGeometryProcessor INHERITED; |
-}; |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { |
- // We have support for even-odd rendering, but are having some troublesome |
- // seams. Disable in the presence of even-odd for now. |
- return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias && |
- args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() && |
- args.fPath->getFillType() == SkPath::FillType::kWinding_FillType; |
-} |
- |
-class PLSPathBatch : public GrVertexBatch { |
-public: |
- DEFINE_BATCH_CLASS_ID |
- struct Geometry { |
- GrColor fColor; |
- SkMatrix fViewMatrix; |
- SkPath fPath; |
- }; |
- |
- static GrDrawBatch* Create(const Geometry& geometry) { |
- return new PLSPathBatch(geometry); |
- } |
- |
- const char* name() const override { return "PLSBatch"; } |
- |
- void computePipelineOptimizations(GrInitInvariantOutput* color, |
- GrInitInvariantOutput* coverage, |
- GrBatchToXPOverrides* overrides) const override { |
- // When this is called on a batch, there is only one geometry bundle |
- color->setKnownFourComponents(fGeoData[0].fColor); |
- coverage->setUnknownSingleComponent(); |
- overrides->fUsePLSDstRead = true; |
- } |
- |
- void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
- // Handle any color overrides |
- if (!overrides.readsColor()) { |
- fGeoData[0].fColor = GrColor_ILLEGAL; |
- } |
- overrides.getOverrideColorIfSet(&fGeoData[0].fColor); |
- |
- // setup batch properties |
- fBatch.fColorIgnored = !overrides.readsColor(); |
- fBatch.fColor = fGeoData[0].fColor; |
- fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); |
- fBatch.fCoverageIgnored = !overrides.readsCoverage(); |
- fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage(); |
- } |
- |
- void onPrepareDraws(Target* target) const override { |
- int instanceCount = fGeoData.count(); |
- |
- SkMatrix invert; |
- if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { |
- SkDebugf("Could not invert viewmatrix\n"); |
- return; |
- } |
- |
- // Setup GrGeometryProcessors |
- SkAutoTUnref<GrPLSGeometryProcessor> triangleProcessor( |
- PLSAATriangleEffect::Create(invert, this->usesLocalCoords())); |
- SkAutoTUnref<GrPLSGeometryProcessor> quadProcessor( |
- PLSQuadEdgeEffect::Create(invert, this->usesLocalCoords())); |
- |
- GrResourceProvider* rp = target->resourceProvider(); |
- for (int i = 0; i < instanceCount; ++i) { |
- const Geometry& args = fGeoData[i]; |
- SkRect bounds = args.fPath.getBounds(); |
- args.fViewMatrix.mapRect(&bounds); |
- bounds.fLeft = SkScalarFloorToScalar(bounds.fLeft); |
- bounds.fTop = SkScalarFloorToScalar(bounds.fTop); |
- bounds.fRight = SkScalarCeilToScalar(bounds.fRight); |
- bounds.fBottom = SkScalarCeilToScalar(bounds.fBottom); |
- triangleProcessor->setBounds(bounds); |
- quadProcessor->setBounds(bounds); |
- |
- // We use the fact that SkPath::transform path does subdivision based on |
- // perspective. Otherwise, we apply the view matrix when copying to the |
- // segment representation. |
- const SkMatrix* viewMatrix = &args.fViewMatrix; |
- |
- // We avoid initializing the path unless we have to |
- const SkPath* pathPtr = &args.fPath; |
- SkTLazy<SkPath> tmpPath; |
- if (viewMatrix->hasPerspective()) { |
- SkPath* tmpPathPtr = tmpPath.init(*pathPtr); |
- tmpPathPtr->setIsVolatile(true); |
- tmpPathPtr->transform(*viewMatrix); |
- viewMatrix = &SkMatrix::I(); |
- pathPtr = tmpPathPtr; |
- } |
- |
- GrVertices grVertices; |
- |
- PLSVertices triVertices; |
- PLSVertices quadVertices; |
- if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp, bounds)) { |
- continue; |
- } |
- |
- if (triVertices.count()) { |
- const GrVertexBuffer* triVertexBuffer; |
- int firstTriVertex; |
- size_t triStride = triangleProcessor->getVertexStride(); |
- PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace( |
- triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex)); |
- if (!triVerts) { |
- SkDebugf("Could not allocate vertices\n"); |
- return; |
- } |
- for (int i = 0; i < triVertices.count(); ++i) { |
- triVerts[i] = triVertices[i]; |
- } |
- grVertices.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex, |
- triVertices.count()); |
- target->initDraw(triangleProcessor, this->pipeline()); |
- target->draw(grVertices); |
- } |
- |
- if (quadVertices.count()) { |
- const GrVertexBuffer* quadVertexBuffer; |
- int firstQuadVertex; |
- size_t quadStride = quadProcessor->getVertexStride(); |
- PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace( |
- quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex)); |
- if (!quadVerts) { |
- SkDebugf("Could not allocate vertices\n"); |
- return; |
- } |
- for (int i = 0; i < quadVertices.count(); ++i) { |
- quadVerts[i] = quadVertices[i]; |
- } |
- grVertices.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex, |
- quadVertices.count()); |
- target->initDraw(quadProcessor, this->pipeline()); |
- target->draw(grVertices); |
- } |
- |
- SkAutoTUnref<GrGeometryProcessor> finishProcessor( |
- PLSFinishEffect::Create(this->color(), |
- pathPtr->getFillType() == |
- SkPath::FillType::kEvenOdd_FillType, |
- invert, |
- this->usesLocalCoords())); |
- const GrVertexBuffer* rectVertexBuffer; |
- size_t finishStride = finishProcessor->getVertexStride(); |
- int firstRectVertex; |
- static const int kRectVertexCount = 6; |
- SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSpace( |
- finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex)); |
- if (!rectVerts) { |
- SkDebugf("Could not allocate vertices\n"); |
- return; |
- } |
- rectVerts[0] = { bounds.fLeft, bounds.fTop }; |
- rectVerts[1] = { bounds.fLeft, bounds.fBottom }; |
- rectVerts[2] = { bounds.fRight, bounds.fBottom }; |
- rectVerts[3] = { bounds.fLeft, bounds.fTop }; |
- rectVerts[4] = { bounds.fRight, bounds.fTop }; |
- rectVerts[5] = { bounds.fRight, bounds.fBottom }; |
- |
- grVertices.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex, |
- kRectVertexCount); |
- target->initDraw(finishProcessor, this->pipeline()); |
- target->draw(grVertices); |
- } |
- } |
- |
- SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
- |
-private: |
- PLSPathBatch(const Geometry& geometry) : INHERITED(ClassID()) { |
- fGeoData.push_back(geometry); |
- |
- // compute bounds |
- fBounds = geometry.fPath.getBounds(); |
- geometry.fViewMatrix.mapRect(&fBounds); |
- } |
- |
- bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
- return false; |
- } |
- |
- GrColor color() const { return fBatch.fColor; } |
- bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } |
- bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; } |
- const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } |
- bool coverageIgnored() const { return fBatch.fCoverageIgnored; } |
- |
- struct BatchTracker { |
- GrColor fColor; |
- bool fUsesLocalCoords; |
- bool fColorIgnored; |
- bool fCoverageIgnored; |
- bool fCanTweakAlphaForCoverage; |
- }; |
- |
- BatchTracker fBatch; |
- SkSTArray<1, Geometry, true> fGeoData; |
- |
- typedef GrVertexBatch INHERITED; |
-}; |
- |
-SkDEBUGCODE(bool inPLSDraw = false;) |
-bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) { |
- if (args.fPath->isEmpty()) { |
- return true; |
- } |
- SkASSERT(!inPLSDraw); |
- SkDEBUGCODE(inPLSDraw = true;) |
- PLSPathBatch::Geometry geometry; |
- geometry.fColor = args.fColor; |
- geometry.fViewMatrix = *args.fViewMatrix; |
- geometry.fPath = *args.fPath; |
- |
- SkAutoTUnref<GrDrawBatch> batch(PLSPathBatch::Create(geometry)); |
- args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
- |
- SkDEBUGCODE(inPLSDraw = false;) |
- return true; |
- |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////////////////////////// |
- |
-#ifdef GR_TEST_UTILS |
- |
-DRAW_BATCH_TEST_DEFINE(PLSPathBatch) { |
- PLSPathBatch::Geometry geometry; |
- geometry.fColor = GrRandomColor(random); |
- geometry.fViewMatrix = GrTest::TestMatrixInvertible(random); |
- geometry.fPath = GrTest::TestPathConvex(random); |
- |
- return PLSPathBatch::Create(geometry); |
-} |
- |
-#endif |