• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrPLSPathRenderer.h"
9 
10 #include "SkChunkAlloc.h"
11 #include "SkGeometry.h"
12 #include "SkPathPriv.h"
13 #include "SkString.h"
14 #include "SkTSort.h"
15 #include "SkTraceEvent.h"
16 #include "GrBatchFlushState.h"
17 #include "GrBatchTest.h"
18 #include "GrCaps.h"
19 #include "GrContext.h"
20 #include "GrDefaultGeoProcFactory.h"
21 #include "GrPLSGeometryProcessor.h"
22 #include "GrInvariantOutput.h"
23 #include "GrPathUtils.h"
24 #include "GrProcessor.h"
25 #include "GrPipelineBuilder.h"
26 #include "GrStrokeInfo.h"
27 #include "GrTessellator.h"
28 #include "batches/GrVertexBatch.h"
29 #include "glsl/GrGLSLGeometryProcessor.h"
30 #include "gl/builders/GrGLProgramBuilder.h"
31 #include "glsl/GrGLSLPLSPathRendering.h"
32 
GrPLSPathRenderer()33 GrPLSPathRenderer::GrPLSPathRenderer() {
34 }
35 
36 struct PLSVertex {
37     SkPoint  fPos;
38     // for triangles, these are the three triangle vertices
39     // for quads, vert1 is the texture UV coords, and vert2 and vert3 are the line segment
40     // comprising the flat edge of the quad
41     SkPoint  fVert1;
42     SkPoint  fVert2;
43     SkPoint  fVert3;
44     int fWinding;
45 };
46 typedef SkTArray<PLSVertex, true> PLSVertices;
47 
48 typedef SkTArray<SkPoint, true> FinishVertices;
49 
50 static const float kCubicTolerance = 0.5f;
51 static const float kConicTolerance = 0.5f;
52 
53 static const float kBloatSize = 1.0f;
54 
55 static const float kBloatLimit = 640000.0f;
56 
57 #define kQuadNumVertices 5
add_quad(SkPoint pts[3],PLSVertices & vertices)58 static void add_quad(SkPoint pts[3], PLSVertices& vertices) {
59     SkPoint normal = SkPoint::Make(pts[0].fY - pts[2].fY,
60                                    pts[2].fX - pts[0].fX);
61     normal.setLength(kBloatSize);
62     SkScalar cross = (pts[1] - pts[0]).cross(pts[2] - pts[0]);
63     if (cross < 0) {
64         normal = -normal;
65     }
66     PLSVertex quad[kQuadNumVertices];
67     quad[0].fPos = pts[0] + normal;
68     quad[1].fPos = pts[0] - normal;
69     quad[2].fPos = pts[1] - normal;
70     quad[3].fPos = pts[2] - normal;
71     quad[4].fPos = pts[2] + normal;
72     for (int i = 0; i < kQuadNumVertices; i++) {
73         quad[i].fWinding = cross < 0 ? 1 : -1;
74         if (cross > 0.0) {
75             quad[i].fVert2 = pts[0];
76             quad[i].fVert3 = pts[2];
77         }
78         else {
79             quad[i].fVert2 = pts[2];
80             quad[i].fVert3 = pts[0];
81         }
82     }
83     GrPathUtils::QuadUVMatrix DevToUV(pts);
84     DevToUV.apply<kQuadNumVertices, sizeof(PLSVertex), sizeof(SkPoint)>(quad);
85     for (int i = 2; i < kQuadNumVertices; i++) {
86         vertices.push_back(quad[0]);
87         vertices.push_back(quad[i - 1]);
88         vertices.push_back(quad[i]);
89     }
90 }
91 
92 /* Used by bloat_tri; outsets a single point. */
outset(SkPoint * p1,SkPoint line1,SkPoint line2)93 static bool outset(SkPoint* p1, SkPoint line1, SkPoint line2) {
94     // rotate the two line vectors 90 degrees to form the normals, and compute
95     // the dot product of the normals
96     SkScalar dotProd = line1.fY * line2.fY + line1.fX * line2.fX;
97     SkScalar lengthSq = 1.0f / ((1.0f - dotProd) / 2.0f);
98     if (lengthSq > kBloatLimit) {
99         return false;
100     }
101     SkPoint bisector = line1 + line2;
102     bisector.setLength(SkScalarSqrt(lengthSq) * kBloatSize);
103     *p1 += bisector;
104     return true;
105 }
106 
107 /* Bloats a triangle so as to create a border kBloatSize pixels wide all around it. */
bloat_tri(SkPoint pts[3])108 static bool bloat_tri(SkPoint pts[3]) {
109     SkPoint line1 = pts[0] - pts[1];
110     line1.normalize();
111     SkPoint line2 = pts[0] - pts[2];
112     line2.normalize();
113     SkPoint line3 = pts[1] - pts[2];
114     line3.normalize();
115 
116     SkPoint result[3];
117     result[0] = pts[0];
118     if (!outset(&result[0], line1, line2)) {
119         return false;
120     }
121     result[1] = pts[1];
122     if (!outset(&result[1], -line1, line3)) {
123         return false;
124     }
125     result[2] = pts[2];
126     if (!outset(&result[2], -line3, -line2)) {
127         return false;
128     }
129     pts[0] = result[0];
130     pts[1] = result[1];
131     pts[2] = result[2];
132     return true;
133 }
134 
get_geometry(const SkPath & path,const SkMatrix & m,PLSVertices & triVertices,PLSVertices & quadVertices,GrResourceProvider * resourceProvider,SkRect bounds)135 static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices,
136                          PLSVertices& quadVertices, GrResourceProvider* resourceProvider,
137                          SkRect bounds) {
138     SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
139     SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, m, bounds);
140     int contourCnt;
141     int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol);
142     if (maxPts <= 0) {
143         return 0;
144     }
145     SkPath linesOnlyPath;
146     linesOnlyPath.setFillType(path.getFillType());
147     SkSTArray<15, SkPoint, true> quadPoints;
148     SkPath::Iter iter(path, true);
149     bool done = false;
150     while (!done) {
151         SkPoint pts[4];
152         SkPath::Verb verb = iter.next(pts);
153         switch (verb) {
154             case SkPath::kMove_Verb:
155                 SkASSERT(quadPoints.count() % 3 == 0);
156                 for (int i = 0; i < quadPoints.count(); i += 3) {
157                     add_quad(&quadPoints[i], quadVertices);
158                 }
159                 quadPoints.reset();
160                 m.mapPoints(&pts[0], 1);
161                 linesOnlyPath.moveTo(pts[0]);
162                 break;
163             case SkPath::kLine_Verb:
164                 m.mapPoints(&pts[1], 1);
165                 linesOnlyPath.lineTo(pts[1]);
166                 break;
167             case SkPath::kQuad_Verb:
168                 m.mapPoints(pts, 3);
169                 linesOnlyPath.lineTo(pts[2]);
170                 quadPoints.push_back(pts[0]);
171                 quadPoints.push_back(pts[1]);
172                 quadPoints.push_back(pts[2]);
173                 break;
174             case SkPath::kCubic_Verb: {
175                 m.mapPoints(pts, 4);
176                 SkSTArray<15, SkPoint, true> quads;
177                 GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, &quads);
178                 int count = quads.count();
179                 for (int q = 0; q < count; q += 3) {
180                     linesOnlyPath.lineTo(quads[q + 2]);
181                     quadPoints.push_back(quads[q]);
182                     quadPoints.push_back(quads[q + 1]);
183                     quadPoints.push_back(quads[q + 2]);
184                 }
185                 break;
186             }
187             case SkPath::kConic_Verb: {
188                 m.mapPoints(pts, 3);
189                 SkScalar weight = iter.conicWeight();
190                 SkAutoConicToQuads converter;
191                 const SkPoint* quads = converter.computeQuads(pts, weight, kConicTolerance);
192                 int count = converter.countQuads();
193                 for (int i = 0; i < count; ++i) {
194                     linesOnlyPath.lineTo(quads[2 * i + 2]);
195                     quadPoints.push_back(quads[2 * i]);
196                     quadPoints.push_back(quads[2 * i + 1]);
197                     quadPoints.push_back(quads[2 * i + 2]);
198                 }
199                 break;
200             }
201             case SkPath::kClose_Verb:
202                 linesOnlyPath.close();
203                 break;
204             case SkPath::kDone_Verb:
205                 done = true;
206                 break;
207             default: SkASSERT(false);
208         }
209     }
210     SkASSERT(quadPoints.count() % 3 == 0);
211     for (int i = 0; i < quadPoints.count(); i += 3) {
212         add_quad(&quadPoints[i], quadVertices);
213     }
214 
215     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
216     GrUniqueKey key;
217     GrUniqueKey::Builder builder(&key, kDomain, 2);
218     builder[0] = path.getGenerationID();
219     builder[1] = path.getFillType();
220     builder.finish();
221     GrTessellator::WindingVertex* windingVertices;
222     int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds, &windingVertices);
223     if (triVertexCount > 0) {
224         for (int i = 0; i < triVertexCount; i += 3) {
225             SkPoint p1 = windingVertices[i].fPos;
226             SkPoint p2 = windingVertices[i + 1].fPos;
227             SkPoint p3 = windingVertices[i + 2].fPos;
228             int winding = windingVertices[i].fWinding;
229             SkASSERT(windingVertices[i + 1].fWinding == winding);
230             SkASSERT(windingVertices[i + 2].fWinding == winding);
231             SkScalar cross = (p2 - p1).cross(p3 - p1);
232             SkPoint bloated[3] = { p1, p2, p3 };
233             if (cross < 0.0f) {
234                 SkTSwap(p1, p3);
235             }
236             if (bloat_tri(bloated)) {
237                 triVertices.push_back({ bloated[0], p1, p2, p3, winding });
238                 triVertices.push_back({ bloated[1], p1, p2, p3, winding });
239                 triVertices.push_back({ bloated[2], p1, p2, p3, winding });
240             }
241             else {
242                 SkScalar minX = SkTMin(p1.fX, SkTMin(p2.fX, p3.fX)) - 1.0f;
243                 SkScalar minY = SkTMin(p1.fY, SkTMin(p2.fY, p3.fY)) - 1.0f;
244                 SkScalar maxX = SkTMax(p1.fX, SkTMax(p2.fX, p3.fX)) + 1.0f;
245                 SkScalar maxY = SkTMax(p1.fY, SkTMax(p2.fY, p3.fY)) + 1.0f;
246                 triVertices.push_back({ { minX, minY }, p1, p2, p3, winding });
247                 triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding });
248                 triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding });
249                 triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding });
250                 triVertices.push_back({ { maxX, maxY }, p1, p2, p3, winding });
251                 triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding });
252             }
253         }
254         delete[] windingVertices;
255     }
256     return triVertexCount > 0 || quadVertices.count() > 0;
257 }
258 
259 class PLSAATriangleEffect : public GrPLSGeometryProcessor {
260 public:
261 
Create(const SkMatrix & localMatrix,bool usesLocalCoords)262     static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
263                                           bool usesLocalCoords) {
264         return new PLSAATriangleEffect(localMatrix, usesLocalCoords);
265     }
266 
~PLSAATriangleEffect()267     virtual ~PLSAATriangleEffect() {}
268 
name() const269     const char* name() const override { return "PLSAATriangle"; }
270 
inPosition() const271     const Attribute* inPosition() const { return fInPosition; }
inVertex1() const272     const Attribute* inVertex1() const { return fInVertex1; }
inVertex2() const273     const Attribute* inVertex2() const { return fInVertex2; }
inVertex3() const274     const Attribute* inVertex3() const { return fInVertex3; }
inWindings() const275     const Attribute* inWindings() const { return fInWindings; }
localMatrix() const276     const SkMatrix& localMatrix() const { return fLocalMatrix; }
usesLocalCoords() const277     bool usesLocalCoords() const { return fUsesLocalCoords; }
278 
279     class GLSLProcessor : public GrGLSLGeometryProcessor {
280     public:
GLSLProcessor(const GrGeometryProcessor &)281         GLSLProcessor(const GrGeometryProcessor&) {}
282 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)283         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
284             const PLSAATriangleEffect& te = args.fGP.cast<PLSAATriangleEffect>();
285             GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
286             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
287             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
288 
289             varyingHandler->emitAttributes(te);
290 
291             this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName);
292 
293             GrGLSLVertToFrag v1(kVec2f_GrSLType);
294             varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision);
295             vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
296                                    v1.vsOut(),
297                                    te.inVertex1()->fName,
298                                    te.inVertex1()->fName);
299 
300             GrGLSLVertToFrag v2(kVec2f_GrSLType);
301             varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision);
302             vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
303                                    v2.vsOut(),
304                                    te.inVertex2()->fName,
305                                    te.inVertex2()->fName);
306 
307             GrGLSLVertToFrag v3(kVec2f_GrSLType);
308             varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision);
309             vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);",
310                                    v3.vsOut(),
311                                    te.inVertex3()->fName,
312                                    te.inVertex3()->fName);
313 
314             GrGLSLVertToFrag delta1(kVec2f_GrSLType);
315             varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision);
316             vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
317                                    delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut());
318 
319             GrGLSLVertToFrag delta2(kVec2f_GrSLType);
320             varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision);
321             vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
322                                    delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut());
323 
324             GrGLSLVertToFrag delta3(kVec2f_GrSLType);
325             varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision);
326             vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
327                                    delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut());
328 
329             GrGLSLVertToFrag windings(kInt_GrSLType);
330             varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
331             vsBuilder->codeAppendf("%s = %s;",
332                                    windings.vsOut(), te.inWindings()->fName);
333 
334             // emit transforms
335             this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
336                                  te.inPosition()->fName, te.localMatrix(), args.fTransformsIn,
337                                  args.fTransformsOut);
338 
339             GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
340             SkAssertResult(fsBuilder->enableFeature(
341                            GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
342             SkAssertResult(fsBuilder->enableFeature(
343                     GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
344             fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
345             // Compute four subsamples, each shifted a quarter pixel along x and y from
346             // gl_FragCoord. The oriented box positioning of the subsamples is of course not
347             // optimal, but it greatly simplifies the math and this simplification is necessary for
348             // performance reasons.
349             fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
350                                    fsBuilder->fragmentPosition());
351             fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn());
352             fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn());
353             fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn());
354             // Check whether first sample is inside the triangle by computing three dot products. If
355             // all are < 0, we're inside. The first vector in each case is half of what it is
356             // "supposed" to be, because we re-use them later as adjustment factors for which half
357             // is the correct value, so we multiply the dots by two to compensate.
358             fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;",
359                                    v1.fsIn());
360             fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;",
361                                    v2.fsIn());
362             fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;",
363                                    v3.fsIn());
364             fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));");
365             fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
366             // for subsequent samples, we don't recalculate the entire dot product -- just adjust it
367             // to the value it would have if we did recompute it.
368             fsBuilder->codeAppend("d1 += delta1.x;");
369             fsBuilder->codeAppend("d2 += delta2.x;");
370             fsBuilder->codeAppend("d3 += delta3.x;");
371             fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
372             fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
373             fsBuilder->codeAppend("d1 += delta1.y;");
374             fsBuilder->codeAppend("d2 += delta2.y;");
375             fsBuilder->codeAppend("d3 += delta3.y;");
376             fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
377             fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
378             fsBuilder->codeAppend("d1 -= delta1.x;");
379             fsBuilder->codeAppend("d2 -= delta2.x;");
380             fsBuilder->codeAppend("d3 -= delta3.x;");
381             fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
382             fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
383         }
384 
GenKey(const GrGeometryProcessor & gp,const GrGLSLCaps &,GrProcessorKeyBuilder * b)385         static inline void GenKey(const GrGeometryProcessor& gp,
386                                   const GrGLSLCaps&,
387                                   GrProcessorKeyBuilder* b) {
388             const PLSAATriangleEffect& te = gp.cast<PLSAATriangleEffect>();
389             uint32_t key = 0;
390             key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0;
391             b->add32(key);
392         }
393 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)394         virtual void setData(const GrGLSLProgramDataManager& pdman,
395                              const GrPrimitiveProcessor& gp) override {
396         }
397 
setTransformData(const GrPrimitiveProcessor & primProc,const GrGLSLProgramDataManager & pdman,int index,const SkTArray<const GrCoordTransform *,true> & transforms)398         void setTransformData(const GrPrimitiveProcessor& primProc,
399                               const GrGLSLProgramDataManager& pdman,
400                               int index,
401                               const SkTArray<const GrCoordTransform*, true>& transforms) override {
402             this->setTransformDataHelper<PLSAATriangleEffect>(primProc, pdman, index, transforms);
403         }
404 
405     private:
406         typedef GrGLSLGeometryProcessor INHERITED;
407     };
408 
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const409     virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
410                                    GrProcessorKeyBuilder* b) const override {
411         GLSLProcessor::GenKey(*this, caps, b);
412     }
413 
createGLSLInstance(const GrGLSLCaps &) const414     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
415         return new GLSLProcessor(*this);
416     }
417 
418 private:
PLSAATriangleEffect(const SkMatrix & localMatrix,bool usesLocalCoords)419     PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
420         : fLocalMatrix(localMatrix)
421         , fUsesLocalCoords(usesLocalCoords) {
422         this->initClassID<PLSAATriangleEffect>();
423         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
424                                                        kHigh_GrSLPrecision));
425         fInVertex1 = &this->addVertexAttrib(Attribute("inVertex1", kVec2f_GrVertexAttribType,
426                                                       kHigh_GrSLPrecision));
427         fInVertex2 = &this->addVertexAttrib(Attribute("inVertex2", kVec2f_GrVertexAttribType,
428                                                       kHigh_GrSLPrecision));
429         fInVertex3 = &this->addVertexAttrib(Attribute("inVertex3", kVec2f_GrVertexAttribType,
430                                                       kHigh_GrSLPrecision));
431         fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType,
432                                                        kLow_GrSLPrecision));
433         this->setWillReadFragmentPosition();
434     }
435 
436     const Attribute* fInPosition;
437     const Attribute* fInVertex1;
438     const Attribute* fInVertex2;
439     const Attribute* fInVertex3;
440     const Attribute* fInWindings;
441     SkMatrix         fLocalMatrix;
442     bool             fUsesLocalCoords;
443 
444     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
445 
446     typedef GrGeometryProcessor INHERITED;
447 };
448 
449 ///////////////////////////////////////////////////////////////////////////////
450 
451 /*
452  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
453  * two components of the vertex attribute. Coverage is based on signed
454  * distance with negative being inside, positive outside. The edge is specified in
455  * window space (y-down). If either the third or fourth component of the interpolated
456  * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
457  * attempt to trim to a portion of the infinite quad.
458  * Requires shader derivative instruction support.
459  */
460 
461 class PLSQuadEdgeEffect : public GrPLSGeometryProcessor {
462 public:
463 
Create(const SkMatrix & localMatrix,bool usesLocalCoords)464     static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
465                                           bool usesLocalCoords) {
466         return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords);
467     }
468 
~PLSQuadEdgeEffect()469     virtual ~PLSQuadEdgeEffect() {}
470 
name() const471     const char* name() const override { return "PLSQuadEdge"; }
472 
inPosition() const473     const Attribute* inPosition() const { return fInPosition; }
inUV() const474     const Attribute* inUV() const { return fInUV; }
inEndpoint1() const475     const Attribute* inEndpoint1() const { return fInEndpoint1; }
inEndpoint2() const476     const Attribute* inEndpoint2() const { return fInEndpoint2; }
inWindings() const477     const Attribute* inWindings() const { return fInWindings; }
localMatrix() const478     const SkMatrix& localMatrix() const { return fLocalMatrix; }
usesLocalCoords() const479     bool usesLocalCoords() const { return fUsesLocalCoords; }
480 
481     class GLSLProcessor : public GrGLSLGeometryProcessor {
482     public:
GLSLProcessor(const GrGeometryProcessor &)483         GLSLProcessor(const GrGeometryProcessor&) {}
484 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)485         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
486             const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>();
487             GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
488             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
489             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
490 
491             // emit attributes
492             varyingHandler->emitAttributes(qe);
493 
494             GrGLSLVertToFrag uv(kVec2f_GrSLType);
495             varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
496             vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName);
497 
498             GrGLSLVertToFrag ep1(kVec2f_GrSLType);
499             varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision);
500             vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(),
501                                   qe.inEndpoint1()->fName, qe.inEndpoint1()->fName);
502 
503             GrGLSLVertToFrag ep2(kVec2f_GrSLType);
504             varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision);
505             vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(),
506                                   qe.inEndpoint2()->fName, qe.inEndpoint2()->fName);
507 
508             GrGLSLVertToFrag delta(kVec2f_GrSLType);
509             varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision);
510             vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;",
511                                    delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(),
512                                    ep1.vsOut());
513 
514             GrGLSLVertToFrag windings(kInt_GrSLType);
515             varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
516             vsBuilder->codeAppendf("%s = %s;",
517                                    windings.vsOut(), qe.inWindings()->fName);
518 
519             // Setup position
520             this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName);
521 
522             // emit transforms
523             this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
524                                  qe.inPosition()->fName, qe.localMatrix(), args.fTransformsIn,
525                                  args.fTransformsOut);
526 
527             GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
528             SkAssertResult(fsBuilder->enableFeature(
529                            GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
530             SkAssertResult(fsBuilder->enableFeature(
531                     GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
532             static const int QUAD_ARGS = 2;
533             GrGLSLShaderVar inQuadArgs[QUAD_ARGS] = {
534                 GrGLSLShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision),
535                 GrGLSLShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision)
536             };
537             SkString inQuadName;
538 
539             const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {"
540                                      "return dot >= 0.0;"
541                                      "} else {"
542                                      "return false;"
543                                      "}";
544             fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode,
545                                     &inQuadName);
546             fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
547             // keep the derivative instructions outside the conditional
548             fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn());
549             fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn());
550             fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;");
551             fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;");
552             fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;",
553                                    uv.fsIn());
554             fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
555                                    fsBuilder->fragmentPosition());
556             fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;",
557                                    delta.fsIn(), ep1.fsIn());
558             fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
559                                    windings.fsIn());
560             fsBuilder->codeAppend("uv += uvIncX;");
561             fsBuilder->codeAppendf("d += %s.x;", delta.fsIn());
562             fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
563                                    windings.fsIn());
564             fsBuilder->codeAppend("uv += uvIncY;");
565             fsBuilder->codeAppendf("d += %s.y;", delta.fsIn());
566             fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
567                                    windings.fsIn());
568             fsBuilder->codeAppend("uv -= uvIncX;");
569             fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn());
570             fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(),
571                                    windings.fsIn());
572         }
573 
GenKey(const GrGeometryProcessor & gp,const GrGLSLCaps &,GrProcessorKeyBuilder * b)574         static inline void GenKey(const GrGeometryProcessor& gp,
575                                   const GrGLSLCaps&,
576                                   GrProcessorKeyBuilder* b) {
577             const PLSQuadEdgeEffect& qee = gp.cast<PLSQuadEdgeEffect>();
578             uint32_t key = 0;
579             key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
580             b->add32(key);
581         }
582 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)583         virtual void setData(const GrGLSLProgramDataManager& pdman,
584                              const GrPrimitiveProcessor& gp) override {
585         }
586 
setTransformData(const GrPrimitiveProcessor & primProc,const GrGLSLProgramDataManager & pdman,int index,const SkTArray<const GrCoordTransform *,true> & transforms)587         void setTransformData(const GrPrimitiveProcessor& primProc,
588                               const GrGLSLProgramDataManager& pdman,
589                               int index,
590                               const SkTArray<const GrCoordTransform*, true>& transforms) override {
591             this->setTransformDataHelper<PLSQuadEdgeEffect>(primProc, pdman, index, transforms);
592         }
593 
594     private:
595         typedef GrGLSLGeometryProcessor INHERITED;
596     };
597 
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const598     virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
599                                    GrProcessorKeyBuilder* b) const override {
600         GLSLProcessor::GenKey(*this, caps, b);
601     }
602 
createGLSLInstance(const GrGLSLCaps &) const603     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
604         return new GLSLProcessor(*this);
605     }
606 
607 private:
PLSQuadEdgeEffect(const SkMatrix & localMatrix,bool usesLocalCoords)608     PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
609         : fLocalMatrix(localMatrix)
610         , fUsesLocalCoords(usesLocalCoords) {
611         this->initClassID<PLSQuadEdgeEffect>();
612         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
613                                                        kHigh_GrSLPrecision));
614         fInUV = &this->addVertexAttrib(Attribute("inUV", kVec2f_GrVertexAttribType,
615                                                  kHigh_GrSLPrecision));
616         fInEndpoint1 = &this->addVertexAttrib(Attribute("inEndpoint1", kVec2f_GrVertexAttribType,
617                                                         kHigh_GrSLPrecision));
618         fInEndpoint2 = &this->addVertexAttrib(Attribute("inEndpoint2", kVec2f_GrVertexAttribType,
619                                                         kHigh_GrSLPrecision));
620         fInWindings  = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType,
621                                                         kLow_GrSLPrecision));
622         this->setWillReadFragmentPosition();
623     }
624 
625     const Attribute* fInPosition;
626     const Attribute* fInUV;
627     const Attribute* fInEndpoint1;
628     const Attribute* fInEndpoint2;
629     const Attribute* fInWindings;
630     SkMatrix         fLocalMatrix;
631     bool             fUsesLocalCoords;
632 
633     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
634 
635     typedef GrGeometryProcessor INHERITED;
636 };
637 
638 class PLSFinishEffect : public GrGeometryProcessor {
639 public:
640 
Create(GrColor color,bool useEvenOdd,const SkMatrix & localMatrix,bool usesLocalCoords)641     static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
642                                        bool usesLocalCoords) {
643         return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords);
644     }
645 
~PLSFinishEffect()646     virtual ~PLSFinishEffect() {}
647 
name() const648     const char* name() const override { return "PLSFinish"; }
649 
inPosition() const650     const Attribute* inPosition() const { return fInPosition; }
color() const651     GrColor color() const { return fColor; }
colorIgnored() const652     bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
localMatrix() const653     const SkMatrix& localMatrix() const { return fLocalMatrix; }
usesLocalCoords() const654     bool usesLocalCoords() const { return fUsesLocalCoords; }
655 
getPixelLocalStorageState() const656     GrPixelLocalStorageState getPixelLocalStorageState() const override {
657         return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState;
658     }
659 
getDestColorOverride() const660     const char* getDestColorOverride() const override {
661         return GR_GL_PLS_DSTCOLOR_NAME;
662     }
663 
664     class GLSLProcessor : public GrGLSLGeometryProcessor {
665     public:
GLSLProcessor(const GrGeometryProcessor &)666         GLSLProcessor(const GrGeometryProcessor&) {}
667 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)668         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
669             const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>();
670             GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
671             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
672             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
673 
674             fUseEvenOdd = uniformHandler->addUniform(kFragment_GrShaderFlag,
675                                                     kFloat_GrSLType, kLow_GrSLPrecision,
676                                                     "useEvenOdd");
677             const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd);
678 
679             varyingHandler->emitAttributes(fe);
680             this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName);
681             this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
682                                  fe.inPosition()->fName, fe.localMatrix(), args.fTransformsIn,
683                                  args.fTransformsOut);
684 
685             GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
686             SkAssertResult(fsBuilder->enableFeature(
687                            GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
688             fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
689             fsBuilder->codeAppend("float coverage;");
690             fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd);
691             fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;");
692             fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;");
693             fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;");
694             fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;");
695             fsBuilder->codeAppend("} else {");
696             fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;");
697             fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;");
698             fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;");
699             fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;");
700             fsBuilder->codeAppend("}");
701             if (!fe.colorIgnored()) {
702                 this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor,
703                                         &fColorUniform);
704             }
705             fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage);
706             fsBuilder->codeAppendf("%s = vec4(1.0, 0.0, 1.0, 1.0);", args.fOutputColor);
707         }
708 
GenKey(const GrGeometryProcessor & gp,const GrGLSLCaps &,GrProcessorKeyBuilder * b)709         static inline void GenKey(const GrGeometryProcessor& gp,
710                                   const GrGLSLCaps&,
711                                   GrProcessorKeyBuilder* b) {
712             const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>();
713             uint32_t key = 0;
714             key |= fe.usesLocalCoords() && fe.localMatrix().hasPerspective() ? 0x1 : 0x0;
715             b->add32(key);
716         }
717 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)718         virtual void setData(const GrGLSLProgramDataManager& pdman,
719                              const GrPrimitiveProcessor& gp) override {
720             const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>();
721             pdman.set1f(fUseEvenOdd, fe.fUseEvenOdd);
722             if (fe.color() != fColor && !fe.colorIgnored()) {
723                 GrGLfloat c[4];
724                 GrColorToRGBAFloat(fe.color(), c);
725                 pdman.set4fv(fColorUniform, 1, c);
726                 fColor = fe.color();
727             }
728         }
729 
setTransformData(const GrPrimitiveProcessor & primProc,const GrGLSLProgramDataManager & pdman,int index,const SkTArray<const GrCoordTransform *,true> & transforms)730         void setTransformData(const GrPrimitiveProcessor& primProc,
731                               const GrGLSLProgramDataManager& pdman,
732                               int index,
733                               const SkTArray<const GrCoordTransform*, true>& transforms) override {
734             this->setTransformDataHelper<PLSFinishEffect>(primProc, pdman, index, transforms);
735         }
736 
737     private:
738         GrColor fColor;
739         UniformHandle fColorUniform;
740         UniformHandle fUseEvenOdd;
741 
742         typedef GrGLSLGeometryProcessor INHERITED;
743     };
744 
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const745     virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
746                                    GrProcessorKeyBuilder* b) const override {
747         GLSLProcessor::GenKey(*this, caps, b);
748     }
749 
createGLSLInstance(const GrGLSLCaps &) const750     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
751         return new GLSLProcessor(*this);
752     }
753 
754 private:
PLSFinishEffect(GrColor color,bool useEvenOdd,const SkMatrix & localMatrix,bool usesLocalCoords)755     PLSFinishEffect(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
756                     bool usesLocalCoords)
757         : fColor(color)
758         , fUseEvenOdd(useEvenOdd)
759         , fLocalMatrix(localMatrix)
760         , fUsesLocalCoords(usesLocalCoords) {
761         this->initClassID<PLSFinishEffect>();
762         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
763                                                        kHigh_GrSLPrecision));
764     }
765 
766     const Attribute* fInPosition;
767     GrColor          fColor;
768     bool             fUseEvenOdd;
769     SkMatrix         fLocalMatrix;
770     bool             fUsesLocalCoords;
771 
772     typedef GrGeometryProcessor INHERITED;
773 };
774 
775 ///////////////////////////////////////////////////////////////////////////////
776 
onCanDrawPath(const CanDrawPathArgs & args) const777 bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
778     // We have support for even-odd rendering, but are having some troublesome
779     // seams. Disable in the presence of even-odd for now.
780     return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
781             args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
782             args.fPath->getFillType() == SkPath::FillType::kWinding_FillType;
783 }
784 
785 class PLSPathBatch : public GrVertexBatch {
786 public:
787     DEFINE_BATCH_CLASS_ID
788     struct Geometry {
789         GrColor fColor;
790         SkMatrix fViewMatrix;
791         SkPath fPath;
792     };
793 
Create(const Geometry & geometry)794     static GrDrawBatch* Create(const Geometry& geometry) {
795         return new PLSPathBatch(geometry);
796     }
797 
name() const798     const char* name() const override { return "PLSBatch"; }
799 
computePipelineOptimizations(GrInitInvariantOutput * color,GrInitInvariantOutput * coverage,GrBatchToXPOverrides * overrides) const800     void computePipelineOptimizations(GrInitInvariantOutput* color,
801                                       GrInitInvariantOutput* coverage,
802                                       GrBatchToXPOverrides* overrides) const override {
803         // When this is called on a batch, there is only one geometry bundle
804         color->setKnownFourComponents(fGeoData[0].fColor);
805         coverage->setUnknownSingleComponent();
806         overrides->fUsePLSDstRead = true;
807     }
808 
initBatchTracker(const GrXPOverridesForBatch & overrides)809     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
810         // Handle any color overrides
811         if (!overrides.readsColor()) {
812             fGeoData[0].fColor = GrColor_ILLEGAL;
813         }
814         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
815 
816         // setup batch properties
817         fBatch.fColorIgnored = !overrides.readsColor();
818         fBatch.fColor = fGeoData[0].fColor;
819         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
820         fBatch.fCoverageIgnored = !overrides.readsCoverage();
821         fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
822     }
823 
onPrepareDraws(Target * target) const824     void onPrepareDraws(Target* target) const override {
825         int instanceCount = fGeoData.count();
826 
827         SkMatrix invert;
828         if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
829             SkDebugf("Could not invert viewmatrix\n");
830             return;
831         }
832 
833         // Setup GrGeometryProcessors
834         SkAutoTUnref<GrPLSGeometryProcessor> triangleProcessor(
835                 PLSAATriangleEffect::Create(invert, this->usesLocalCoords()));
836         SkAutoTUnref<GrPLSGeometryProcessor> quadProcessor(
837                 PLSQuadEdgeEffect::Create(invert, this->usesLocalCoords()));
838 
839         GrResourceProvider* rp = target->resourceProvider();
840         for (int i = 0; i < instanceCount; ++i) {
841             const Geometry& args = fGeoData[i];
842             SkRect bounds = args.fPath.getBounds();
843             args.fViewMatrix.mapRect(&bounds);
844             bounds.fLeft = SkScalarFloorToScalar(bounds.fLeft);
845             bounds.fTop = SkScalarFloorToScalar(bounds.fTop);
846             bounds.fRight = SkScalarCeilToScalar(bounds.fRight);
847             bounds.fBottom = SkScalarCeilToScalar(bounds.fBottom);
848             triangleProcessor->setBounds(bounds);
849             quadProcessor->setBounds(bounds);
850 
851             // We use the fact that SkPath::transform path does subdivision based on
852             // perspective. Otherwise, we apply the view matrix when copying to the
853             // segment representation.
854             const SkMatrix* viewMatrix = &args.fViewMatrix;
855 
856             // We avoid initializing the path unless we have to
857             const SkPath* pathPtr = &args.fPath;
858             SkTLazy<SkPath> tmpPath;
859             if (viewMatrix->hasPerspective()) {
860                 SkPath* tmpPathPtr = tmpPath.init(*pathPtr);
861                 tmpPathPtr->setIsVolatile(true);
862                 tmpPathPtr->transform(*viewMatrix);
863                 viewMatrix = &SkMatrix::I();
864                 pathPtr = tmpPathPtr;
865             }
866 
867             GrVertices grVertices;
868 
869             PLSVertices triVertices;
870             PLSVertices quadVertices;
871             if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp, bounds)) {
872                 continue;
873             }
874 
875             if (triVertices.count()) {
876                 const GrVertexBuffer* triVertexBuffer;
877                 int firstTriVertex;
878                 size_t triStride = triangleProcessor->getVertexStride();
879                 PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace(
880                         triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex));
881                 if (!triVerts) {
882                     SkDebugf("Could not allocate vertices\n");
883                     return;
884                 }
885                 for (int i = 0; i < triVertices.count(); ++i) {
886                     triVerts[i] = triVertices[i];
887                 }
888                 grVertices.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex,
889                                 triVertices.count());
890                 target->initDraw(triangleProcessor, this->pipeline());
891                 target->draw(grVertices);
892             }
893 
894             if (quadVertices.count()) {
895                 const GrVertexBuffer* quadVertexBuffer;
896                 int firstQuadVertex;
897                 size_t quadStride = quadProcessor->getVertexStride();
898                 PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace(
899                         quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex));
900                 if (!quadVerts) {
901                     SkDebugf("Could not allocate vertices\n");
902                     return;
903                 }
904                 for (int i = 0; i < quadVertices.count(); ++i) {
905                     quadVerts[i] = quadVertices[i];
906                 }
907                 grVertices.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex,
908                                 quadVertices.count());
909                 target->initDraw(quadProcessor, this->pipeline());
910                 target->draw(grVertices);
911             }
912 
913             SkAutoTUnref<GrGeometryProcessor> finishProcessor(
914                     PLSFinishEffect::Create(this->color(),
915                                             pathPtr->getFillType() ==
916                                                                 SkPath::FillType::kEvenOdd_FillType,
917                                             invert,
918                                             this->usesLocalCoords()));
919             const GrVertexBuffer* rectVertexBuffer;
920             size_t finishStride = finishProcessor->getVertexStride();
921             int firstRectVertex;
922             static const int kRectVertexCount = 6;
923             SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSpace(
924                     finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex));
925             if (!rectVerts) {
926                 SkDebugf("Could not allocate vertices\n");
927                 return;
928             }
929             rectVerts[0] = { bounds.fLeft, bounds.fTop };
930             rectVerts[1] = { bounds.fLeft, bounds.fBottom };
931             rectVerts[2] = { bounds.fRight, bounds.fBottom };
932             rectVerts[3] = { bounds.fLeft, bounds.fTop };
933             rectVerts[4] = { bounds.fRight, bounds.fTop };
934             rectVerts[5] = { bounds.fRight, bounds.fBottom };
935 
936             grVertices.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex,
937                             kRectVertexCount);
938             target->initDraw(finishProcessor, this->pipeline());
939             target->draw(grVertices);
940         }
941     }
942 
geoData()943     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
944 
945 private:
PLSPathBatch(const Geometry & geometry)946     PLSPathBatch(const Geometry& geometry) : INHERITED(ClassID()) {
947         fGeoData.push_back(geometry);
948 
949         // compute bounds
950         fBounds = geometry.fPath.getBounds();
951         geometry.fViewMatrix.mapRect(&fBounds);
952     }
953 
onCombineIfPossible(GrBatch * t,const GrCaps & caps)954     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
955         return false;
956     }
957 
color() const958     GrColor color() const { return fBatch.fColor; }
usesLocalCoords() const959     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
canTweakAlphaForCoverage() const960     bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
viewMatrix() const961     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
coverageIgnored() const962     bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
963 
964     struct BatchTracker {
965         GrColor fColor;
966         bool fUsesLocalCoords;
967         bool fColorIgnored;
968         bool fCoverageIgnored;
969         bool fCanTweakAlphaForCoverage;
970     };
971 
972     BatchTracker fBatch;
973     SkSTArray<1, Geometry, true> fGeoData;
974 
975     typedef GrVertexBatch INHERITED;
976 };
977 
SkDEBUGCODE(bool inPLSDraw=false;)978 SkDEBUGCODE(bool inPLSDraw = false;)
979 bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) {
980     if (args.fPath->isEmpty()) {
981         return true;
982     }
983     SkASSERT(!inPLSDraw);
984     SkDEBUGCODE(inPLSDraw = true;)
985     PLSPathBatch::Geometry geometry;
986     geometry.fColor = args.fColor;
987     geometry.fViewMatrix = *args.fViewMatrix;
988     geometry.fPath = *args.fPath;
989 
990     SkAutoTUnref<GrDrawBatch> batch(PLSPathBatch::Create(geometry));
991     args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
992 
993     SkDEBUGCODE(inPLSDraw = false;)
994     return true;
995 
996 }
997 
998 ///////////////////////////////////////////////////////////////////////////////////////////////////
999 
1000 #ifdef GR_TEST_UTILS
1001 
DRAW_BATCH_TEST_DEFINE(PLSPathBatch)1002 DRAW_BATCH_TEST_DEFINE(PLSPathBatch) {
1003     PLSPathBatch::Geometry geometry;
1004     geometry.fColor = GrRandomColor(random);
1005     geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
1006     geometry.fPath = GrTest::TestPathConvex(random);
1007 
1008     return PLSPathBatch::Create(geometry);
1009 }
1010 
1011 #endif
1012