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