Home | History | Annotate | Download | only in batches
      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 
     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
     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. */
     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. */
    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 
    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 
    262     static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
    263                                           bool usesLocalCoords) {
    264         return new PLSAATriangleEffect(localMatrix, usesLocalCoords);
    265     }
    266 
    267     virtual ~PLSAATriangleEffect() {}
    268 
    269     const char* name() const override { return "PLSAATriangle"; }
    270 
    271     const Attribute* inPosition() const { return fInPosition; }
    272     const Attribute* inVertex1() const { return fInVertex1; }
    273     const Attribute* inVertex2() const { return fInVertex2; }
    274     const Attribute* inVertex3() const { return fInVertex3; }
    275     const Attribute* inWindings() const { return fInWindings; }
    276     const SkMatrix& localMatrix() const { return fLocalMatrix; }
    277     bool usesLocalCoords() const { return fUsesLocalCoords; }
    278 
    279     class GLSLProcessor : public GrGLSLGeometryProcessor {
    280     public:
    281         GLSLProcessor(const GrGeometryProcessor&) {}
    282 
    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 
    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 
    394         virtual void setData(const GrGLSLProgramDataManager& pdman,
    395                              const GrPrimitiveProcessor& gp) override {
    396         }
    397 
    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 
    409     virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
    410                                    GrProcessorKeyBuilder* b) const override {
    411         GLSLProcessor::GenKey(*this, caps, b);
    412     }
    413 
    414     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
    415         return new GLSLProcessor(*this);
    416     }
    417 
    418 private:
    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 
    464     static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
    465                                           bool usesLocalCoords) {
    466         return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords);
    467     }
    468 
    469     virtual ~PLSQuadEdgeEffect() {}
    470 
    471     const char* name() const override { return "PLSQuadEdge"; }
    472 
    473     const Attribute* inPosition() const { return fInPosition; }
    474     const Attribute* inUV() const { return fInUV; }
    475     const Attribute* inEndpoint1() const { return fInEndpoint1; }
    476     const Attribute* inEndpoint2() const { return fInEndpoint2; }
    477     const Attribute* inWindings() const { return fInWindings; }
    478     const SkMatrix& localMatrix() const { return fLocalMatrix; }
    479     bool usesLocalCoords() const { return fUsesLocalCoords; }
    480 
    481     class GLSLProcessor : public GrGLSLGeometryProcessor {
    482     public:
    483         GLSLProcessor(const GrGeometryProcessor&) {}
    484 
    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 
    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 
    583         virtual void setData(const GrGLSLProgramDataManager& pdman,
    584                              const GrPrimitiveProcessor& gp) override {
    585         }
    586 
    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 
    598     virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
    599                                    GrProcessorKeyBuilder* b) const override {
    600         GLSLProcessor::GenKey(*this, caps, b);
    601     }
    602 
    603     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
    604         return new GLSLProcessor(*this);
    605     }
    606 
    607 private:
    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 
    641     static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
    642                                        bool usesLocalCoords) {
    643         return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords);
    644     }
    645 
    646     virtual ~PLSFinishEffect() {}
    647 
    648     const char* name() const override { return "PLSFinish"; }
    649 
    650     const Attribute* inPosition() const { return fInPosition; }
    651     GrColor color() const { return fColor; }
    652     bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
    653     const SkMatrix& localMatrix() const { return fLocalMatrix; }
    654     bool usesLocalCoords() const { return fUsesLocalCoords; }
    655 
    656     GrPixelLocalStorageState getPixelLocalStorageState() const override {
    657         return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState;
    658     }
    659 
    660     const char* getDestColorOverride() const override {
    661         return GR_GL_PLS_DSTCOLOR_NAME;
    662     }
    663 
    664     class GLSLProcessor : public GrGLSLGeometryProcessor {
    665     public:
    666         GLSLProcessor(const GrGeometryProcessor&) {}
    667 
    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 
    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 
    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 
    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 
    745     virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
    746                                    GrProcessorKeyBuilder* b) const override {
    747         GLSLProcessor::GenKey(*this, caps, b);
    748     }
    749 
    750     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
    751         return new GLSLProcessor(*this);
    752     }
    753 
    754 private:
    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 
    777 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 
    794     static GrDrawBatch* Create(const Geometry& geometry) {
    795         return new PLSPathBatch(geometry);
    796     }
    797 
    798     const char* name() const override { return "PLSBatch"; }
    799 
    800     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 
    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 
    824     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 
    943     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
    944 
    945 private:
    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 
    954     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
    955         return false;
    956     }
    957 
    958     GrColor color() const { return fBatch.fColor; }
    959     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
    960     bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
    961     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
    962     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 
    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 
   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