xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/DefaultPathRenderer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/DefaultPathRenderer.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStrokeRec.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMatrixPriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAuditTrail.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrClip.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDefaultGeoProcFactory.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRenderTargetProxy.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSimpleMesh.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrStyle.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrUserStencilSettings.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrUtil.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrDisableColorXP.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrPathUtils.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrStyledShape.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrOp.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrPathStencilSettings.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
56*c8dee2aaSAndroid Build Coastguard Worker 
57*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
59*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpTest.h"
60*c8dee2aaSAndroid Build Coastguard Worker #endif
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
63*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
64*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
67*c8dee2aaSAndroid Build Coastguard Worker class GrSurfaceProxyView;
68*c8dee2aaSAndroid Build Coastguard Worker class SkArenaAlloc;
69*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
74*c8dee2aaSAndroid Build Coastguard Worker // Helpers for drawPath
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker namespace {
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker #define STENCIL_OFF     0   // Always disable stencil (even when needed)
79*c8dee2aaSAndroid Build Coastguard Worker 
single_pass_shape(const GrStyledShape & shape)80*c8dee2aaSAndroid Build Coastguard Worker inline bool single_pass_shape(const GrStyledShape& shape) {
81*c8dee2aaSAndroid Build Coastguard Worker #if STENCIL_OFF
82*c8dee2aaSAndroid Build Coastguard Worker     return true;
83*c8dee2aaSAndroid Build Coastguard Worker #else
84*c8dee2aaSAndroid Build Coastguard Worker     // Inverse fill is always two pass.
85*c8dee2aaSAndroid Build Coastguard Worker     if (shape.inverseFilled()) {
86*c8dee2aaSAndroid Build Coastguard Worker         return false;
87*c8dee2aaSAndroid Build Coastguard Worker     }
88*c8dee2aaSAndroid Build Coastguard Worker     // This path renderer only accepts simple fill paths or stroke paths that are either hairline
89*c8dee2aaSAndroid Build Coastguard Worker     // or have a stroke width small enough to treat as hairline. Hairline paths are always single
90*c8dee2aaSAndroid Build Coastguard Worker     // pass. Filled paths are single pass if they're convex.
91*c8dee2aaSAndroid Build Coastguard Worker     if (shape.style().isSimpleFill()) {
92*c8dee2aaSAndroid Build Coastguard Worker         return shape.knownToBeConvex();
93*c8dee2aaSAndroid Build Coastguard Worker     }
94*c8dee2aaSAndroid Build Coastguard Worker     return true;
95*c8dee2aaSAndroid Build Coastguard Worker #endif
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker class PathGeoBuilder {
99*c8dee2aaSAndroid Build Coastguard Worker public:
PathGeoBuilder(GrPrimitiveType primitiveType,GrMeshDrawTarget * target,SkTDArray<GrSimpleMesh * > * meshes)100*c8dee2aaSAndroid Build Coastguard Worker     PathGeoBuilder(GrPrimitiveType primitiveType,
101*c8dee2aaSAndroid Build Coastguard Worker                    GrMeshDrawTarget* target,
102*c8dee2aaSAndroid Build Coastguard Worker                    SkTDArray<GrSimpleMesh*>* meshes)
103*c8dee2aaSAndroid Build Coastguard Worker             : fPrimitiveType(primitiveType)
104*c8dee2aaSAndroid Build Coastguard Worker             , fTarget(target)
105*c8dee2aaSAndroid Build Coastguard Worker             , fVertexStride(sizeof(SkPoint))
106*c8dee2aaSAndroid Build Coastguard Worker             , fFirstIndex(0)
107*c8dee2aaSAndroid Build Coastguard Worker             , fIndicesInChunk(0)
108*c8dee2aaSAndroid Build Coastguard Worker             , fIndices(nullptr)
109*c8dee2aaSAndroid Build Coastguard Worker             , fMeshes(meshes) {
110*c8dee2aaSAndroid Build Coastguard Worker         this->allocNewBuffers();
111*c8dee2aaSAndroid Build Coastguard Worker     }
112*c8dee2aaSAndroid Build Coastguard Worker 
~PathGeoBuilder()113*c8dee2aaSAndroid Build Coastguard Worker     ~PathGeoBuilder() {
114*c8dee2aaSAndroid Build Coastguard Worker         this->createMeshAndPutBackReserve();
115*c8dee2aaSAndroid Build Coastguard Worker     }
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker     /**
118*c8dee2aaSAndroid Build Coastguard Worker      *  Path verbs
119*c8dee2aaSAndroid Build Coastguard Worker      */
moveTo(const SkPoint & p)120*c8dee2aaSAndroid Build Coastguard Worker     void moveTo(const SkPoint& p) {
121*c8dee2aaSAndroid Build Coastguard Worker         if (!this->ensureSpace(1)) {
122*c8dee2aaSAndroid Build Coastguard Worker             return;
123*c8dee2aaSAndroid Build Coastguard Worker         }
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker         if (!this->isHairline()) {
126*c8dee2aaSAndroid Build Coastguard Worker             fSubpathIndexStart = this->currentIndex();
127*c8dee2aaSAndroid Build Coastguard Worker             fSubpathStartPoint = p;
128*c8dee2aaSAndroid Build Coastguard Worker         }
129*c8dee2aaSAndroid Build Coastguard Worker         *(fCurVert++) = p;
130*c8dee2aaSAndroid Build Coastguard Worker     }
131*c8dee2aaSAndroid Build Coastguard Worker 
addLine(const SkPoint pts[])132*c8dee2aaSAndroid Build Coastguard Worker     void addLine(const SkPoint pts[]) {
133*c8dee2aaSAndroid Build Coastguard Worker         if (!this->ensureSpace(1, this->indexScale(), &pts[0])) {
134*c8dee2aaSAndroid Build Coastguard Worker             return;
135*c8dee2aaSAndroid Build Coastguard Worker         }
136*c8dee2aaSAndroid Build Coastguard Worker 
137*c8dee2aaSAndroid Build Coastguard Worker         if (this->isIndexed()) {
138*c8dee2aaSAndroid Build Coastguard Worker             uint16_t prevIdx = this->currentIndex() - 1;
139*c8dee2aaSAndroid Build Coastguard Worker             this->appendCountourEdgeIndices(prevIdx);
140*c8dee2aaSAndroid Build Coastguard Worker         }
141*c8dee2aaSAndroid Build Coastguard Worker         *(fCurVert++) = pts[1];
142*c8dee2aaSAndroid Build Coastguard Worker     }
143*c8dee2aaSAndroid Build Coastguard Worker 
addQuad(const SkPoint pts[],SkScalar srcSpaceTolSqd,SkScalar srcSpaceTol)144*c8dee2aaSAndroid Build Coastguard Worker     void addQuad(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
145*c8dee2aaSAndroid Build Coastguard Worker         if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve,
146*c8dee2aaSAndroid Build Coastguard Worker                              GrPathUtils::kMaxPointsPerCurve * this->indexScale(),
147*c8dee2aaSAndroid Build Coastguard Worker                              &pts[0])) {
148*c8dee2aaSAndroid Build Coastguard Worker             return;
149*c8dee2aaSAndroid Build Coastguard Worker         }
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker         // First pt of quad is the pt we ended on in previous step
152*c8dee2aaSAndroid Build Coastguard Worker         uint16_t firstQPtIdx = this->currentIndex() - 1;
153*c8dee2aaSAndroid Build Coastguard Worker         uint16_t numPts = (uint16_t)GrPathUtils::generateQuadraticPoints(
154*c8dee2aaSAndroid Build Coastguard Worker                 pts[0], pts[1], pts[2], srcSpaceTolSqd, &fCurVert,
155*c8dee2aaSAndroid Build Coastguard Worker                 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
156*c8dee2aaSAndroid Build Coastguard Worker         if (this->isIndexed()) {
157*c8dee2aaSAndroid Build Coastguard Worker             for (uint16_t i = 0; i < numPts; ++i) {
158*c8dee2aaSAndroid Build Coastguard Worker                 this->appendCountourEdgeIndices(firstQPtIdx + i);
159*c8dee2aaSAndroid Build Coastguard Worker             }
160*c8dee2aaSAndroid Build Coastguard Worker         }
161*c8dee2aaSAndroid Build Coastguard Worker     }
162*c8dee2aaSAndroid Build Coastguard Worker 
addConic(SkScalar weight,const SkPoint pts[],SkScalar srcSpaceTolSqd,SkScalar srcSpaceTol)163*c8dee2aaSAndroid Build Coastguard Worker     void addConic(SkScalar weight, const SkPoint pts[], SkScalar srcSpaceTolSqd,
164*c8dee2aaSAndroid Build Coastguard Worker                   SkScalar srcSpaceTol) {
165*c8dee2aaSAndroid Build Coastguard Worker         SkAutoConicToQuads converter;
166*c8dee2aaSAndroid Build Coastguard Worker         const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol);
167*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < converter.countQuads(); ++i) {
168*c8dee2aaSAndroid Build Coastguard Worker             this->addQuad(quadPts + i * 2, srcSpaceTolSqd, srcSpaceTol);
169*c8dee2aaSAndroid Build Coastguard Worker         }
170*c8dee2aaSAndroid Build Coastguard Worker     }
171*c8dee2aaSAndroid Build Coastguard Worker 
addCubic(const SkPoint pts[],SkScalar srcSpaceTolSqd,SkScalar srcSpaceTol)172*c8dee2aaSAndroid Build Coastguard Worker     void addCubic(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
173*c8dee2aaSAndroid Build Coastguard Worker         if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve,
174*c8dee2aaSAndroid Build Coastguard Worker                              GrPathUtils::kMaxPointsPerCurve * this->indexScale(),
175*c8dee2aaSAndroid Build Coastguard Worker                              &pts[0])) {
176*c8dee2aaSAndroid Build Coastguard Worker             return;
177*c8dee2aaSAndroid Build Coastguard Worker         }
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker         // First pt of cubic is the pt we ended on in previous step
180*c8dee2aaSAndroid Build Coastguard Worker         uint16_t firstCPtIdx = this->currentIndex() - 1;
181*c8dee2aaSAndroid Build Coastguard Worker         uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
182*c8dee2aaSAndroid Build Coastguard Worker                 pts[0], pts[1], pts[2], pts[3], srcSpaceTolSqd, &fCurVert,
183*c8dee2aaSAndroid Build Coastguard Worker                 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
184*c8dee2aaSAndroid Build Coastguard Worker         if (this->isIndexed()) {
185*c8dee2aaSAndroid Build Coastguard Worker             for (uint16_t i = 0; i < numPts; ++i) {
186*c8dee2aaSAndroid Build Coastguard Worker                 this->appendCountourEdgeIndices(firstCPtIdx + i);
187*c8dee2aaSAndroid Build Coastguard Worker             }
188*c8dee2aaSAndroid Build Coastguard Worker         }
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
addPath(const SkPath & path,SkScalar srcSpaceTol)191*c8dee2aaSAndroid Build Coastguard Worker     void addPath(const SkPath& path, SkScalar srcSpaceTol) {
192*c8dee2aaSAndroid Build Coastguard Worker         SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol;
193*c8dee2aaSAndroid Build Coastguard Worker 
194*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Iter iter(path, false);
195*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[4];
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker         bool done = false;
198*c8dee2aaSAndroid Build Coastguard Worker         while (!done) {
199*c8dee2aaSAndroid Build Coastguard Worker             SkPath::Verb verb = iter.next(pts);
200*c8dee2aaSAndroid Build Coastguard Worker             switch (verb) {
201*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kMove_Verb:
202*c8dee2aaSAndroid Build Coastguard Worker                     this->moveTo(pts[0]);
203*c8dee2aaSAndroid Build Coastguard Worker                     break;
204*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kLine_Verb:
205*c8dee2aaSAndroid Build Coastguard Worker                     this->addLine(pts);
206*c8dee2aaSAndroid Build Coastguard Worker                     break;
207*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kConic_Verb:
208*c8dee2aaSAndroid Build Coastguard Worker                     this->addConic(iter.conicWeight(), pts, srcSpaceTolSqd, srcSpaceTol);
209*c8dee2aaSAndroid Build Coastguard Worker                     break;
210*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kQuad_Verb:
211*c8dee2aaSAndroid Build Coastguard Worker                     this->addQuad(pts, srcSpaceTolSqd, srcSpaceTol);
212*c8dee2aaSAndroid Build Coastguard Worker                     break;
213*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kCubic_Verb:
214*c8dee2aaSAndroid Build Coastguard Worker                     this->addCubic(pts, srcSpaceTolSqd, srcSpaceTol);
215*c8dee2aaSAndroid Build Coastguard Worker                     break;
216*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kClose_Verb:
217*c8dee2aaSAndroid Build Coastguard Worker                     break;
218*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kDone_Verb:
219*c8dee2aaSAndroid Build Coastguard Worker                     done = true;
220*c8dee2aaSAndroid Build Coastguard Worker             }
221*c8dee2aaSAndroid Build Coastguard Worker         }
222*c8dee2aaSAndroid Build Coastguard Worker     }
223*c8dee2aaSAndroid Build Coastguard Worker 
PathHasMultipleSubpaths(const SkPath & path)224*c8dee2aaSAndroid Build Coastguard Worker     static bool PathHasMultipleSubpaths(const SkPath& path) {
225*c8dee2aaSAndroid Build Coastguard Worker         bool first = true;
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Iter iter(path, false);
228*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Verb verb;
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[4];
231*c8dee2aaSAndroid Build Coastguard Worker         while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
232*c8dee2aaSAndroid Build Coastguard Worker             if (SkPath::kMove_Verb == verb && !first) {
233*c8dee2aaSAndroid Build Coastguard Worker                 return true;
234*c8dee2aaSAndroid Build Coastguard Worker             }
235*c8dee2aaSAndroid Build Coastguard Worker             first = false;
236*c8dee2aaSAndroid Build Coastguard Worker         }
237*c8dee2aaSAndroid Build Coastguard Worker         return false;
238*c8dee2aaSAndroid Build Coastguard Worker     }
239*c8dee2aaSAndroid Build Coastguard Worker 
240*c8dee2aaSAndroid Build Coastguard Worker private:
241*c8dee2aaSAndroid Build Coastguard Worker     /**
242*c8dee2aaSAndroid Build Coastguard Worker      *  Derived properties
243*c8dee2aaSAndroid Build Coastguard Worker      *  TODO: Cache some of these for better performance, rather than re-computing?
244*c8dee2aaSAndroid Build Coastguard Worker      */
isIndexed() const245*c8dee2aaSAndroid Build Coastguard Worker     bool isIndexed() const {
246*c8dee2aaSAndroid Build Coastguard Worker         return GrPrimitiveType::kLines == fPrimitiveType ||
247*c8dee2aaSAndroid Build Coastguard Worker                GrPrimitiveType::kTriangles == fPrimitiveType;
248*c8dee2aaSAndroid Build Coastguard Worker     }
isHairline() const249*c8dee2aaSAndroid Build Coastguard Worker     bool isHairline() const {
250*c8dee2aaSAndroid Build Coastguard Worker         return GrPrimitiveType::kLines == fPrimitiveType ||
251*c8dee2aaSAndroid Build Coastguard Worker                GrPrimitiveType::kLineStrip == fPrimitiveType;
252*c8dee2aaSAndroid Build Coastguard Worker     }
indexScale() const253*c8dee2aaSAndroid Build Coastguard Worker     int indexScale() const {
254*c8dee2aaSAndroid Build Coastguard Worker         switch (fPrimitiveType) {
255*c8dee2aaSAndroid Build Coastguard Worker             case GrPrimitiveType::kLines:
256*c8dee2aaSAndroid Build Coastguard Worker                 return 2;
257*c8dee2aaSAndroid Build Coastguard Worker             case GrPrimitiveType::kTriangles:
258*c8dee2aaSAndroid Build Coastguard Worker                 return 3;
259*c8dee2aaSAndroid Build Coastguard Worker             default:
260*c8dee2aaSAndroid Build Coastguard Worker                 return 0;
261*c8dee2aaSAndroid Build Coastguard Worker         }
262*c8dee2aaSAndroid Build Coastguard Worker     }
263*c8dee2aaSAndroid Build Coastguard Worker 
currentIndex() const264*c8dee2aaSAndroid Build Coastguard Worker     uint16_t currentIndex() const { return fCurVert - fVertices; }
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker     // Allocate vertex and (possibly) index buffers
allocNewBuffers()267*c8dee2aaSAndroid Build Coastguard Worker     void allocNewBuffers() {
268*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fValid);
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker         // Ensure that we always get enough verts for a worst-case quad/cubic, plus leftover points
271*c8dee2aaSAndroid Build Coastguard Worker         // from previous mesh piece (up to two verts to continue fanning). If we can't get that
272*c8dee2aaSAndroid Build Coastguard Worker         // many, ask for a much larger number. This needs to be fairly big to handle  quads/cubics,
273*c8dee2aaSAndroid Build Coastguard Worker         // which have a worst-case of 1k points.
274*c8dee2aaSAndroid Build Coastguard Worker         static const int kMinVerticesPerChunk = GrPathUtils::kMaxPointsPerCurve + 2;
275*c8dee2aaSAndroid Build Coastguard Worker         static const int kFallbackVerticesPerChunk = 16384;
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker         fVertices = static_cast<SkPoint*>(fTarget->makeVertexSpaceAtLeast(fVertexStride,
278*c8dee2aaSAndroid Build Coastguard Worker                                                                           kMinVerticesPerChunk,
279*c8dee2aaSAndroid Build Coastguard Worker                                                                           kFallbackVerticesPerChunk,
280*c8dee2aaSAndroid Build Coastguard Worker                                                                           &fVertexBuffer,
281*c8dee2aaSAndroid Build Coastguard Worker                                                                           &fFirstVertex,
282*c8dee2aaSAndroid Build Coastguard Worker                                                                           &fVerticesInChunk));
283*c8dee2aaSAndroid Build Coastguard Worker         if (!fVertices) {
284*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("WARNING: Failed to allocate vertex buffer for DefaultPathRenderer.\n");
285*c8dee2aaSAndroid Build Coastguard Worker             fCurVert = nullptr;
286*c8dee2aaSAndroid Build Coastguard Worker             fCurIdx = fIndices = nullptr;
287*c8dee2aaSAndroid Build Coastguard Worker             fSubpathIndexStart = 0;
288*c8dee2aaSAndroid Build Coastguard Worker             fValid = false;
289*c8dee2aaSAndroid Build Coastguard Worker             return;
290*c8dee2aaSAndroid Build Coastguard Worker         }
291*c8dee2aaSAndroid Build Coastguard Worker 
292*c8dee2aaSAndroid Build Coastguard Worker         if (this->isIndexed()) {
293*c8dee2aaSAndroid Build Coastguard Worker             // Similar to above: Ensure we get enough indices for one worst-case quad/cubic.
294*c8dee2aaSAndroid Build Coastguard Worker             // No extra indices are needed for stitching, though. If we can't get that many, ask
295*c8dee2aaSAndroid Build Coastguard Worker             // for enough to match our large vertex request.
296*c8dee2aaSAndroid Build Coastguard Worker             const int kMinIndicesPerChunk = GrPathUtils::kMaxPointsPerCurve * this->indexScale();
297*c8dee2aaSAndroid Build Coastguard Worker             const int kFallbackIndicesPerChunk = kFallbackVerticesPerChunk * this->indexScale();
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker             fIndices = fTarget->makeIndexSpaceAtLeast(kMinIndicesPerChunk, kFallbackIndicesPerChunk,
300*c8dee2aaSAndroid Build Coastguard Worker                                                       &fIndexBuffer, &fFirstIndex,
301*c8dee2aaSAndroid Build Coastguard Worker                                                       &fIndicesInChunk);
302*c8dee2aaSAndroid Build Coastguard Worker             if (!fIndices) {
303*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("WARNING: Failed to allocate index buffer for DefaultPathRenderer.\n");
304*c8dee2aaSAndroid Build Coastguard Worker                 fVertices = nullptr;
305*c8dee2aaSAndroid Build Coastguard Worker                 fValid = false;
306*c8dee2aaSAndroid Build Coastguard Worker             }
307*c8dee2aaSAndroid Build Coastguard Worker         }
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker         fCurVert = fVertices;
310*c8dee2aaSAndroid Build Coastguard Worker         fCurIdx = fIndices;
311*c8dee2aaSAndroid Build Coastguard Worker         fSubpathIndexStart = 0;
312*c8dee2aaSAndroid Build Coastguard Worker     }
313*c8dee2aaSAndroid Build Coastguard Worker 
appendCountourEdgeIndices(uint16_t edgeV0Idx)314*c8dee2aaSAndroid Build Coastguard Worker     void appendCountourEdgeIndices(uint16_t edgeV0Idx) {
315*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCurIdx);
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker         // When drawing lines we're appending line segments along the countour. When applying the
318*c8dee2aaSAndroid Build Coastguard Worker         // other fill rules we're drawing triangle fans around the start of the current (sub)path.
319*c8dee2aaSAndroid Build Coastguard Worker         if (!this->isHairline()) {
320*c8dee2aaSAndroid Build Coastguard Worker             *(fCurIdx++) = fSubpathIndexStart;
321*c8dee2aaSAndroid Build Coastguard Worker         }
322*c8dee2aaSAndroid Build Coastguard Worker         *(fCurIdx++) = edgeV0Idx;
323*c8dee2aaSAndroid Build Coastguard Worker         *(fCurIdx++) = edgeV0Idx + 1;
324*c8dee2aaSAndroid Build Coastguard Worker     }
325*c8dee2aaSAndroid Build Coastguard Worker 
326*c8dee2aaSAndroid Build Coastguard Worker     // Emits a single draw with all accumulated vertex/index data
createMeshAndPutBackReserve()327*c8dee2aaSAndroid Build Coastguard Worker     void createMeshAndPutBackReserve() {
328*c8dee2aaSAndroid Build Coastguard Worker         if (!fValid) {
329*c8dee2aaSAndroid Build Coastguard Worker             return;
330*c8dee2aaSAndroid Build Coastguard Worker         }
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker         int vertexCount = fCurVert - fVertices;
333*c8dee2aaSAndroid Build Coastguard Worker         int indexCount = fCurIdx - fIndices;
334*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(vertexCount <= fVerticesInChunk);
335*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(indexCount <= fIndicesInChunk);
336*c8dee2aaSAndroid Build Coastguard Worker 
337*c8dee2aaSAndroid Build Coastguard Worker         GrSimpleMesh* mesh = nullptr;
338*c8dee2aaSAndroid Build Coastguard Worker         if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
339*c8dee2aaSAndroid Build Coastguard Worker             mesh = fTarget->allocMesh();
340*c8dee2aaSAndroid Build Coastguard Worker             if (!this->isIndexed()) {
341*c8dee2aaSAndroid Build Coastguard Worker                 mesh->set(std::move(fVertexBuffer), vertexCount, fFirstVertex);
342*c8dee2aaSAndroid Build Coastguard Worker             } else {
343*c8dee2aaSAndroid Build Coastguard Worker                 mesh->setIndexed(std::move(fIndexBuffer), indexCount, fFirstIndex, 0,
344*c8dee2aaSAndroid Build Coastguard Worker                                  vertexCount - 1, GrPrimitiveRestart::kNo, std::move(fVertexBuffer),
345*c8dee2aaSAndroid Build Coastguard Worker                                  fFirstVertex);
346*c8dee2aaSAndroid Build Coastguard Worker             }
347*c8dee2aaSAndroid Build Coastguard Worker         }
348*c8dee2aaSAndroid Build Coastguard Worker 
349*c8dee2aaSAndroid Build Coastguard Worker         fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
350*c8dee2aaSAndroid Build Coastguard Worker         fTarget->putBackVertices((size_t)(fVerticesInChunk - vertexCount), fVertexStride);
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker         if (mesh) {
353*c8dee2aaSAndroid Build Coastguard Worker             fMeshes->push_back(mesh);
354*c8dee2aaSAndroid Build Coastguard Worker         }
355*c8dee2aaSAndroid Build Coastguard Worker     }
356*c8dee2aaSAndroid Build Coastguard Worker 
ensureSpace(int vertsNeeded,int indicesNeeded=0,const SkPoint * lastPoint=nullptr)357*c8dee2aaSAndroid Build Coastguard Worker     bool ensureSpace(int vertsNeeded, int indicesNeeded = 0, const SkPoint* lastPoint = nullptr) {
358*c8dee2aaSAndroid Build Coastguard Worker         if (!fValid) {
359*c8dee2aaSAndroid Build Coastguard Worker             return false;
360*c8dee2aaSAndroid Build Coastguard Worker         }
361*c8dee2aaSAndroid Build Coastguard Worker 
362*c8dee2aaSAndroid Build Coastguard Worker         if (fCurVert + vertsNeeded > fVertices + fVerticesInChunk ||
363*c8dee2aaSAndroid Build Coastguard Worker             fCurIdx + indicesNeeded > fIndices + fIndicesInChunk) {
364*c8dee2aaSAndroid Build Coastguard Worker             // We are about to run out of space (possibly)
365*c8dee2aaSAndroid Build Coastguard Worker 
366*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
367*c8dee2aaSAndroid Build Coastguard Worker             // To maintain continuity, we need to remember one or two points from the current mesh.
368*c8dee2aaSAndroid Build Coastguard Worker             // Lines only need the last point, fills need the first point from the current contour.
369*c8dee2aaSAndroid Build Coastguard Worker             // We always grab both here, and append the ones we need at the end of this process.
370*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fSubpathIndexStart < fVerticesInChunk);
371*c8dee2aaSAndroid Build Coastguard Worker             // This assert is reading from the gpu buffer fVertices and will be slow, but for debug
372*c8dee2aaSAndroid Build Coastguard Worker             // that is okay.
373*c8dee2aaSAndroid Build Coastguard Worker             if (!this->isHairline()) {
374*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(fSubpathStartPoint == fVertices[fSubpathIndexStart]);
375*c8dee2aaSAndroid Build Coastguard Worker             }
376*c8dee2aaSAndroid Build Coastguard Worker             if (lastPoint) {
377*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(*(fCurVert - 1) == *lastPoint);
378*c8dee2aaSAndroid Build Coastguard Worker             }
379*c8dee2aaSAndroid Build Coastguard Worker #endif
380*c8dee2aaSAndroid Build Coastguard Worker 
381*c8dee2aaSAndroid Build Coastguard Worker             // Draw the mesh we've accumulated, and put back any unused space
382*c8dee2aaSAndroid Build Coastguard Worker             this->createMeshAndPutBackReserve();
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker             // Get new buffers
385*c8dee2aaSAndroid Build Coastguard Worker             this->allocNewBuffers();
386*c8dee2aaSAndroid Build Coastguard Worker             if (!fValid) {
387*c8dee2aaSAndroid Build Coastguard Worker                 return false;
388*c8dee2aaSAndroid Build Coastguard Worker             }
389*c8dee2aaSAndroid Build Coastguard Worker 
390*c8dee2aaSAndroid Build Coastguard Worker             // On moves we don't need to copy over any points to the new buffer and we pass in a
391*c8dee2aaSAndroid Build Coastguard Worker             // null lastPoint.
392*c8dee2aaSAndroid Build Coastguard Worker             if (lastPoint) {
393*c8dee2aaSAndroid Build Coastguard Worker                 // Append copies of the points we saved so the two meshes will weld properly
394*c8dee2aaSAndroid Build Coastguard Worker                 if (!this->isHairline()) {
395*c8dee2aaSAndroid Build Coastguard Worker                     *(fCurVert++) = fSubpathStartPoint;
396*c8dee2aaSAndroid Build Coastguard Worker                 }
397*c8dee2aaSAndroid Build Coastguard Worker                 *(fCurVert++) = *lastPoint;
398*c8dee2aaSAndroid Build Coastguard Worker             }
399*c8dee2aaSAndroid Build Coastguard Worker         }
400*c8dee2aaSAndroid Build Coastguard Worker 
401*c8dee2aaSAndroid Build Coastguard Worker         return true;
402*c8dee2aaSAndroid Build Coastguard Worker     }
403*c8dee2aaSAndroid Build Coastguard Worker 
404*c8dee2aaSAndroid Build Coastguard Worker     GrPrimitiveType fPrimitiveType;
405*c8dee2aaSAndroid Build Coastguard Worker     GrMeshDrawTarget* fTarget;
406*c8dee2aaSAndroid Build Coastguard Worker     size_t fVertexStride;
407*c8dee2aaSAndroid Build Coastguard Worker 
408*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fVertexBuffer;
409*c8dee2aaSAndroid Build Coastguard Worker     int fFirstVertex;
410*c8dee2aaSAndroid Build Coastguard Worker     int fVerticesInChunk;
411*c8dee2aaSAndroid Build Coastguard Worker     SkPoint* fVertices;
412*c8dee2aaSAndroid Build Coastguard Worker     SkPoint* fCurVert;
413*c8dee2aaSAndroid Build Coastguard Worker 
414*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fIndexBuffer;
415*c8dee2aaSAndroid Build Coastguard Worker     int fFirstIndex;
416*c8dee2aaSAndroid Build Coastguard Worker     int fIndicesInChunk;
417*c8dee2aaSAndroid Build Coastguard Worker     uint16_t* fIndices;
418*c8dee2aaSAndroid Build Coastguard Worker     uint16_t* fCurIdx;
419*c8dee2aaSAndroid Build Coastguard Worker     uint16_t fSubpathIndexStart;
420*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fSubpathStartPoint;
421*c8dee2aaSAndroid Build Coastguard Worker 
422*c8dee2aaSAndroid Build Coastguard Worker     bool fValid = true;
423*c8dee2aaSAndroid Build Coastguard Worker     SkTDArray<GrSimpleMesh*>* fMeshes;
424*c8dee2aaSAndroid Build Coastguard Worker };
425*c8dee2aaSAndroid Build Coastguard Worker 
426*c8dee2aaSAndroid Build Coastguard Worker class DefaultPathOp final : public GrMeshDrawOp {
427*c8dee2aaSAndroid Build Coastguard Worker private:
428*c8dee2aaSAndroid Build Coastguard Worker     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
429*c8dee2aaSAndroid Build Coastguard Worker 
430*c8dee2aaSAndroid Build Coastguard Worker public:
431*c8dee2aaSAndroid Build Coastguard Worker     DEFINE_OP_CLASS_ID
432*c8dee2aaSAndroid Build Coastguard Worker 
Make(GrRecordingContext * context,GrPaint && paint,const SkPath & path,SkScalar tolerance,uint8_t coverage,const SkMatrix & viewMatrix,bool isHairline,GrAAType aaType,const SkRect & devBounds,const GrUserStencilSettings * stencilSettings)433*c8dee2aaSAndroid Build Coastguard Worker     static GrOp::Owner Make(GrRecordingContext* context,
434*c8dee2aaSAndroid Build Coastguard Worker                             GrPaint&& paint,
435*c8dee2aaSAndroid Build Coastguard Worker                             const SkPath& path,
436*c8dee2aaSAndroid Build Coastguard Worker                             SkScalar tolerance,
437*c8dee2aaSAndroid Build Coastguard Worker                             uint8_t coverage,
438*c8dee2aaSAndroid Build Coastguard Worker                             const SkMatrix& viewMatrix,
439*c8dee2aaSAndroid Build Coastguard Worker                             bool isHairline,
440*c8dee2aaSAndroid Build Coastguard Worker                             GrAAType aaType,
441*c8dee2aaSAndroid Build Coastguard Worker                             const SkRect& devBounds,
442*c8dee2aaSAndroid Build Coastguard Worker                             const GrUserStencilSettings* stencilSettings) {
443*c8dee2aaSAndroid Build Coastguard Worker         return Helper::FactoryHelper<DefaultPathOp>(context, std::move(paint), path, tolerance,
444*c8dee2aaSAndroid Build Coastguard Worker                                                     coverage, viewMatrix, isHairline, aaType,
445*c8dee2aaSAndroid Build Coastguard Worker                                                     devBounds, stencilSettings);
446*c8dee2aaSAndroid Build Coastguard Worker     }
447*c8dee2aaSAndroid Build Coastguard Worker 
name() const448*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "DefaultPathOp"; }
449*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const450*c8dee2aaSAndroid Build Coastguard Worker     void visitProxies(const GrVisitProxyFunc& func) const override {
451*c8dee2aaSAndroid Build Coastguard Worker         if (fProgramInfo) {
452*c8dee2aaSAndroid Build Coastguard Worker             fProgramInfo->visitFPProxies(func);
453*c8dee2aaSAndroid Build Coastguard Worker         } else {
454*c8dee2aaSAndroid Build Coastguard Worker             fHelper.visitProxies(func);
455*c8dee2aaSAndroid Build Coastguard Worker         }
456*c8dee2aaSAndroid Build Coastguard Worker     }
457*c8dee2aaSAndroid Build Coastguard Worker 
DefaultPathOp(GrProcessorSet * processorSet,const SkPMColor4f & color,const SkPath & path,SkScalar tolerance,uint8_t coverage,const SkMatrix & viewMatrix,bool isHairline,GrAAType aaType,const SkRect & devBounds,const GrUserStencilSettings * stencilSettings)458*c8dee2aaSAndroid Build Coastguard Worker     DefaultPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const SkPath& path,
459*c8dee2aaSAndroid Build Coastguard Worker                   SkScalar tolerance, uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline,
460*c8dee2aaSAndroid Build Coastguard Worker                   GrAAType aaType, const SkRect& devBounds,
461*c8dee2aaSAndroid Build Coastguard Worker                   const GrUserStencilSettings* stencilSettings)
462*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(ClassID())
463*c8dee2aaSAndroid Build Coastguard Worker             , fHelper(processorSet, aaType, stencilSettings)
464*c8dee2aaSAndroid Build Coastguard Worker             , fColor(color)
465*c8dee2aaSAndroid Build Coastguard Worker             , fCoverage(coverage)
466*c8dee2aaSAndroid Build Coastguard Worker             , fViewMatrix(viewMatrix)
467*c8dee2aaSAndroid Build Coastguard Worker             , fIsHairline(isHairline) {
468*c8dee2aaSAndroid Build Coastguard Worker         fPaths.emplace_back(PathData{path, tolerance});
469*c8dee2aaSAndroid Build Coastguard Worker 
470*c8dee2aaSAndroid Build Coastguard Worker         HasAABloat aaBloat = (aaType == GrAAType::kNone) ? HasAABloat ::kNo : HasAABloat::kYes;
471*c8dee2aaSAndroid Build Coastguard Worker         this->setBounds(devBounds, aaBloat,
472*c8dee2aaSAndroid Build Coastguard Worker                         isHairline ? IsHairline::kYes : IsHairline::kNo);
473*c8dee2aaSAndroid Build Coastguard Worker     }
474*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const475*c8dee2aaSAndroid Build Coastguard Worker     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
476*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)477*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
478*c8dee2aaSAndroid Build Coastguard Worker                                       GrClampType clampType) override {
479*c8dee2aaSAndroid Build Coastguard Worker         GrProcessorAnalysisCoverage gpCoverage =
480*c8dee2aaSAndroid Build Coastguard Worker                 this->coverage() == 0xFF ? GrProcessorAnalysisCoverage::kNone
481*c8dee2aaSAndroid Build Coastguard Worker                                          : GrProcessorAnalysisCoverage::kSingleChannel;
482*c8dee2aaSAndroid Build Coastguard Worker         // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
483*c8dee2aaSAndroid Build Coastguard Worker         return fHelper.finalizeProcessors(caps, clip, clampType, gpCoverage, &fColor, nullptr);
484*c8dee2aaSAndroid Build Coastguard Worker     }
485*c8dee2aaSAndroid Build Coastguard Worker 
486*c8dee2aaSAndroid Build Coastguard Worker private:
primType() const487*c8dee2aaSAndroid Build Coastguard Worker     GrPrimitiveType primType() const {
488*c8dee2aaSAndroid Build Coastguard Worker         if (this->isHairline()) {
489*c8dee2aaSAndroid Build Coastguard Worker             int instanceCount = fPaths.size();
490*c8dee2aaSAndroid Build Coastguard Worker 
491*c8dee2aaSAndroid Build Coastguard Worker             // We avoid indices when we have a single hairline contour.
492*c8dee2aaSAndroid Build Coastguard Worker             bool isIndexed = instanceCount > 1 ||
493*c8dee2aaSAndroid Build Coastguard Worker                                 PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath);
494*c8dee2aaSAndroid Build Coastguard Worker 
495*c8dee2aaSAndroid Build Coastguard Worker             return isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip;
496*c8dee2aaSAndroid Build Coastguard Worker         }
497*c8dee2aaSAndroid Build Coastguard Worker 
498*c8dee2aaSAndroid Build Coastguard Worker         return GrPrimitiveType::kTriangles;
499*c8dee2aaSAndroid Build Coastguard Worker     }
500*c8dee2aaSAndroid Build Coastguard Worker 
programInfo()501*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* programInfo() override { return fProgramInfo; }
502*c8dee2aaSAndroid Build Coastguard Worker 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)503*c8dee2aaSAndroid Build Coastguard Worker     void onCreateProgramInfo(const GrCaps* caps,
504*c8dee2aaSAndroid Build Coastguard Worker                              SkArenaAlloc* arena,
505*c8dee2aaSAndroid Build Coastguard Worker                              const GrSurfaceProxyView& writeView,
506*c8dee2aaSAndroid Build Coastguard Worker                              bool usesMSAASurface,
507*c8dee2aaSAndroid Build Coastguard Worker                              GrAppliedClip&& appliedClip,
508*c8dee2aaSAndroid Build Coastguard Worker                              const GrDstProxyView& dstProxyView,
509*c8dee2aaSAndroid Build Coastguard Worker                              GrXferBarrierFlags renderPassXferBarriers,
510*c8dee2aaSAndroid Build Coastguard Worker                              GrLoadOp colorLoadOp) override {
511*c8dee2aaSAndroid Build Coastguard Worker         GrGeometryProcessor* gp;
512*c8dee2aaSAndroid Build Coastguard Worker         {
513*c8dee2aaSAndroid Build Coastguard Worker             using namespace GrDefaultGeoProcFactory;
514*c8dee2aaSAndroid Build Coastguard Worker             Color color(this->color());
515*c8dee2aaSAndroid Build Coastguard Worker             Coverage coverage(this->coverage());
516*c8dee2aaSAndroid Build Coastguard Worker             LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
517*c8dee2aaSAndroid Build Coastguard Worker                                                               : LocalCoords::kUnused_Type);
518*c8dee2aaSAndroid Build Coastguard Worker             gp = GrDefaultGeoProcFactory::Make(arena,
519*c8dee2aaSAndroid Build Coastguard Worker                                                color,
520*c8dee2aaSAndroid Build Coastguard Worker                                                coverage,
521*c8dee2aaSAndroid Build Coastguard Worker                                                localCoords,
522*c8dee2aaSAndroid Build Coastguard Worker                                                this->viewMatrix());
523*c8dee2aaSAndroid Build Coastguard Worker         }
524*c8dee2aaSAndroid Build Coastguard Worker 
525*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(gp->vertexStride() == sizeof(SkPoint));
526*c8dee2aaSAndroid Build Coastguard Worker 
527*c8dee2aaSAndroid Build Coastguard Worker         fProgramInfo =  fHelper.createProgramInfoWithStencil(caps, arena, writeView,
528*c8dee2aaSAndroid Build Coastguard Worker                                                              usesMSAASurface,
529*c8dee2aaSAndroid Build Coastguard Worker                                                              std::move(appliedClip), dstProxyView,
530*c8dee2aaSAndroid Build Coastguard Worker                                                              gp, this->primType(),
531*c8dee2aaSAndroid Build Coastguard Worker                                                              renderPassXferBarriers, colorLoadOp);
532*c8dee2aaSAndroid Build Coastguard Worker 
533*c8dee2aaSAndroid Build Coastguard Worker     }
534*c8dee2aaSAndroid Build Coastguard Worker 
onPrepareDraws(GrMeshDrawTarget * target)535*c8dee2aaSAndroid Build Coastguard Worker     void onPrepareDraws(GrMeshDrawTarget* target) override {
536*c8dee2aaSAndroid Build Coastguard Worker         PathGeoBuilder pathGeoBuilder(this->primType(), target, &fMeshes);
537*c8dee2aaSAndroid Build Coastguard Worker 
538*c8dee2aaSAndroid Build Coastguard Worker         // fill buffers
539*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fPaths.size(); i++) {
540*c8dee2aaSAndroid Build Coastguard Worker             const PathData& args = fPaths[i];
541*c8dee2aaSAndroid Build Coastguard Worker             pathGeoBuilder.addPath(args.fPath, args.fTolerance);
542*c8dee2aaSAndroid Build Coastguard Worker         }
543*c8dee2aaSAndroid Build Coastguard Worker     }
544*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)545*c8dee2aaSAndroid Build Coastguard Worker     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
546*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo) {
547*c8dee2aaSAndroid Build Coastguard Worker             this->createProgramInfo(flushState);
548*c8dee2aaSAndroid Build Coastguard Worker         }
549*c8dee2aaSAndroid Build Coastguard Worker 
550*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo || fMeshes.empty()) {
551*c8dee2aaSAndroid Build Coastguard Worker             return;
552*c8dee2aaSAndroid Build Coastguard Worker         }
553*c8dee2aaSAndroid Build Coastguard Worker 
554*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
555*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
556*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fMeshes.size(); ++i) {
557*c8dee2aaSAndroid Build Coastguard Worker             flushState->drawMesh(*fMeshes[i]);
558*c8dee2aaSAndroid Build Coastguard Worker         }
559*c8dee2aaSAndroid Build Coastguard Worker     }
560*c8dee2aaSAndroid Build Coastguard Worker 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)561*c8dee2aaSAndroid Build Coastguard Worker     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
562*c8dee2aaSAndroid Build Coastguard Worker         DefaultPathOp* that = t->cast<DefaultPathOp>();
563*c8dee2aaSAndroid Build Coastguard Worker         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
564*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
565*c8dee2aaSAndroid Build Coastguard Worker         }
566*c8dee2aaSAndroid Build Coastguard Worker 
567*c8dee2aaSAndroid Build Coastguard Worker         if (this->color() != that->color()) {
568*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
569*c8dee2aaSAndroid Build Coastguard Worker         }
570*c8dee2aaSAndroid Build Coastguard Worker 
571*c8dee2aaSAndroid Build Coastguard Worker         if (this->coverage() != that->coverage()) {
572*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
573*c8dee2aaSAndroid Build Coastguard Worker         }
574*c8dee2aaSAndroid Build Coastguard Worker 
575*c8dee2aaSAndroid Build Coastguard Worker         if (!SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix())) {
576*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
577*c8dee2aaSAndroid Build Coastguard Worker         }
578*c8dee2aaSAndroid Build Coastguard Worker 
579*c8dee2aaSAndroid Build Coastguard Worker         if (this->isHairline() != that->isHairline()) {
580*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
581*c8dee2aaSAndroid Build Coastguard Worker         }
582*c8dee2aaSAndroid Build Coastguard Worker 
583*c8dee2aaSAndroid Build Coastguard Worker         fPaths.push_back_n(that->fPaths.size(), that->fPaths.begin());
584*c8dee2aaSAndroid Build Coastguard Worker         return CombineResult::kMerged;
585*c8dee2aaSAndroid Build Coastguard Worker     }
586*c8dee2aaSAndroid Build Coastguard Worker 
587*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const588*c8dee2aaSAndroid Build Coastguard Worker     SkString onDumpInfo() const override {
589*c8dee2aaSAndroid Build Coastguard Worker         SkString string = SkStringPrintf("Color: 0x%08x Count: %d\n",
590*c8dee2aaSAndroid Build Coastguard Worker                                          fColor.toBytes_RGBA(), fPaths.size());
591*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& path : fPaths) {
592*c8dee2aaSAndroid Build Coastguard Worker             string.appendf("Tolerance: %.2f\n", path.fTolerance);
593*c8dee2aaSAndroid Build Coastguard Worker         }
594*c8dee2aaSAndroid Build Coastguard Worker         string += fHelper.dumpInfo();
595*c8dee2aaSAndroid Build Coastguard Worker         return string;
596*c8dee2aaSAndroid Build Coastguard Worker     }
597*c8dee2aaSAndroid Build Coastguard Worker #endif
598*c8dee2aaSAndroid Build Coastguard Worker 
color() const599*c8dee2aaSAndroid Build Coastguard Worker     const SkPMColor4f& color() const { return fColor; }
coverage() const600*c8dee2aaSAndroid Build Coastguard Worker     uint8_t coverage() const { return fCoverage; }
viewMatrix() const601*c8dee2aaSAndroid Build Coastguard Worker     const SkMatrix& viewMatrix() const { return fViewMatrix; }
isHairline() const602*c8dee2aaSAndroid Build Coastguard Worker     bool isHairline() const { return fIsHairline; }
603*c8dee2aaSAndroid Build Coastguard Worker 
604*c8dee2aaSAndroid Build Coastguard Worker     struct PathData {
605*c8dee2aaSAndroid Build Coastguard Worker         SkPath fPath;
606*c8dee2aaSAndroid Build Coastguard Worker         SkScalar fTolerance;
607*c8dee2aaSAndroid Build Coastguard Worker     };
608*c8dee2aaSAndroid Build Coastguard Worker 
609*c8dee2aaSAndroid Build Coastguard Worker     STArray<1, PathData, true> fPaths;
610*c8dee2aaSAndroid Build Coastguard Worker     Helper fHelper;
611*c8dee2aaSAndroid Build Coastguard Worker     SkPMColor4f fColor;
612*c8dee2aaSAndroid Build Coastguard Worker     uint8_t fCoverage;
613*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix fViewMatrix;
614*c8dee2aaSAndroid Build Coastguard Worker     bool fIsHairline;
615*c8dee2aaSAndroid Build Coastguard Worker 
616*c8dee2aaSAndroid Build Coastguard Worker     SkTDArray<GrSimpleMesh*> fMeshes;
617*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* fProgramInfo = nullptr;
618*c8dee2aaSAndroid Build Coastguard Worker 
619*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrMeshDrawOp;
620*c8dee2aaSAndroid Build Coastguard Worker };
621*c8dee2aaSAndroid Build Coastguard Worker 
622*c8dee2aaSAndroid Build Coastguard Worker }  // anonymous namespace
623*c8dee2aaSAndroid Build Coastguard Worker 
624*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
625*c8dee2aaSAndroid Build Coastguard Worker 
626*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
627*c8dee2aaSAndroid Build Coastguard Worker 
GR_DRAW_OP_TEST_DEFINE(DefaultPathOp)628*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
629*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix viewMatrix = GrTest::TestMatrix(random);
630*c8dee2aaSAndroid Build Coastguard Worker 
631*c8dee2aaSAndroid Build Coastguard Worker     // For now just hairlines because the other types of draws require two ops.
632*c8dee2aaSAndroid Build Coastguard Worker     // TODO we should figure out a way to combine the stencil and cover steps into one op.
633*c8dee2aaSAndroid Build Coastguard Worker     GrStyle style(SkStrokeRec::kHairline_InitStyle);
634*c8dee2aaSAndroid Build Coastguard Worker     const SkPath& path = GrTest::TestPath(random);
635*c8dee2aaSAndroid Build Coastguard Worker 
636*c8dee2aaSAndroid Build Coastguard Worker     // Compute srcSpaceTol
637*c8dee2aaSAndroid Build Coastguard Worker     SkRect bounds = path.getBounds();
638*c8dee2aaSAndroid Build Coastguard Worker     SkScalar tol = GrPathUtils::kDefaultTolerance;
639*c8dee2aaSAndroid Build Coastguard Worker     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
640*c8dee2aaSAndroid Build Coastguard Worker 
641*c8dee2aaSAndroid Build Coastguard Worker     viewMatrix.mapRect(&bounds);
642*c8dee2aaSAndroid Build Coastguard Worker     uint8_t coverage = GrTest::RandomCoverage(random);
643*c8dee2aaSAndroid Build Coastguard Worker     GrAAType aaType = GrAAType::kNone;
644*c8dee2aaSAndroid Build Coastguard Worker     if (numSamples > 1 && random->nextBool()) {
645*c8dee2aaSAndroid Build Coastguard Worker         aaType = GrAAType::kMSAA;
646*c8dee2aaSAndroid Build Coastguard Worker     }
647*c8dee2aaSAndroid Build Coastguard Worker     return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix,
648*c8dee2aaSAndroid Build Coastguard Worker                                true, aaType, bounds, GrGetRandomStencil(random, context));
649*c8dee2aaSAndroid Build Coastguard Worker }
650*c8dee2aaSAndroid Build Coastguard Worker 
651*c8dee2aaSAndroid Build Coastguard Worker #endif
652*c8dee2aaSAndroid Build Coastguard Worker 
653*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
654*c8dee2aaSAndroid Build Coastguard Worker 
655*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
656*c8dee2aaSAndroid Build Coastguard Worker 
internalDrawPath(skgpu::ganesh::SurfaceDrawContext * sdc,GrPaint && paint,GrAAType aaType,const GrUserStencilSettings & userStencilSettings,const GrClip * clip,const SkMatrix & viewMatrix,const GrStyledShape & shape,bool stencilOnly)657*c8dee2aaSAndroid Build Coastguard Worker bool DefaultPathRenderer::internalDrawPath(skgpu::ganesh::SurfaceDrawContext* sdc,
658*c8dee2aaSAndroid Build Coastguard Worker                                            GrPaint&& paint,
659*c8dee2aaSAndroid Build Coastguard Worker                                            GrAAType aaType,
660*c8dee2aaSAndroid Build Coastguard Worker                                            const GrUserStencilSettings& userStencilSettings,
661*c8dee2aaSAndroid Build Coastguard Worker                                            const GrClip* clip,
662*c8dee2aaSAndroid Build Coastguard Worker                                            const SkMatrix& viewMatrix,
663*c8dee2aaSAndroid Build Coastguard Worker                                            const GrStyledShape& shape,
664*c8dee2aaSAndroid Build Coastguard Worker                                            bool stencilOnly) {
665*c8dee2aaSAndroid Build Coastguard Worker     auto context = sdc->recordingContext();
666*c8dee2aaSAndroid Build Coastguard Worker 
667*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(GrAAType::kCoverage != aaType);
668*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
669*c8dee2aaSAndroid Build Coastguard Worker     shape.asPath(&path);
670*c8dee2aaSAndroid Build Coastguard Worker 
671*c8dee2aaSAndroid Build Coastguard Worker     SkScalar hairlineCoverage;
672*c8dee2aaSAndroid Build Coastguard Worker     uint8_t newCoverage = 0xff;
673*c8dee2aaSAndroid Build Coastguard Worker     bool isHairline = false;
674*c8dee2aaSAndroid Build Coastguard Worker     if (GrIsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) {
675*c8dee2aaSAndroid Build Coastguard Worker         newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
676*c8dee2aaSAndroid Build Coastguard Worker         isHairline = true;
677*c8dee2aaSAndroid Build Coastguard Worker     } else {
678*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(shape.style().isSimpleFill());
679*c8dee2aaSAndroid Build Coastguard Worker     }
680*c8dee2aaSAndroid Build Coastguard Worker 
681*c8dee2aaSAndroid Build Coastguard Worker     int                          passCount = 0;
682*c8dee2aaSAndroid Build Coastguard Worker     const GrUserStencilSettings* passes[2];
683*c8dee2aaSAndroid Build Coastguard Worker     bool                         reverse = false;
684*c8dee2aaSAndroid Build Coastguard Worker     bool                         lastPassIsBounds;
685*c8dee2aaSAndroid Build Coastguard Worker 
686*c8dee2aaSAndroid Build Coastguard Worker     if (isHairline) {
687*c8dee2aaSAndroid Build Coastguard Worker         passCount = 1;
688*c8dee2aaSAndroid Build Coastguard Worker         if (stencilOnly) {
689*c8dee2aaSAndroid Build Coastguard Worker             passes[0] = &gDirectToStencil;
690*c8dee2aaSAndroid Build Coastguard Worker         } else {
691*c8dee2aaSAndroid Build Coastguard Worker             passes[0] = &userStencilSettings;
692*c8dee2aaSAndroid Build Coastguard Worker         }
693*c8dee2aaSAndroid Build Coastguard Worker         lastPassIsBounds = false;
694*c8dee2aaSAndroid Build Coastguard Worker     } else {
695*c8dee2aaSAndroid Build Coastguard Worker         if (single_pass_shape(shape)) {
696*c8dee2aaSAndroid Build Coastguard Worker             passCount = 1;
697*c8dee2aaSAndroid Build Coastguard Worker             if (stencilOnly) {
698*c8dee2aaSAndroid Build Coastguard Worker                 passes[0] = &gDirectToStencil;
699*c8dee2aaSAndroid Build Coastguard Worker             } else {
700*c8dee2aaSAndroid Build Coastguard Worker                 passes[0] = &userStencilSettings;
701*c8dee2aaSAndroid Build Coastguard Worker             }
702*c8dee2aaSAndroid Build Coastguard Worker             lastPassIsBounds = false;
703*c8dee2aaSAndroid Build Coastguard Worker         } else {
704*c8dee2aaSAndroid Build Coastguard Worker             switch (path.getFillType()) {
705*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathFillType::kInverseEvenOdd:
706*c8dee2aaSAndroid Build Coastguard Worker                     reverse = true;
707*c8dee2aaSAndroid Build Coastguard Worker                     [[fallthrough]];
708*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathFillType::kEvenOdd:
709*c8dee2aaSAndroid Build Coastguard Worker                     passes[0] = &gEOStencilPass;
710*c8dee2aaSAndroid Build Coastguard Worker                     if (stencilOnly) {
711*c8dee2aaSAndroid Build Coastguard Worker                         passCount = 1;
712*c8dee2aaSAndroid Build Coastguard Worker                         lastPassIsBounds = false;
713*c8dee2aaSAndroid Build Coastguard Worker                     } else {
714*c8dee2aaSAndroid Build Coastguard Worker                         passCount = 2;
715*c8dee2aaSAndroid Build Coastguard Worker                         lastPassIsBounds = true;
716*c8dee2aaSAndroid Build Coastguard Worker                         if (reverse) {
717*c8dee2aaSAndroid Build Coastguard Worker                             passes[1] = &gInvEOColorPass;
718*c8dee2aaSAndroid Build Coastguard Worker                         } else {
719*c8dee2aaSAndroid Build Coastguard Worker                             passes[1] = &gEOColorPass;
720*c8dee2aaSAndroid Build Coastguard Worker                         }
721*c8dee2aaSAndroid Build Coastguard Worker                     }
722*c8dee2aaSAndroid Build Coastguard Worker                     break;
723*c8dee2aaSAndroid Build Coastguard Worker 
724*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathFillType::kInverseWinding:
725*c8dee2aaSAndroid Build Coastguard Worker                     reverse = true;
726*c8dee2aaSAndroid Build Coastguard Worker                     [[fallthrough]];
727*c8dee2aaSAndroid Build Coastguard Worker                 case SkPathFillType::kWinding:
728*c8dee2aaSAndroid Build Coastguard Worker                     passes[0] = &gWindStencilPass;
729*c8dee2aaSAndroid Build Coastguard Worker                     passCount = 2;
730*c8dee2aaSAndroid Build Coastguard Worker                     if (stencilOnly) {
731*c8dee2aaSAndroid Build Coastguard Worker                         lastPassIsBounds = false;
732*c8dee2aaSAndroid Build Coastguard Worker                         --passCount;
733*c8dee2aaSAndroid Build Coastguard Worker                     } else {
734*c8dee2aaSAndroid Build Coastguard Worker                         lastPassIsBounds = true;
735*c8dee2aaSAndroid Build Coastguard Worker                         if (reverse) {
736*c8dee2aaSAndroid Build Coastguard Worker                             passes[passCount-1] = &gInvWindColorPass;
737*c8dee2aaSAndroid Build Coastguard Worker                         } else {
738*c8dee2aaSAndroid Build Coastguard Worker                             passes[passCount-1] = &gWindColorPass;
739*c8dee2aaSAndroid Build Coastguard Worker                         }
740*c8dee2aaSAndroid Build Coastguard Worker                     }
741*c8dee2aaSAndroid Build Coastguard Worker                     break;
742*c8dee2aaSAndroid Build Coastguard Worker                 default:
743*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("Unknown path fFill!");
744*c8dee2aaSAndroid Build Coastguard Worker                     return false;
745*c8dee2aaSAndroid Build Coastguard Worker             }
746*c8dee2aaSAndroid Build Coastguard Worker         }
747*c8dee2aaSAndroid Build Coastguard Worker     }
748*c8dee2aaSAndroid Build Coastguard Worker 
749*c8dee2aaSAndroid Build Coastguard Worker     SkScalar tol = GrPathUtils::kDefaultTolerance;
750*c8dee2aaSAndroid Build Coastguard Worker     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
751*c8dee2aaSAndroid Build Coastguard Worker 
752*c8dee2aaSAndroid Build Coastguard Worker     SkRect devBounds;
753*c8dee2aaSAndroid Build Coastguard Worker     GetPathDevBounds(path, sdc->asRenderTargetProxy()->backingStoreDimensions(),
754*c8dee2aaSAndroid Build Coastguard Worker                      viewMatrix, &devBounds);
755*c8dee2aaSAndroid Build Coastguard Worker 
756*c8dee2aaSAndroid Build Coastguard Worker     for (int p = 0; p < passCount; ++p) {
757*c8dee2aaSAndroid Build Coastguard Worker         if (lastPassIsBounds && (p == passCount-1)) {
758*c8dee2aaSAndroid Build Coastguard Worker             SkRect bounds;
759*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix localMatrix = SkMatrix::I();
760*c8dee2aaSAndroid Build Coastguard Worker             if (reverse) {
761*c8dee2aaSAndroid Build Coastguard Worker                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
762*c8dee2aaSAndroid Build Coastguard Worker                 bounds = devBounds;
763*c8dee2aaSAndroid Build Coastguard Worker                 SkMatrix vmi;
764*c8dee2aaSAndroid Build Coastguard Worker                 // mapRect through persp matrix may not be correct
765*c8dee2aaSAndroid Build Coastguard Worker                 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
766*c8dee2aaSAndroid Build Coastguard Worker                     vmi.mapRect(&bounds);
767*c8dee2aaSAndroid Build Coastguard Worker                 } else {
768*c8dee2aaSAndroid Build Coastguard Worker                     if (!viewMatrix.invert(&localMatrix)) {
769*c8dee2aaSAndroid Build Coastguard Worker                         return false;
770*c8dee2aaSAndroid Build Coastguard Worker                     }
771*c8dee2aaSAndroid Build Coastguard Worker                 }
772*c8dee2aaSAndroid Build Coastguard Worker             } else {
773*c8dee2aaSAndroid Build Coastguard Worker                 bounds = path.getBounds();
774*c8dee2aaSAndroid Build Coastguard Worker             }
775*c8dee2aaSAndroid Build Coastguard Worker             const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
776*c8dee2aaSAndroid Build Coastguard Worker                                                                                viewMatrix;
777*c8dee2aaSAndroid Build Coastguard Worker             // This is a non-coverage aa rect op since we assert aaType != kCoverage at the start
778*c8dee2aaSAndroid Build Coastguard Worker             assert_alive(paint);
779*c8dee2aaSAndroid Build Coastguard Worker             sdc->stencilRect(clip, passes[p], std::move(paint),
780*c8dee2aaSAndroid Build Coastguard Worker                              GrAA(aaType == GrAAType::kMSAA), viewM, bounds,
781*c8dee2aaSAndroid Build Coastguard Worker                              &localMatrix);
782*c8dee2aaSAndroid Build Coastguard Worker         } else {
783*c8dee2aaSAndroid Build Coastguard Worker             bool stencilPass = stencilOnly || passCount > 1;
784*c8dee2aaSAndroid Build Coastguard Worker             GrOp::Owner op;
785*c8dee2aaSAndroid Build Coastguard Worker             if (stencilPass) {
786*c8dee2aaSAndroid Build Coastguard Worker                 GrPaint stencilPaint;
787*c8dee2aaSAndroid Build Coastguard Worker                 stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
788*c8dee2aaSAndroid Build Coastguard Worker                 op = DefaultPathOp::Make(context, std::move(stencilPaint), path, srcSpaceTol,
789*c8dee2aaSAndroid Build Coastguard Worker                                          newCoverage, viewMatrix, isHairline, aaType, devBounds,
790*c8dee2aaSAndroid Build Coastguard Worker                                          passes[p]);
791*c8dee2aaSAndroid Build Coastguard Worker             } else {
792*c8dee2aaSAndroid Build Coastguard Worker                 assert_alive(paint);
793*c8dee2aaSAndroid Build Coastguard Worker                 op = DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, newCoverage,
794*c8dee2aaSAndroid Build Coastguard Worker                                          viewMatrix, isHairline, aaType, devBounds, passes[p]);
795*c8dee2aaSAndroid Build Coastguard Worker             }
796*c8dee2aaSAndroid Build Coastguard Worker             sdc->addDrawOp(clip, std::move(op));
797*c8dee2aaSAndroid Build Coastguard Worker         }
798*c8dee2aaSAndroid Build Coastguard Worker     }
799*c8dee2aaSAndroid Build Coastguard Worker     return true;
800*c8dee2aaSAndroid Build Coastguard Worker }
801*c8dee2aaSAndroid Build Coastguard Worker 
802*c8dee2aaSAndroid Build Coastguard Worker PathRenderer::StencilSupport
onGetStencilSupport(const GrStyledShape & shape) const803*c8dee2aaSAndroid Build Coastguard Worker DefaultPathRenderer::onGetStencilSupport(const GrStyledShape& shape) const {
804*c8dee2aaSAndroid Build Coastguard Worker     if (single_pass_shape(shape)) {
805*c8dee2aaSAndroid Build Coastguard Worker         return kNoRestriction_StencilSupport;
806*c8dee2aaSAndroid Build Coastguard Worker     } else {
807*c8dee2aaSAndroid Build Coastguard Worker         return kStencilOnly_StencilSupport;
808*c8dee2aaSAndroid Build Coastguard Worker     }
809*c8dee2aaSAndroid Build Coastguard Worker }
810*c8dee2aaSAndroid Build Coastguard Worker 
onCanDrawPath(const CanDrawPathArgs & args) const811*c8dee2aaSAndroid Build Coastguard Worker PathRenderer::CanDrawPath DefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
812*c8dee2aaSAndroid Build Coastguard Worker     bool isHairline = GrIsStrokeHairlineOrEquivalent(
813*c8dee2aaSAndroid Build Coastguard Worker             args.fShape->style(), *args.fViewMatrix, nullptr);
814*c8dee2aaSAndroid Build Coastguard Worker     // If we aren't a single_pass_shape or hairline, we require stencil buffers.
815*c8dee2aaSAndroid Build Coastguard Worker     if (!(single_pass_shape(*args.fShape) || isHairline) &&
816*c8dee2aaSAndroid Build Coastguard Worker         !args.fProxy->canUseStencil(*args.fCaps)) {
817*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
818*c8dee2aaSAndroid Build Coastguard Worker     }
819*c8dee2aaSAndroid Build Coastguard Worker     // If antialiasing is required, we only support MSAA.
820*c8dee2aaSAndroid Build Coastguard Worker     if (GrAAType::kNone != args.fAAType && GrAAType::kMSAA != args.fAAType) {
821*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
822*c8dee2aaSAndroid Build Coastguard Worker     }
823*c8dee2aaSAndroid Build Coastguard Worker     // This can draw any path with any simple fill style.
824*c8dee2aaSAndroid Build Coastguard Worker     if (!args.fShape->style().isSimpleFill() && !isHairline) {
825*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
826*c8dee2aaSAndroid Build Coastguard Worker     }
827*c8dee2aaSAndroid Build Coastguard Worker     // Don't try to draw hairlines with DefaultPathRenderer if avoidLineDraws is true.
828*c8dee2aaSAndroid Build Coastguard Worker     // Alternatively, we could try to implement hairline draws without line primitives in
829*c8dee2aaSAndroid Build Coastguard Worker     // DefaultPathRenderer, but this is simpler.
830*c8dee2aaSAndroid Build Coastguard Worker     if (args.fCaps->avoidLineDraws() && isHairline) {
831*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
832*c8dee2aaSAndroid Build Coastguard Worker     }
833*c8dee2aaSAndroid Build Coastguard Worker     // This is the fallback renderer for when a path is too complicated for the others to draw.
834*c8dee2aaSAndroid Build Coastguard Worker     return CanDrawPath::kAsBackup;
835*c8dee2aaSAndroid Build Coastguard Worker }
836*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPath(const DrawPathArgs & args)837*c8dee2aaSAndroid Build Coastguard Worker bool DefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
838*c8dee2aaSAndroid Build Coastguard Worker     GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
839*c8dee2aaSAndroid Build Coastguard Worker                               "DefaultPathRenderer::onDrawPath");
840*c8dee2aaSAndroid Build Coastguard Worker     GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone;
841*c8dee2aaSAndroid Build Coastguard Worker 
842*c8dee2aaSAndroid Build Coastguard Worker     return this->internalDrawPath(
843*c8dee2aaSAndroid Build Coastguard Worker             args.fSurfaceDrawContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings,
844*c8dee2aaSAndroid Build Coastguard Worker             args.fClip, *args.fViewMatrix, *args.fShape, false);
845*c8dee2aaSAndroid Build Coastguard Worker }
846*c8dee2aaSAndroid Build Coastguard Worker 
onStencilPath(const StencilPathArgs & args)847*c8dee2aaSAndroid Build Coastguard Worker void DefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
848*c8dee2aaSAndroid Build Coastguard Worker     GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
849*c8dee2aaSAndroid Build Coastguard Worker                               "DefaultPathRenderer::onStencilPath");
850*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!args.fShape->inverseFilled());
851*c8dee2aaSAndroid Build Coastguard Worker 
852*c8dee2aaSAndroid Build Coastguard Worker     GrPaint paint;
853*c8dee2aaSAndroid Build Coastguard Worker     paint.setXPFactory(GrDisableColorXPFactory::Get());
854*c8dee2aaSAndroid Build Coastguard Worker 
855*c8dee2aaSAndroid Build Coastguard Worker     auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
856*c8dee2aaSAndroid Build Coastguard Worker 
857*c8dee2aaSAndroid Build Coastguard Worker     this->internalDrawPath(
858*c8dee2aaSAndroid Build Coastguard Worker             args.fSurfaceDrawContext, std::move(paint), aaType, GrUserStencilSettings::kUnused,
859*c8dee2aaSAndroid Build Coastguard Worker             args.fClip, *args.fViewMatrix, *args.fShape, true);
860*c8dee2aaSAndroid Build Coastguard Worker }
861*c8dee2aaSAndroid Build Coastguard Worker 
862*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh
863