Home | History | Annotate | Download | only in ops
      1 /*
      2  * Copyright 2016 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 "GrMSAAPathRenderer.h"
      9 #include "GrAuditTrail.h"
     10 #include "GrClip.h"
     11 #include "GrDefaultGeoProcFactory.h"
     12 #include "GrFixedClip.h"
     13 #include "GrMesh.h"
     14 #include "GrOpFlushState.h"
     15 #include "GrPathStencilSettings.h"
     16 #include "GrPathUtils.h"
     17 #include "GrSimpleMeshDrawOpHelper.h"
     18 #include "SkAutoMalloc.h"
     19 #include "SkGeometry.h"
     20 #include "SkTraceEvent.h"
     21 #include "gl/GrGLVaryingHandler.h"
     22 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     23 #include "glsl/GrGLSLGeometryProcessor.h"
     24 #include "glsl/GrGLSLProgramDataManager.h"
     25 #include "glsl/GrGLSLUtil.h"
     26 #include "glsl/GrGLSLVertexGeoBuilder.h"
     27 #include "ops/GrMeshDrawOp.h"
     28 #include "ops/GrRectOpFactory.h"
     29 
     30 static const float kTolerance = 0.5f;
     31 
     32 ////////////////////////////////////////////////////////////////////////////////
     33 // Helpers for drawPath
     34 
     35 static inline bool single_pass_shape(const GrShape& shape) {
     36     if (!shape.inverseFilled()) {
     37         return shape.knownToBeConvex();
     38     }
     39     return false;
     40 }
     41 
     42 GrPathRenderer::StencilSupport GrMSAAPathRenderer::onGetStencilSupport(const GrShape& shape) const {
     43     if (single_pass_shape(shape)) {
     44         return GrPathRenderer::kNoRestriction_StencilSupport;
     45     } else {
     46         return GrPathRenderer::kStencilOnly_StencilSupport;
     47     }
     48 }
     49 
     50 struct MSAALineVertices {
     51     struct Vertex {
     52         SkPoint fPosition;
     53         SkColor fColor;
     54     };
     55     Vertex* vertices;
     56     Vertex* nextVertex;
     57 #ifdef SK_DEBUG
     58     Vertex* verticesEnd;
     59 #endif
     60     uint16_t* indices;
     61     uint16_t* nextIndex;
     62 };
     63 
     64 struct MSAAQuadVertices {
     65     struct Vertex {
     66         SkPoint fPosition;
     67         SkPoint fUV;
     68         SkColor fColor;
     69     };
     70     Vertex* vertices;
     71     Vertex* nextVertex;
     72 #ifdef SK_DEBUG
     73     Vertex* verticesEnd;
     74 #endif
     75     uint16_t* indices;
     76     uint16_t* nextIndex;
     77 };
     78 
     79 static inline void append_contour_edge_indices(uint16_t fanCenterIdx,
     80                                                uint16_t edgeV0Idx,
     81                                                MSAALineVertices& lines) {
     82     *(lines.nextIndex++) = fanCenterIdx;
     83     *(lines.nextIndex++) = edgeV0Idx;
     84     *(lines.nextIndex++) = edgeV0Idx + 1;
     85 }
     86 
     87 static inline void add_quad(MSAALineVertices& lines, MSAAQuadVertices& quads, const SkPoint pts[],
     88                             SkColor color, bool indexed, uint16_t subpathLineIdxStart) {
     89     SkASSERT(lines.nextVertex < lines.verticesEnd);
     90     *lines.nextVertex = { pts[2], color };
     91     if (indexed) {
     92         int prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
     93         if (prevIdx > subpathLineIdxStart) {
     94             append_contour_edge_indices(subpathLineIdxStart, prevIdx, lines);
     95         }
     96     }
     97     lines.nextVertex++;
     98 
     99     SkASSERT(quads.nextVertex + 2 < quads.verticesEnd);
    100     // the texture coordinates are drawn from the Loop-Blinn rendering algorithm
    101     *(quads.nextVertex++) = { pts[0], SkPoint::Make(0.0, 0.0), color };
    102     *(quads.nextVertex++) = { pts[1], SkPoint::Make(0.5, 0.0), color };
    103     *(quads.nextVertex++) = { pts[2], SkPoint::Make(1.0, 1.0), color };
    104     if (indexed) {
    105         uint16_t offset = (uint16_t) (quads.nextVertex - quads.vertices) - 3;
    106         *(quads.nextIndex++) = offset++;
    107         *(quads.nextIndex++) = offset++;
    108         *(quads.nextIndex++) = offset++;
    109     }
    110 }
    111 
    112 namespace {
    113 
    114 class MSAAQuadProcessor : public GrGeometryProcessor {
    115 public:
    116     static GrGeometryProcessor* Create(const SkMatrix& viewMatrix) {
    117         return new MSAAQuadProcessor(viewMatrix);
    118     }
    119 
    120     ~MSAAQuadProcessor() override {}
    121 
    122     const char* name() const override { return "MSAAQuadProcessor"; }
    123 
    124     const Attribute* inPosition() const { return fInPosition; }
    125     const Attribute* inUV() const { return fInUV; }
    126     const Attribute* inColor() const { return fInColor; }
    127     const SkMatrix& viewMatrix() const { return fViewMatrix; }
    128 
    129     class GLSLProcessor : public GrGLSLGeometryProcessor {
    130     public:
    131         GLSLProcessor(const GrGeometryProcessor& qpr) {}
    132 
    133         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
    134             const MSAAQuadProcessor& qp = args.fGP.cast<MSAAQuadProcessor>();
    135             GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
    136             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
    137             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    138 
    139             // emit attributes
    140             varyingHandler->emitAttributes(qp);
    141             varyingHandler->addPassThroughAttribute(qp.inColor(), args.fOutputColor);
    142 
    143             GrGLSLVarying uv(kFloat2_GrSLType);
    144             varyingHandler->addVarying("uv", &uv);
    145             vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName);
    146 
    147             // Setup position
    148             this->writeOutputPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName,
    149                                       qp.viewMatrix(), &fViewMatrixUniform);
    150 
    151             // emit transforms
    152             this->emitTransforms(vsBuilder, varyingHandler, uniformHandler,
    153                                  qp.inPosition()->asShaderVar(), SkMatrix::I(),
    154                                  args.fFPCoordTransformHandler);
    155 
    156             GrGLSLFPFragmentBuilder* fsBuilder = args.fFragBuilder;
    157             fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(),
    158                                                                         uv.fsIn());
    159             fsBuilder->codeAppendf("%s = half4(1.0);", args.fOutputCoverage);
    160         }
    161 
    162         static inline void GenKey(const GrGeometryProcessor& gp,
    163                                   const GrShaderCaps&,
    164                                   GrProcessorKeyBuilder* b) {
    165             const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
    166             uint32_t key = 0;
    167             key |= qp.viewMatrix().hasPerspective() ? 0x1 : 0x0;
    168             key |= qp.viewMatrix().isIdentity() ? 0x2: 0x0;
    169             b->add32(key);
    170         }
    171 
    172         void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
    173                      FPCoordTransformIter&& transformIter) override {
    174             const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
    175             if (!qp.viewMatrix().isIdentity()) {
    176                 float viewMatrix[3 * 3];
    177                 GrGLSLGetMatrix<3>(viewMatrix, qp.viewMatrix());
    178                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
    179             }
    180             this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
    181         }
    182 
    183     private:
    184         typedef GrGLSLGeometryProcessor INHERITED;
    185 
    186         UniformHandle fViewMatrixUniform;
    187     };
    188 
    189     virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
    190                                    GrProcessorKeyBuilder* b) const override {
    191         GLSLProcessor::GenKey(*this, caps, b);
    192     }
    193 
    194     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
    195         return new GLSLProcessor(*this);
    196     }
    197 
    198 private:
    199     MSAAQuadProcessor(const SkMatrix& viewMatrix)
    200         : INHERITED(kMSAAQuadProcessor_ClassID)
    201         , fViewMatrix(viewMatrix) {
    202         fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
    203         fInUV = &this->addVertexAttrib("inUV", kFloat2_GrVertexAttribType);
    204         fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
    205         this->setSampleShading(1.0f);
    206     }
    207 
    208     const Attribute* fInPosition;
    209     const Attribute* fInUV;
    210     const Attribute* fInColor;
    211     SkMatrix         fViewMatrix;
    212 
    213     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
    214 
    215     typedef GrGeometryProcessor INHERITED;
    216 };
    217 
    218 class MSAAPathOp final : public GrMeshDrawOp {
    219 private:
    220     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
    221 
    222 public:
    223     DEFINE_OP_CLASS_ID
    224 
    225     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkPath& path, GrAAType aaType,
    226                                           const SkMatrix& viewMatrix, const SkRect& devBounds,
    227                                           const GrUserStencilSettings* stencilSettings) {
    228         int contourCount;
    229         int maxLineVertices;
    230         int maxQuadVertices;
    231         ComputeWorstCasePointCount(path, viewMatrix, &contourCount, &maxLineVertices,
    232                                    &maxQuadVertices);
    233         bool isIndexed = contourCount > 1;
    234         if (isIndexed &&
    235             (maxLineVertices > kMaxIndexedVertexCnt || maxQuadVertices > kMaxIndexedVertexCnt)) {
    236             return nullptr;
    237         }
    238 
    239         return Helper::FactoryHelper<MSAAPathOp>(std::move(paint), path, aaType, viewMatrix,
    240                                                  devBounds, maxLineVertices, maxQuadVertices,
    241                                                  isIndexed, stencilSettings);
    242     }
    243 
    244     const char* name() const override { return "MSAAPathOp"; }
    245 
    246     void visitProxies(const VisitProxyFunc& func) const override {
    247         fHelper.visitProxies(func);
    248     }
    249 
    250     SkString dumpInfo() const override {
    251         SkString string;
    252         string.appendf("Indexed: %d\n", fIsIndexed);
    253         for (const auto& path : fPaths) {
    254             string.appendf("Color: 0x%08x\n", path.fColor);
    255         }
    256         string += fHelper.dumpInfo();
    257         string += INHERITED::dumpInfo();
    258         return string;
    259     }
    260 
    261     MSAAPathOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkPath& path,
    262                GrAAType aaType, const SkMatrix& viewMatrix, const SkRect& devBounds,
    263                int maxLineVertices, int maxQuadVertices, bool isIndexed,
    264                const GrUserStencilSettings* stencilSettings)
    265             : INHERITED(ClassID())
    266             , fHelper(helperArgs, aaType, stencilSettings)
    267             , fViewMatrix(viewMatrix)
    268             , fMaxLineVertices(maxLineVertices)
    269             , fMaxQuadVertices(maxQuadVertices)
    270             , fIsIndexed(isIndexed) {
    271         fPaths.emplace_back(PathInfo{color, path});
    272         this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
    273     }
    274 
    275     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
    276 
    277     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
    278                                 GrPixelConfigIsClamped dstIsClamped) override {
    279         return fHelper.xpRequiresDstTexture(caps, clip, dstIsClamped,
    280                                             GrProcessorAnalysisCoverage::kNone,
    281                                             &fPaths.front().fColor);
    282     }
    283 
    284 private:
    285     static void ComputeWorstCasePointCount(const SkPath& path, const SkMatrix& m, int* subpaths,
    286                                            int* outLinePointCount, int* outQuadPointCount) {
    287         SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m, path.getBounds());
    288         int linePointCount = 0;
    289         int quadPointCount = 0;
    290         *subpaths = 1;
    291 
    292         bool first = true;
    293 
    294         SkPath::Iter iter(path, true);
    295         SkPath::Verb verb;
    296 
    297         SkPoint pts[4];
    298         while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
    299             switch (verb) {
    300                 case SkPath::kLine_Verb:
    301                     linePointCount += 1;
    302                     break;
    303                 case SkPath::kConic_Verb: {
    304                     SkScalar weight = iter.conicWeight();
    305                     SkAutoConicToQuads converter;
    306                     converter.computeQuads(pts, weight, tolerance);
    307                     int quadPts = converter.countQuads();
    308                     linePointCount += quadPts;
    309                     quadPointCount += 3 * quadPts;
    310                 }
    311                 case SkPath::kQuad_Verb:
    312                     linePointCount += 1;
    313                     quadPointCount += 3;
    314                     break;
    315                 case SkPath::kCubic_Verb: {
    316                     SkSTArray<15, SkPoint, true> quadPts;
    317                     GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
    318                     int count = quadPts.count();
    319                     linePointCount += count / 3;
    320                     quadPointCount += count;
    321                     break;
    322                 }
    323                 case SkPath::kMove_Verb:
    324                     linePointCount += 1;
    325                     if (!first) {
    326                         ++(*subpaths);
    327                     }
    328                     break;
    329                 default:
    330                     break;
    331             }
    332             first = false;
    333         }
    334         *outLinePointCount = linePointCount;
    335         *outQuadPointCount = quadPointCount;
    336     }
    337 
    338     void onPrepareDraws(Target* target) override {
    339         if (fMaxLineVertices == 0) {
    340             SkASSERT(fMaxQuadVertices == 0);
    341             return;
    342         }
    343 
    344         GrPrimitiveType primitiveType = fIsIndexed ? GrPrimitiveType::kTriangles
    345                                                    : GrPrimitiveType::kTriangleFan;
    346 
    347         // allocate vertex / index buffers
    348         const GrBuffer* lineVertexBuffer;
    349         int firstLineVertex;
    350         MSAALineVertices lines;
    351         int lineVertexStride = sizeof(MSAALineVertices::Vertex);
    352         lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride,
    353                                                                              fMaxLineVertices,
    354                                                                              &lineVertexBuffer,
    355                                                                              &firstLineVertex);
    356         if (!lines.vertices) {
    357             SkDebugf("Could not allocate vertices\n");
    358             return;
    359         }
    360         lines.nextVertex = lines.vertices;
    361         SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;)
    362 
    363         MSAAQuadVertices quads;
    364         int quadVertexStride = sizeof(MSAAQuadVertices::Vertex);
    365         SkAutoMalloc quadVertexPtr(fMaxQuadVertices * quadVertexStride);
    366         quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get();
    367         quads.nextVertex = quads.vertices;
    368         SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;)
    369 
    370         const GrBuffer* lineIndexBuffer = nullptr;
    371         int firstLineIndex = 0;
    372         if (fIsIndexed) {
    373             lines.indices =
    374                     target->makeIndexSpace(3 * fMaxLineVertices, &lineIndexBuffer, &firstLineIndex);
    375             if (!lines.indices) {
    376                 SkDebugf("Could not allocate indices\n");
    377                 return;
    378             }
    379             lines.nextIndex = lines.indices;
    380         } else {
    381             lines.indices = nullptr;
    382             lines.nextIndex = nullptr;
    383         }
    384 
    385         SkAutoFree quadIndexPtr;
    386         if (fIsIndexed) {
    387             quads.indices = (uint16_t*)sk_malloc_throw(3 * fMaxQuadVertices * sizeof(uint16_t));
    388             quadIndexPtr.reset(quads.indices);
    389             quads.nextIndex = quads.indices;
    390         } else {
    391             quads.indices = nullptr;
    392             quads.nextIndex = nullptr;
    393         }
    394         // fill buffers
    395         for (int i = 0; i < fPaths.count(); i++) {
    396             const PathInfo& pathInfo = fPaths[i];
    397             if (!this->createGeom(lines,
    398                                   quads,
    399                                   pathInfo.fPath,
    400                                   fViewMatrix,
    401                                   pathInfo.fColor,
    402                                   fIsIndexed)) {
    403                 return;
    404             }
    405         }
    406         int lineVertexOffset = (int) (lines.nextVertex - lines.vertices);
    407         int lineIndexOffset = (int) (lines.nextIndex - lines.indices);
    408         SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= 3 * fMaxLineVertices);
    409         int quadVertexOffset = (int) (quads.nextVertex - quads.vertices);
    410         int quadIndexOffset = (int) (quads.nextIndex - quads.indices);
    411         SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= 3 * fMaxQuadVertices);
    412 
    413         const GrPipeline* pipeline = fHelper.makePipeline(target);
    414 
    415         if (lineVertexOffset) {
    416             sk_sp<GrGeometryProcessor> lineGP;
    417             {
    418                 using namespace GrDefaultGeoProcFactory;
    419                 lineGP = GrDefaultGeoProcFactory::Make(Color(Color::kPremulGrColorAttribute_Type),
    420                                                        Coverage::kSolid_Type,
    421                                                        LocalCoords(LocalCoords::kUnused_Type),
    422                                                        fViewMatrix);
    423             }
    424             SkASSERT(lineVertexStride == lineGP->getVertexStride());
    425 
    426             GrMesh lineMeshes(primitiveType);
    427             if (!fIsIndexed) {
    428                 lineMeshes.setNonIndexedNonInstanced(lineVertexOffset);
    429             } else {
    430                 lineMeshes.setIndexed(lineIndexBuffer, lineIndexOffset, firstLineIndex,
    431                                       0, lineVertexOffset - 1);
    432             }
    433             lineMeshes.setVertexData(lineVertexBuffer, firstLineVertex);
    434 
    435             // We can get line vertices from path moveTos with no actual segments and thus no index
    436             // count. We assert that indexed draws contain a positive index count, so bail here in
    437             // that case.
    438             if (!fIsIndexed || lineIndexOffset) {
    439                 target->draw(lineGP.get(), pipeline, lineMeshes);
    440             }
    441         }
    442 
    443         if (quadVertexOffset) {
    444             sk_sp<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix));
    445             SkASSERT(quadVertexStride == quadGP->getVertexStride());
    446 
    447             const GrBuffer* quadVertexBuffer;
    448             int firstQuadVertex;
    449             MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*)
    450                     target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer,
    451                                             &firstQuadVertex);
    452             memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset);
    453             GrMesh quadMeshes(GrPrimitiveType::kTriangles);
    454             if (!fIsIndexed) {
    455                 quadMeshes.setNonIndexedNonInstanced(quadVertexOffset);
    456             } else {
    457                 const GrBuffer* quadIndexBuffer;
    458                 int firstQuadIndex;
    459                 uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset,
    460                                                                            &quadIndexBuffer,
    461                                                                            &firstQuadIndex);
    462                 memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset);
    463                 quadMeshes.setIndexed(quadIndexBuffer, quadIndexOffset, firstQuadIndex,
    464                                       0, quadVertexOffset - 1);
    465             }
    466             quadMeshes.setVertexData(quadVertexBuffer, firstQuadVertex);
    467             target->draw(quadGP.get(), pipeline, quadMeshes);
    468         }
    469     }
    470 
    471     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
    472         MSAAPathOp* that = t->cast<MSAAPathOp>();
    473         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
    474             return false;
    475         }
    476 
    477         if (this->bounds().intersects(that->bounds())) {
    478             return false;
    479         }
    480 
    481         if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
    482             return false;
    483         }
    484 
    485         // If we grow to include 2+ paths we will be indexed.
    486         if (((fMaxLineVertices + that->fMaxLineVertices) > kMaxIndexedVertexCnt) ||
    487             ((fMaxQuadVertices + that->fMaxQuadVertices) > kMaxIndexedVertexCnt)) {
    488             return false;
    489         }
    490 
    491         fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
    492         this->joinBounds(*that);
    493         fIsIndexed = true;
    494         fMaxLineVertices += that->fMaxLineVertices;
    495         fMaxQuadVertices += that->fMaxQuadVertices;
    496         return true;
    497     }
    498 
    499     bool createGeom(MSAALineVertices& lines,
    500                     MSAAQuadVertices& quads,
    501                     const SkPath& path,
    502                     const SkMatrix& m,
    503                     SkColor color,
    504                     bool isIndexed) const {
    505         {
    506             const SkScalar tolerance = GrPathUtils::scaleToleranceToSrc(kTolerance, m,
    507                                                                         path.getBounds());
    508             uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices);
    509 
    510             SkPoint pts[4];
    511 
    512             bool first = true;
    513             SkPath::Iter iter(path, true);
    514 
    515             bool done = false;
    516             while (!done) {
    517                 SkPath::Verb verb = iter.next(pts);
    518                 switch (verb) {
    519                     case SkPath::kMove_Verb:
    520                         if (!first) {
    521                             uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices);
    522                             subpathIdxStart = currIdx;
    523                         }
    524                         SkASSERT(lines.nextVertex < lines.verticesEnd);
    525                         *(lines.nextVertex++) = { pts[0], color };
    526                         break;
    527                     case SkPath::kLine_Verb:
    528                         if (isIndexed) {
    529                             uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
    530                             if (prevIdx > subpathIdxStart) {
    531                                 append_contour_edge_indices(subpathIdxStart, prevIdx, lines);
    532                             }
    533                         }
    534                         SkASSERT(lines.nextVertex < lines.verticesEnd);
    535                         *(lines.nextVertex++) = { pts[1], color };
    536                         break;
    537                     case SkPath::kConic_Verb: {
    538                         SkScalar weight = iter.conicWeight();
    539                         SkAutoConicToQuads converter;
    540                         const SkPoint* quadPts = converter.computeQuads(pts, weight, tolerance);
    541                         for (int i = 0; i < converter.countQuads(); ++i) {
    542                             add_quad(lines, quads, quadPts + i * 2, color, isIndexed,
    543                                      subpathIdxStart);
    544                         }
    545                         break;
    546                     }
    547                     case SkPath::kQuad_Verb: {
    548                         add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart);
    549                         break;
    550                     }
    551                     case SkPath::kCubic_Verb: {
    552                         SkSTArray<15, SkPoint, true> quadPts;
    553                         GrPathUtils::convertCubicToQuads(pts, tolerance, &quadPts);
    554                         int count = quadPts.count();
    555                         for (int i = 0; i < count; i += 3) {
    556                             add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart);
    557                         }
    558                         break;
    559                     }
    560                     case SkPath::kClose_Verb:
    561                         break;
    562                     case SkPath::kDone_Verb:
    563                         done = true;
    564                 }
    565                 first = false;
    566             }
    567         }
    568         return true;
    569     }
    570 
    571     // Lines and quads may render with an index buffer. However, we don't have any support for
    572     // overflowing the max index.
    573     static constexpr int kMaxIndexedVertexCnt = SK_MaxU16 / 3;
    574     struct PathInfo {
    575         GrColor  fColor;
    576         SkPath   fPath;
    577     };
    578 
    579     Helper fHelper;
    580     SkSTArray<1, PathInfo, true> fPaths;
    581     SkMatrix fViewMatrix;
    582     int fMaxLineVertices;
    583     int fMaxQuadVertices;
    584     bool fIsIndexed;
    585 
    586     typedef GrMeshDrawOp INHERITED;
    587 };
    588 
    589 }  // anonymous namespace
    590 
    591 bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
    592                                           GrPaint&& paint,
    593                                           GrAAType aaType,
    594                                           const GrUserStencilSettings& userStencilSettings,
    595                                           const GrClip& clip,
    596                                           const SkMatrix& viewMatrix,
    597                                           const GrShape& shape,
    598                                           bool stencilOnly) {
    599     SkASSERT(shape.style().isSimpleFill());
    600     SkPath path;
    601     shape.asPath(&path);
    602 
    603     const GrUserStencilSettings* passes[2] = {nullptr, nullptr};
    604     bool                         reverse = false;
    605 
    606     if (single_pass_shape(shape)) {
    607         if (stencilOnly) {
    608             passes[0] = &gDirectToStencil;
    609         } else {
    610             passes[0] = &userStencilSettings;
    611         }
    612     } else {
    613         switch (path.getFillType()) {
    614             case SkPath::kInverseEvenOdd_FillType:
    615                 reverse = true;
    616                 // fallthrough
    617             case SkPath::kEvenOdd_FillType:
    618                 passes[0] = &gEOStencilPass;
    619                 if (!stencilOnly) {
    620                     passes[1] = reverse ? &gInvEOColorPass : &gEOColorPass;
    621                 }
    622                 break;
    623 
    624             case SkPath::kInverseWinding_FillType:
    625                 reverse = true;
    626                 // fallthrough
    627             case SkPath::kWinding_FillType:
    628                 passes[0] = &gWindStencilPass;
    629                 if (!stencilOnly) {
    630                     passes[1] = reverse ? &gInvWindColorPass : &gWindColorPass;
    631                 }
    632                 break;
    633             default:
    634                 SkDEBUGFAIL("Unknown path fFill!");
    635                 return false;
    636         }
    637     }
    638 
    639     SkRect devBounds;
    640     GetPathDevBounds(path,
    641                      renderTargetContext->asRenderTargetProxy()->worstCaseWidth(),
    642                      renderTargetContext->asRenderTargetProxy()->worstCaseHeight(),
    643                      viewMatrix, &devBounds);
    644 
    645     SkASSERT(passes[0]);
    646     {  // First pass
    647         bool firstPassIsStencil = stencilOnly || passes[1];
    648         // If we have a cover pass then we ignore the paint in the first pass and apply it in the
    649         // second.
    650         std::unique_ptr<GrDrawOp> op;
    651         if (firstPassIsStencil) {
    652             GrPaint stencilPaint;
    653             stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
    654             op = MSAAPathOp::Make(std::move(stencilPaint), path, aaType, viewMatrix, devBounds,
    655                                   passes[0]);
    656         } else {
    657             op = MSAAPathOp::Make(std::move(paint), path, aaType, viewMatrix, devBounds, passes[0]);
    658         }
    659         if (!op) {
    660             return false;
    661         }
    662         renderTargetContext->addDrawOp(clip, std::move(op));
    663     }
    664 
    665     if (passes[1]) {
    666         SkRect bounds;
    667         SkMatrix localMatrix = SkMatrix::I();
    668         if (reverse) {
    669             // draw over the dev bounds (which will be the whole dst surface for inv fill).
    670             bounds = devBounds;
    671             SkMatrix vmi;
    672             // mapRect through persp matrix may not be correct
    673             if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
    674                 vmi.mapRect(&bounds);
    675             } else {
    676                 if (!viewMatrix.invert(&localMatrix)) {
    677                     return false;
    678                 }
    679             }
    680         } else {
    681             bounds = path.getBounds();
    682         }
    683         const SkMatrix& viewM =
    684                 (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix;
    685         renderTargetContext->addDrawOp(
    686                 clip,
    687                 GrRectOpFactory::MakeNonAAFillWithLocalMatrix(std::move(paint), viewM, localMatrix,
    688                                                               bounds, aaType, passes[1]));
    689     }
    690     return true;
    691 }
    692 
    693 GrPathRenderer::CanDrawPath GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
    694     // If we aren't a single_pass_shape, we require stencil buffers.
    695     if (!single_pass_shape(*args.fShape) && args.fCaps->avoidStencilBuffers()) {
    696         return CanDrawPath::kNo;
    697     }
    698     // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
    699     // handled by passing on the original shape and letting the caller compute the stroked shape
    700     // which will have a fill style.
    701     if (!args.fShape->style().isSimpleFill() || GrAAType::kCoverage == args.fAAType) {
    702         return CanDrawPath::kNo;
    703     }
    704     return CanDrawPath::kYes;
    705 }
    706 
    707 bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
    708     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
    709                               "GrMSAAPathRenderer::onDrawPath");
    710     SkTLazy<GrShape> tmpShape;
    711     const GrShape* shape = args.fShape;
    712     if (shape->style().applies()) {
    713         SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
    714         tmpShape.init(args.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale));
    715         shape = tmpShape.get();
    716     }
    717     return this->internalDrawPath(args.fRenderTargetContext,
    718                                   std::move(args.fPaint),
    719                                   args.fAAType,
    720                                   *args.fUserStencilSettings,
    721                                   *args.fClip,
    722                                   *args.fViewMatrix,
    723                                   *shape,
    724                                   false);
    725 }
    726 
    727 void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
    728     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
    729                               "GrMSAAPathRenderer::onStencilPath");
    730     SkASSERT(args.fShape->style().isSimpleFill());
    731     SkASSERT(!args.fShape->mayBeInverseFilledAfterStyling());
    732 
    733     GrPaint paint;
    734     paint.setXPFactory(GrDisableColorXPFactory::Get());
    735 
    736     this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType,
    737                            GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
    738                            *args.fShape, true);
    739 }
    740 
    741 ///////////////////////////////////////////////////////////////////////////////////////////////////
    742