xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/AAConvexPathRenderer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 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/AAConvexPathRenderer.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/SkPoint.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTLazy.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/core/SkPathEnums.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathPriv.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPointPriv.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/KeyBuilder.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAuditTrail.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpTest.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorUnitTest.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSimpleMesh.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrStyle.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrPathUtils.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrStyledShape.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
56*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrOp.h"
59*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
62*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
63*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
64*c8dee2aaSAndroid Build Coastguard Worker #endif
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
67*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
68*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
69*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
72*c8dee2aaSAndroid Build Coastguard Worker class GrGLSLProgramDataManager;
73*c8dee2aaSAndroid Build Coastguard Worker class GrGLSLUniformHandler;
74*c8dee2aaSAndroid Build Coastguard Worker class GrSurfaceProxyView;
75*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
76*c8dee2aaSAndroid Build Coastguard Worker struct GrUserStencilSettings;
77*c8dee2aaSAndroid Build Coastguard Worker struct SkRect;
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker namespace {
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker struct Segment {
86*c8dee2aaSAndroid Build Coastguard Worker     enum {
87*c8dee2aaSAndroid Build Coastguard Worker         kLine = 0,
88*c8dee2aaSAndroid Build Coastguard Worker         kQuad = 1,
89*c8dee2aaSAndroid Build Coastguard Worker     } fType;
90*c8dee2aaSAndroid Build Coastguard Worker     // These enum values are assumed in member functions below.
91*c8dee2aaSAndroid Build Coastguard Worker     static_assert(0 == kLine && 1 == kQuad);
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker     // line uses one pt, quad uses 2 pts
94*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fPts[2];
95*c8dee2aaSAndroid Build Coastguard Worker     // normal to edge ending at each pt
96*c8dee2aaSAndroid Build Coastguard Worker     SkVector fNorms[2];
97*c8dee2aaSAndroid Build Coastguard Worker     // is the corner where the previous segment meets this segment
98*c8dee2aaSAndroid Build Coastguard Worker     // sharp. If so, fMid is a normalized bisector facing outward.
99*c8dee2aaSAndroid Build Coastguard Worker     SkVector fMid;
100*c8dee2aaSAndroid Build Coastguard Worker 
countPointsskgpu::ganesh::__anon033b8e600111::Segment101*c8dee2aaSAndroid Build Coastguard Worker     int countPoints() const {
102*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fType == kLine || fType == kQuad);
103*c8dee2aaSAndroid Build Coastguard Worker         return fType + 1;
104*c8dee2aaSAndroid Build Coastguard Worker     }
endPtskgpu::ganesh::__anon033b8e600111::Segment105*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint& endPt() const {
106*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fType == kLine || fType == kQuad);
107*c8dee2aaSAndroid Build Coastguard Worker         return fPts[fType];
108*c8dee2aaSAndroid Build Coastguard Worker     }
endNormskgpu::ganesh::__anon033b8e600111::Segment109*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint& endNorm() const {
110*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fType == kLine || fType == kQuad);
111*c8dee2aaSAndroid Build Coastguard Worker         return fNorms[fType];
112*c8dee2aaSAndroid Build Coastguard Worker     }
113*c8dee2aaSAndroid Build Coastguard Worker };
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker typedef TArray<Segment, true> SegmentArray;
116*c8dee2aaSAndroid Build Coastguard Worker 
center_of_mass(const SegmentArray & segments,SkPoint * c)117*c8dee2aaSAndroid Build Coastguard Worker bool center_of_mass(const SegmentArray& segments, SkPoint* c) {
118*c8dee2aaSAndroid Build Coastguard Worker     SkScalar area = 0;
119*c8dee2aaSAndroid Build Coastguard Worker     SkPoint center = {0, 0};
120*c8dee2aaSAndroid Build Coastguard Worker     int count = segments.size();
121*c8dee2aaSAndroid Build Coastguard Worker     if (count <= 0) {
122*c8dee2aaSAndroid Build Coastguard Worker         return false;
123*c8dee2aaSAndroid Build Coastguard Worker     }
124*c8dee2aaSAndroid Build Coastguard Worker     SkPoint p0 = {0, 0};
125*c8dee2aaSAndroid Build Coastguard Worker     if (count > 2) {
126*c8dee2aaSAndroid Build Coastguard Worker         // We translate the polygon so that the first point is at the origin.
127*c8dee2aaSAndroid Build Coastguard Worker         // This avoids some precision issues with small area polygons far away
128*c8dee2aaSAndroid Build Coastguard Worker         // from the origin.
129*c8dee2aaSAndroid Build Coastguard Worker         p0 = segments[0].endPt();
130*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pi;
131*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pj;
132*c8dee2aaSAndroid Build Coastguard Worker         // the first and last iteration of the below loop would compute
133*c8dee2aaSAndroid Build Coastguard Worker         // zeros since the starting / ending point is (0,0). So instead we start
134*c8dee2aaSAndroid Build Coastguard Worker         // at i=1 and make the last iteration i=count-2.
135*c8dee2aaSAndroid Build Coastguard Worker         pj = segments[1].endPt() - p0;
136*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 1; i < count - 1; ++i) {
137*c8dee2aaSAndroid Build Coastguard Worker             pi = pj;
138*c8dee2aaSAndroid Build Coastguard Worker             pj = segments[i + 1].endPt() - p0;
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker             SkScalar t = SkPoint::CrossProduct(pi, pj);
141*c8dee2aaSAndroid Build Coastguard Worker             area += t;
142*c8dee2aaSAndroid Build Coastguard Worker             center.fX += (pi.fX + pj.fX) * t;
143*c8dee2aaSAndroid Build Coastguard Worker             center.fY += (pi.fY + pj.fY) * t;
144*c8dee2aaSAndroid Build Coastguard Worker         }
145*c8dee2aaSAndroid Build Coastguard Worker     }
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker     // If the poly has no area then we instead return the average of
148*c8dee2aaSAndroid Build Coastguard Worker     // its points.
149*c8dee2aaSAndroid Build Coastguard Worker     if (SkScalarNearlyZero(area)) {
150*c8dee2aaSAndroid Build Coastguard Worker         SkPoint avg;
151*c8dee2aaSAndroid Build Coastguard Worker         avg.set(0, 0);
152*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < count; ++i) {
153*c8dee2aaSAndroid Build Coastguard Worker             const SkPoint& pt = segments[i].endPt();
154*c8dee2aaSAndroid Build Coastguard Worker             avg.fX += pt.fX;
155*c8dee2aaSAndroid Build Coastguard Worker             avg.fY += pt.fY;
156*c8dee2aaSAndroid Build Coastguard Worker         }
157*c8dee2aaSAndroid Build Coastguard Worker         SkScalar denom = SK_Scalar1 / count;
158*c8dee2aaSAndroid Build Coastguard Worker         avg.scale(denom);
159*c8dee2aaSAndroid Build Coastguard Worker         *c = avg;
160*c8dee2aaSAndroid Build Coastguard Worker     } else {
161*c8dee2aaSAndroid Build Coastguard Worker         area *= 3;
162*c8dee2aaSAndroid Build Coastguard Worker         area = SkScalarInvert(area);
163*c8dee2aaSAndroid Build Coastguard Worker         center.scale(area);
164*c8dee2aaSAndroid Build Coastguard Worker         // undo the translate of p0 to the origin.
165*c8dee2aaSAndroid Build Coastguard Worker         *c = center + p0;
166*c8dee2aaSAndroid Build Coastguard Worker     }
167*c8dee2aaSAndroid Build Coastguard Worker     return !SkIsNaN(c->fX) && !SkIsNaN(c->fY) && c->isFinite();
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker 
compute_vectors(SegmentArray * segments,SkPoint * fanPt,SkPathFirstDirection dir,int * vCount,int * iCount)170*c8dee2aaSAndroid Build Coastguard Worker bool compute_vectors(SegmentArray* segments,
171*c8dee2aaSAndroid Build Coastguard Worker                      SkPoint* fanPt,
172*c8dee2aaSAndroid Build Coastguard Worker                      SkPathFirstDirection dir,
173*c8dee2aaSAndroid Build Coastguard Worker                      int* vCount,
174*c8dee2aaSAndroid Build Coastguard Worker                      int* iCount) {
175*c8dee2aaSAndroid Build Coastguard Worker     if (!center_of_mass(*segments, fanPt)) {
176*c8dee2aaSAndroid Build Coastguard Worker         return false;
177*c8dee2aaSAndroid Build Coastguard Worker     }
178*c8dee2aaSAndroid Build Coastguard Worker     int count = segments->size();
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker     // Make the normals point towards the outside
181*c8dee2aaSAndroid Build Coastguard Worker     SkPointPriv::Side normSide;
182*c8dee2aaSAndroid Build Coastguard Worker     if (dir == SkPathFirstDirection::kCCW) {
183*c8dee2aaSAndroid Build Coastguard Worker         normSide = SkPointPriv::kRight_Side;
184*c8dee2aaSAndroid Build Coastguard Worker     } else {
185*c8dee2aaSAndroid Build Coastguard Worker         normSide = SkPointPriv::kLeft_Side;
186*c8dee2aaSAndroid Build Coastguard Worker     }
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker     int64_t vCount64 = 0;
189*c8dee2aaSAndroid Build Coastguard Worker     int64_t iCount64 = 0;
190*c8dee2aaSAndroid Build Coastguard Worker     // compute normals at all points
191*c8dee2aaSAndroid Build Coastguard Worker     for (int a = 0; a < count; ++a) {
192*c8dee2aaSAndroid Build Coastguard Worker         Segment& sega = (*segments)[a];
193*c8dee2aaSAndroid Build Coastguard Worker         int b = (a + 1) % count;
194*c8dee2aaSAndroid Build Coastguard Worker         Segment& segb = (*segments)[b];
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker         const SkPoint* prevPt = &sega.endPt();
197*c8dee2aaSAndroid Build Coastguard Worker         int n = segb.countPoints();
198*c8dee2aaSAndroid Build Coastguard Worker         for (int p = 0; p < n; ++p) {
199*c8dee2aaSAndroid Build Coastguard Worker             segb.fNorms[p] = segb.fPts[p] - *prevPt;
200*c8dee2aaSAndroid Build Coastguard Worker             segb.fNorms[p].normalize();
201*c8dee2aaSAndroid Build Coastguard Worker             segb.fNorms[p] = SkPointPriv::MakeOrthog(segb.fNorms[p], normSide);
202*c8dee2aaSAndroid Build Coastguard Worker             prevPt = &segb.fPts[p];
203*c8dee2aaSAndroid Build Coastguard Worker         }
204*c8dee2aaSAndroid Build Coastguard Worker         if (Segment::kLine == segb.fType) {
205*c8dee2aaSAndroid Build Coastguard Worker             vCount64 += 5;
206*c8dee2aaSAndroid Build Coastguard Worker             iCount64 += 9;
207*c8dee2aaSAndroid Build Coastguard Worker         } else {
208*c8dee2aaSAndroid Build Coastguard Worker             vCount64 += 6;
209*c8dee2aaSAndroid Build Coastguard Worker             iCount64 += 12;
210*c8dee2aaSAndroid Build Coastguard Worker         }
211*c8dee2aaSAndroid Build Coastguard Worker     }
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker     // compute mid-vectors where segments meet. TODO: Detect shallow corners
214*c8dee2aaSAndroid Build Coastguard Worker     // and leave out the wedges and close gaps by stitching segments together.
215*c8dee2aaSAndroid Build Coastguard Worker     for (int a = 0; a < count; ++a) {
216*c8dee2aaSAndroid Build Coastguard Worker         const Segment& sega = (*segments)[a];
217*c8dee2aaSAndroid Build Coastguard Worker         int b = (a + 1) % count;
218*c8dee2aaSAndroid Build Coastguard Worker         Segment& segb = (*segments)[b];
219*c8dee2aaSAndroid Build Coastguard Worker         segb.fMid = segb.fNorms[0] + sega.endNorm();
220*c8dee2aaSAndroid Build Coastguard Worker         segb.fMid.normalize();
221*c8dee2aaSAndroid Build Coastguard Worker         // corner wedges
222*c8dee2aaSAndroid Build Coastguard Worker         vCount64 += 4;
223*c8dee2aaSAndroid Build Coastguard Worker         iCount64 += 6;
224*c8dee2aaSAndroid Build Coastguard Worker     }
225*c8dee2aaSAndroid Build Coastguard Worker     if (vCount64 > SK_MaxS32 || iCount64 > SK_MaxS32) {
226*c8dee2aaSAndroid Build Coastguard Worker         return false;
227*c8dee2aaSAndroid Build Coastguard Worker     }
228*c8dee2aaSAndroid Build Coastguard Worker     *vCount = vCount64;
229*c8dee2aaSAndroid Build Coastguard Worker     *iCount = iCount64;
230*c8dee2aaSAndroid Build Coastguard Worker     return true;
231*c8dee2aaSAndroid Build Coastguard Worker }
232*c8dee2aaSAndroid Build Coastguard Worker 
233*c8dee2aaSAndroid Build Coastguard Worker struct DegenerateTestData {
isDegenerateskgpu::ganesh::__anon033b8e600111::DegenerateTestData234*c8dee2aaSAndroid Build Coastguard Worker     bool isDegenerate() const { return Stage::kNonDegenerate != fStage; }
235*c8dee2aaSAndroid Build Coastguard Worker     enum class Stage {
236*c8dee2aaSAndroid Build Coastguard Worker         kInitial,
237*c8dee2aaSAndroid Build Coastguard Worker         kPoint,
238*c8dee2aaSAndroid Build Coastguard Worker         kLine,
239*c8dee2aaSAndroid Build Coastguard Worker         kNonDegenerate,
240*c8dee2aaSAndroid Build Coastguard Worker     };
241*c8dee2aaSAndroid Build Coastguard Worker     Stage       fStage = Stage::kInitial;
242*c8dee2aaSAndroid Build Coastguard Worker     SkPoint     fFirstPoint;
243*c8dee2aaSAndroid Build Coastguard Worker     SkVector    fLineNormal;
244*c8dee2aaSAndroid Build Coastguard Worker     SkScalar    fLineC;
245*c8dee2aaSAndroid Build Coastguard Worker };
246*c8dee2aaSAndroid Build Coastguard Worker 
247*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar kClose = (SK_Scalar1 / 16);
248*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar kCloseSqd = kClose * kClose;
249*c8dee2aaSAndroid Build Coastguard Worker 
update_degenerate_test(DegenerateTestData * data,const SkPoint & pt)250*c8dee2aaSAndroid Build Coastguard Worker void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
251*c8dee2aaSAndroid Build Coastguard Worker     switch (data->fStage) {
252*c8dee2aaSAndroid Build Coastguard Worker         case DegenerateTestData::Stage::kInitial:
253*c8dee2aaSAndroid Build Coastguard Worker             data->fFirstPoint = pt;
254*c8dee2aaSAndroid Build Coastguard Worker             data->fStage = DegenerateTestData::Stage::kPoint;
255*c8dee2aaSAndroid Build Coastguard Worker             break;
256*c8dee2aaSAndroid Build Coastguard Worker         case DegenerateTestData::Stage::kPoint:
257*c8dee2aaSAndroid Build Coastguard Worker             if (SkPointPriv::DistanceToSqd(pt, data->fFirstPoint) > kCloseSqd) {
258*c8dee2aaSAndroid Build Coastguard Worker                 data->fLineNormal = pt - data->fFirstPoint;
259*c8dee2aaSAndroid Build Coastguard Worker                 data->fLineNormal.normalize();
260*c8dee2aaSAndroid Build Coastguard Worker                 data->fLineNormal = SkPointPriv::MakeOrthog(data->fLineNormal);
261*c8dee2aaSAndroid Build Coastguard Worker                 data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
262*c8dee2aaSAndroid Build Coastguard Worker                 data->fStage = DegenerateTestData::Stage::kLine;
263*c8dee2aaSAndroid Build Coastguard Worker             }
264*c8dee2aaSAndroid Build Coastguard Worker             break;
265*c8dee2aaSAndroid Build Coastguard Worker         case DegenerateTestData::Stage::kLine:
266*c8dee2aaSAndroid Build Coastguard Worker             if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
267*c8dee2aaSAndroid Build Coastguard Worker                 data->fStage = DegenerateTestData::Stage::kNonDegenerate;
268*c8dee2aaSAndroid Build Coastguard Worker             }
269*c8dee2aaSAndroid Build Coastguard Worker             break;
270*c8dee2aaSAndroid Build Coastguard Worker         case DegenerateTestData::Stage::kNonDegenerate:
271*c8dee2aaSAndroid Build Coastguard Worker             break;
272*c8dee2aaSAndroid Build Coastguard Worker         default:
273*c8dee2aaSAndroid Build Coastguard Worker             SK_ABORT("Unexpected degenerate test stage.");
274*c8dee2aaSAndroid Build Coastguard Worker     }
275*c8dee2aaSAndroid Build Coastguard Worker }
276*c8dee2aaSAndroid Build Coastguard Worker 
get_direction(const SkPath & path,const SkMatrix & m,SkPathFirstDirection * dir)277*c8dee2aaSAndroid Build Coastguard Worker inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPathFirstDirection* dir) {
278*c8dee2aaSAndroid Build Coastguard Worker     // At this point, we've already returned true from canDraw(), which checked that the path's
279*c8dee2aaSAndroid Build Coastguard Worker     // direction could be determined, so this should just be fetching the cached direction.
280*c8dee2aaSAndroid Build Coastguard Worker     // However, if perspective is involved, we're operating on a transformed path, which may no
281*c8dee2aaSAndroid Build Coastguard Worker     // longer have a computable direction.
282*c8dee2aaSAndroid Build Coastguard Worker     *dir = SkPathPriv::ComputeFirstDirection(path);
283*c8dee2aaSAndroid Build Coastguard Worker     if (*dir == SkPathFirstDirection::kUnknown) {
284*c8dee2aaSAndroid Build Coastguard Worker         return false;
285*c8dee2aaSAndroid Build Coastguard Worker     }
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker     // check whether m reverses the orientation
288*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!m.hasPerspective());
289*c8dee2aaSAndroid Build Coastguard Worker     SkScalar det2x2 = m.get(SkMatrix::kMScaleX) * m.get(SkMatrix::kMScaleY) -
290*c8dee2aaSAndroid Build Coastguard Worker                       m.get(SkMatrix::kMSkewX)  * m.get(SkMatrix::kMSkewY);
291*c8dee2aaSAndroid Build Coastguard Worker     if (det2x2 < 0) {
292*c8dee2aaSAndroid Build Coastguard Worker         *dir = SkPathPriv::OppositeFirstDirection(*dir);
293*c8dee2aaSAndroid Build Coastguard Worker     }
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker     return true;
296*c8dee2aaSAndroid Build Coastguard Worker }
297*c8dee2aaSAndroid Build Coastguard Worker 
add_line_to_segment(const SkPoint & pt,SegmentArray * segments)298*c8dee2aaSAndroid Build Coastguard Worker inline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments) {
299*c8dee2aaSAndroid Build Coastguard Worker     segments->push_back();
300*c8dee2aaSAndroid Build Coastguard Worker     segments->back().fType = Segment::kLine;
301*c8dee2aaSAndroid Build Coastguard Worker     segments->back().fPts[0] = pt;
302*c8dee2aaSAndroid Build Coastguard Worker }
303*c8dee2aaSAndroid Build Coastguard Worker 
add_quad_segment(const SkPoint pts[3],SegmentArray * segments)304*c8dee2aaSAndroid Build Coastguard Worker inline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments) {
305*c8dee2aaSAndroid Build Coastguard Worker     if (SkPointPriv::DistanceToLineSegmentBetweenSqd(pts[1], pts[0], pts[2]) < kCloseSqd) {
306*c8dee2aaSAndroid Build Coastguard Worker         if (pts[0] != pts[2]) {
307*c8dee2aaSAndroid Build Coastguard Worker             add_line_to_segment(pts[2], segments);
308*c8dee2aaSAndroid Build Coastguard Worker         }
309*c8dee2aaSAndroid Build Coastguard Worker     } else {
310*c8dee2aaSAndroid Build Coastguard Worker         segments->push_back();
311*c8dee2aaSAndroid Build Coastguard Worker         segments->back().fType = Segment::kQuad;
312*c8dee2aaSAndroid Build Coastguard Worker         segments->back().fPts[0] = pts[1];
313*c8dee2aaSAndroid Build Coastguard Worker         segments->back().fPts[1] = pts[2];
314*c8dee2aaSAndroid Build Coastguard Worker     }
315*c8dee2aaSAndroid Build Coastguard Worker }
316*c8dee2aaSAndroid Build Coastguard Worker 
add_cubic_segments(const SkPoint pts[4],SkPathFirstDirection dir,SegmentArray * segments)317*c8dee2aaSAndroid Build Coastguard Worker inline void add_cubic_segments(const SkPoint pts[4],
318*c8dee2aaSAndroid Build Coastguard Worker                                SkPathFirstDirection dir,
319*c8dee2aaSAndroid Build Coastguard Worker                                SegmentArray* segments) {
320*c8dee2aaSAndroid Build Coastguard Worker     STArray<15, SkPoint, true> quads;
321*c8dee2aaSAndroid Build Coastguard Worker     GrPathUtils::convertCubicToQuadsConstrainToTangents(pts, SK_Scalar1, dir, &quads);
322*c8dee2aaSAndroid Build Coastguard Worker     int count = quads.size();
323*c8dee2aaSAndroid Build Coastguard Worker     for (int q = 0; q < count; q += 3) {
324*c8dee2aaSAndroid Build Coastguard Worker         add_quad_segment(&quads[q], segments);
325*c8dee2aaSAndroid Build Coastguard Worker     }
326*c8dee2aaSAndroid Build Coastguard Worker }
327*c8dee2aaSAndroid Build Coastguard Worker 
get_segments(const SkPath & path,const SkMatrix & m,SegmentArray * segments,SkPoint * fanPt,int * vCount,int * iCount)328*c8dee2aaSAndroid Build Coastguard Worker bool get_segments(const SkPath& path,
329*c8dee2aaSAndroid Build Coastguard Worker                   const SkMatrix& m,
330*c8dee2aaSAndroid Build Coastguard Worker                   SegmentArray* segments,
331*c8dee2aaSAndroid Build Coastguard Worker                   SkPoint* fanPt,
332*c8dee2aaSAndroid Build Coastguard Worker                   int* vCount,
333*c8dee2aaSAndroid Build Coastguard Worker                   int* iCount) {
334*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Iter iter(path, true);
335*c8dee2aaSAndroid Build Coastguard Worker     // This renderer over-emphasizes very thin path regions. We use the distance
336*c8dee2aaSAndroid Build Coastguard Worker     // to the path from the sample to compute coverage. Every pixel intersected
337*c8dee2aaSAndroid Build Coastguard Worker     // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
338*c8dee2aaSAndroid Build Coastguard Worker     // notice that the sample may be close to a very thin area of the path and
339*c8dee2aaSAndroid Build Coastguard Worker     // thus should be very light. This is particularly egregious for degenerate
340*c8dee2aaSAndroid Build Coastguard Worker     // line paths. We detect paths that are very close to a line (zero area) and
341*c8dee2aaSAndroid Build Coastguard Worker     // draw nothing.
342*c8dee2aaSAndroid Build Coastguard Worker     DegenerateTestData degenerateData;
343*c8dee2aaSAndroid Build Coastguard Worker     SkPathFirstDirection dir;
344*c8dee2aaSAndroid Build Coastguard Worker     if (!get_direction(path, m, &dir)) {
345*c8dee2aaSAndroid Build Coastguard Worker         return false;
346*c8dee2aaSAndroid Build Coastguard Worker     }
347*c8dee2aaSAndroid Build Coastguard Worker 
348*c8dee2aaSAndroid Build Coastguard Worker     for (;;) {
349*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[4];
350*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Verb verb = iter.next(pts);
351*c8dee2aaSAndroid Build Coastguard Worker         switch (verb) {
352*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kMove_Verb:
353*c8dee2aaSAndroid Build Coastguard Worker                 m.mapPoints(pts, 1);
354*c8dee2aaSAndroid Build Coastguard Worker                 update_degenerate_test(&degenerateData, pts[0]);
355*c8dee2aaSAndroid Build Coastguard Worker                 break;
356*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kLine_Verb: {
357*c8dee2aaSAndroid Build Coastguard Worker                 if (!SkPathPriv::AllPointsEq(pts, 2)) {
358*c8dee2aaSAndroid Build Coastguard Worker                     m.mapPoints(&pts[1], 1);
359*c8dee2aaSAndroid Build Coastguard Worker                     update_degenerate_test(&degenerateData, pts[1]);
360*c8dee2aaSAndroid Build Coastguard Worker                     add_line_to_segment(pts[1], segments);
361*c8dee2aaSAndroid Build Coastguard Worker                 }
362*c8dee2aaSAndroid Build Coastguard Worker                 break;
363*c8dee2aaSAndroid Build Coastguard Worker             }
364*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kQuad_Verb:
365*c8dee2aaSAndroid Build Coastguard Worker                 if (!SkPathPriv::AllPointsEq(pts, 3)) {
366*c8dee2aaSAndroid Build Coastguard Worker                     m.mapPoints(pts, 3);
367*c8dee2aaSAndroid Build Coastguard Worker                     update_degenerate_test(&degenerateData, pts[1]);
368*c8dee2aaSAndroid Build Coastguard Worker                     update_degenerate_test(&degenerateData, pts[2]);
369*c8dee2aaSAndroid Build Coastguard Worker                     add_quad_segment(pts, segments);
370*c8dee2aaSAndroid Build Coastguard Worker                 }
371*c8dee2aaSAndroid Build Coastguard Worker                 break;
372*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kConic_Verb: {
373*c8dee2aaSAndroid Build Coastguard Worker                 if (!SkPathPriv::AllPointsEq(pts, 3)) {
374*c8dee2aaSAndroid Build Coastguard Worker                     m.mapPoints(pts, 3);
375*c8dee2aaSAndroid Build Coastguard Worker                     SkScalar weight = iter.conicWeight();
376*c8dee2aaSAndroid Build Coastguard Worker                     SkAutoConicToQuads converter;
377*c8dee2aaSAndroid Build Coastguard Worker                     const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
378*c8dee2aaSAndroid Build Coastguard Worker                     for (int i = 0; i < converter.countQuads(); ++i) {
379*c8dee2aaSAndroid Build Coastguard Worker                         update_degenerate_test(&degenerateData, quadPts[2*i + 1]);
380*c8dee2aaSAndroid Build Coastguard Worker                         update_degenerate_test(&degenerateData, quadPts[2*i + 2]);
381*c8dee2aaSAndroid Build Coastguard Worker                         add_quad_segment(quadPts + 2*i, segments);
382*c8dee2aaSAndroid Build Coastguard Worker                     }
383*c8dee2aaSAndroid Build Coastguard Worker                 }
384*c8dee2aaSAndroid Build Coastguard Worker                 break;
385*c8dee2aaSAndroid Build Coastguard Worker             }
386*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kCubic_Verb: {
387*c8dee2aaSAndroid Build Coastguard Worker                 if (!SkPathPriv::AllPointsEq(pts, 4)) {
388*c8dee2aaSAndroid Build Coastguard Worker                     m.mapPoints(pts, 4);
389*c8dee2aaSAndroid Build Coastguard Worker                     update_degenerate_test(&degenerateData, pts[1]);
390*c8dee2aaSAndroid Build Coastguard Worker                     update_degenerate_test(&degenerateData, pts[2]);
391*c8dee2aaSAndroid Build Coastguard Worker                     update_degenerate_test(&degenerateData, pts[3]);
392*c8dee2aaSAndroid Build Coastguard Worker                     add_cubic_segments(pts, dir, segments);
393*c8dee2aaSAndroid Build Coastguard Worker                 }
394*c8dee2aaSAndroid Build Coastguard Worker                 break;
395*c8dee2aaSAndroid Build Coastguard Worker             }
396*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kDone_Verb:
397*c8dee2aaSAndroid Build Coastguard Worker                 if (degenerateData.isDegenerate()) {
398*c8dee2aaSAndroid Build Coastguard Worker                     return false;
399*c8dee2aaSAndroid Build Coastguard Worker                 } else {
400*c8dee2aaSAndroid Build Coastguard Worker                     return compute_vectors(segments, fanPt, dir, vCount, iCount);
401*c8dee2aaSAndroid Build Coastguard Worker                 }
402*c8dee2aaSAndroid Build Coastguard Worker             default:
403*c8dee2aaSAndroid Build Coastguard Worker                 break;
404*c8dee2aaSAndroid Build Coastguard Worker         }
405*c8dee2aaSAndroid Build Coastguard Worker     }
406*c8dee2aaSAndroid Build Coastguard Worker }
407*c8dee2aaSAndroid Build Coastguard Worker 
408*c8dee2aaSAndroid Build Coastguard Worker struct Draw {
Drawskgpu::ganesh::__anon033b8e600111::Draw409*c8dee2aaSAndroid Build Coastguard Worker     Draw() : fVertexCnt(0), fIndexCnt(0) {}
410*c8dee2aaSAndroid Build Coastguard Worker     int fVertexCnt;
411*c8dee2aaSAndroid Build Coastguard Worker     int fIndexCnt;
412*c8dee2aaSAndroid Build Coastguard Worker };
413*c8dee2aaSAndroid Build Coastguard Worker 
414*c8dee2aaSAndroid Build Coastguard Worker typedef TArray<Draw, true> DrawArray;
415*c8dee2aaSAndroid Build Coastguard Worker 
create_vertices(const SegmentArray & segments,const SkPoint & fanPt,const VertexColor & color,DrawArray * draws,VertexWriter & verts,uint16_t * idxs,size_t vertexStride)416*c8dee2aaSAndroid Build Coastguard Worker void create_vertices(const SegmentArray& segments,
417*c8dee2aaSAndroid Build Coastguard Worker                      const SkPoint& fanPt,
418*c8dee2aaSAndroid Build Coastguard Worker                      const VertexColor& color,
419*c8dee2aaSAndroid Build Coastguard Worker                      DrawArray* draws,
420*c8dee2aaSAndroid Build Coastguard Worker                      VertexWriter& verts,
421*c8dee2aaSAndroid Build Coastguard Worker                      uint16_t* idxs,
422*c8dee2aaSAndroid Build Coastguard Worker                      size_t vertexStride) {
423*c8dee2aaSAndroid Build Coastguard Worker     Draw* draw = &draws->push_back();
424*c8dee2aaSAndroid Build Coastguard Worker     // alias just to make vert/index assignments easier to read.
425*c8dee2aaSAndroid Build Coastguard Worker     int* v = &draw->fVertexCnt;
426*c8dee2aaSAndroid Build Coastguard Worker     int* i = &draw->fIndexCnt;
427*c8dee2aaSAndroid Build Coastguard Worker 
428*c8dee2aaSAndroid Build Coastguard Worker     int count = segments.size();
429*c8dee2aaSAndroid Build Coastguard Worker     for (int a = 0; a < count; ++a) {
430*c8dee2aaSAndroid Build Coastguard Worker         const Segment& sega = segments[a];
431*c8dee2aaSAndroid Build Coastguard Worker         int b = (a + 1) % count;
432*c8dee2aaSAndroid Build Coastguard Worker         const Segment& segb = segments[b];
433*c8dee2aaSAndroid Build Coastguard Worker 
434*c8dee2aaSAndroid Build Coastguard Worker         // Check whether adding the verts for this segment to the current draw would cause index
435*c8dee2aaSAndroid Build Coastguard Worker         // values to overflow.
436*c8dee2aaSAndroid Build Coastguard Worker         int vCount = 4;
437*c8dee2aaSAndroid Build Coastguard Worker         if (Segment::kLine == segb.fType) {
438*c8dee2aaSAndroid Build Coastguard Worker             vCount += 5;
439*c8dee2aaSAndroid Build Coastguard Worker         } else {
440*c8dee2aaSAndroid Build Coastguard Worker             vCount += 6;
441*c8dee2aaSAndroid Build Coastguard Worker         }
442*c8dee2aaSAndroid Build Coastguard Worker         if (draw->fVertexCnt + vCount > (1 << 16)) {
443*c8dee2aaSAndroid Build Coastguard Worker             idxs += *i;
444*c8dee2aaSAndroid Build Coastguard Worker             draw = &draws->push_back();
445*c8dee2aaSAndroid Build Coastguard Worker             v = &draw->fVertexCnt;
446*c8dee2aaSAndroid Build Coastguard Worker             i = &draw->fIndexCnt;
447*c8dee2aaSAndroid Build Coastguard Worker         }
448*c8dee2aaSAndroid Build Coastguard Worker 
449*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar negOneDists[2] = { -SK_Scalar1, -SK_Scalar1 };
450*c8dee2aaSAndroid Build Coastguard Worker 
451*c8dee2aaSAndroid Build Coastguard Worker         // FIXME: These tris are inset in the 1 unit arc around the corner
452*c8dee2aaSAndroid Build Coastguard Worker         SkPoint p0 = sega.endPt();
453*c8dee2aaSAndroid Build Coastguard Worker         // Position, Color, UV, D0, D1
454*c8dee2aaSAndroid Build Coastguard Worker         verts << p0                    << color << SkPoint{0, 0}           << negOneDists;
455*c8dee2aaSAndroid Build Coastguard Worker         verts << (p0 + sega.endNorm()) << color << SkPoint{0, -SK_Scalar1} << negOneDists;
456*c8dee2aaSAndroid Build Coastguard Worker         verts << (p0 + segb.fMid)      << color << SkPoint{0, -SK_Scalar1} << negOneDists;
457*c8dee2aaSAndroid Build Coastguard Worker         verts << (p0 + segb.fNorms[0]) << color << SkPoint{0, -SK_Scalar1} << negOneDists;
458*c8dee2aaSAndroid Build Coastguard Worker 
459*c8dee2aaSAndroid Build Coastguard Worker         idxs[*i + 0] = *v + 0;
460*c8dee2aaSAndroid Build Coastguard Worker         idxs[*i + 1] = *v + 2;
461*c8dee2aaSAndroid Build Coastguard Worker         idxs[*i + 2] = *v + 1;
462*c8dee2aaSAndroid Build Coastguard Worker         idxs[*i + 3] = *v + 0;
463*c8dee2aaSAndroid Build Coastguard Worker         idxs[*i + 4] = *v + 3;
464*c8dee2aaSAndroid Build Coastguard Worker         idxs[*i + 5] = *v + 2;
465*c8dee2aaSAndroid Build Coastguard Worker 
466*c8dee2aaSAndroid Build Coastguard Worker         *v += 4;
467*c8dee2aaSAndroid Build Coastguard Worker         *i += 6;
468*c8dee2aaSAndroid Build Coastguard Worker 
469*c8dee2aaSAndroid Build Coastguard Worker         if (Segment::kLine == segb.fType) {
470*c8dee2aaSAndroid Build Coastguard Worker             // we draw the line edge as a degenerate quad (u is 0, v is the
471*c8dee2aaSAndroid Build Coastguard Worker             // signed distance to the edge)
472*c8dee2aaSAndroid Build Coastguard Worker             SkPoint v1Pos = sega.endPt();
473*c8dee2aaSAndroid Build Coastguard Worker             SkPoint v2Pos = segb.fPts[0];
474*c8dee2aaSAndroid Build Coastguard Worker             SkScalar dist = SkPointPriv::DistanceToLineBetween(fanPt, v1Pos, v2Pos);
475*c8dee2aaSAndroid Build Coastguard Worker 
476*c8dee2aaSAndroid Build Coastguard Worker             verts << fanPt                    << color << SkPoint{0, dist}        << negOneDists;
477*c8dee2aaSAndroid Build Coastguard Worker             verts << v1Pos                    << color << SkPoint{0, 0}           << negOneDists;
478*c8dee2aaSAndroid Build Coastguard Worker             verts << v2Pos                    << color << SkPoint{0, 0}           << negOneDists;
479*c8dee2aaSAndroid Build Coastguard Worker             verts << (v1Pos + segb.fNorms[0]) << color << SkPoint{0, -SK_Scalar1} << negOneDists;
480*c8dee2aaSAndroid Build Coastguard Worker             verts << (v2Pos + segb.fNorms[0]) << color << SkPoint{0, -SK_Scalar1} << negOneDists;
481*c8dee2aaSAndroid Build Coastguard Worker 
482*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 0] = *v + 3;
483*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 1] = *v + 1;
484*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 2] = *v + 2;
485*c8dee2aaSAndroid Build Coastguard Worker 
486*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 3] = *v + 4;
487*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 4] = *v + 3;
488*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 5] = *v + 2;
489*c8dee2aaSAndroid Build Coastguard Worker 
490*c8dee2aaSAndroid Build Coastguard Worker             *i += 6;
491*c8dee2aaSAndroid Build Coastguard Worker 
492*c8dee2aaSAndroid Build Coastguard Worker             // Draw the interior fan if it exists.
493*c8dee2aaSAndroid Build Coastguard Worker             // TODO: Detect and combine colinear segments. This will ensure we catch every case
494*c8dee2aaSAndroid Build Coastguard Worker             // with no interior, and that the resulting shared edge uses the same endpoints.
495*c8dee2aaSAndroid Build Coastguard Worker             if (count >= 3) {
496*c8dee2aaSAndroid Build Coastguard Worker                 idxs[*i + 0] = *v + 0;
497*c8dee2aaSAndroid Build Coastguard Worker                 idxs[*i + 1] = *v + 2;
498*c8dee2aaSAndroid Build Coastguard Worker                 idxs[*i + 2] = *v + 1;
499*c8dee2aaSAndroid Build Coastguard Worker 
500*c8dee2aaSAndroid Build Coastguard Worker                 *i += 3;
501*c8dee2aaSAndroid Build Coastguard Worker             }
502*c8dee2aaSAndroid Build Coastguard Worker 
503*c8dee2aaSAndroid Build Coastguard Worker             *v += 5;
504*c8dee2aaSAndroid Build Coastguard Worker         } else {
505*c8dee2aaSAndroid Build Coastguard Worker             SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
506*c8dee2aaSAndroid Build Coastguard Worker 
507*c8dee2aaSAndroid Build Coastguard Worker             SkScalar c0 = segb.fNorms[0].dot(qpts[0]);
508*c8dee2aaSAndroid Build Coastguard Worker             SkScalar c1 = segb.fNorms[1].dot(qpts[2]);
509*c8dee2aaSAndroid Build Coastguard Worker 
510*c8dee2aaSAndroid Build Coastguard Worker             // We must transform the positions into UV in cpu memory and then copy them to the gpu
511*c8dee2aaSAndroid Build Coastguard Worker             // buffer. If we write the position first into the gpu buffer then calculate the UVs, it
512*c8dee2aaSAndroid Build Coastguard Worker             // will cause us to read from the GPU buffer which can be very slow.
513*c8dee2aaSAndroid Build Coastguard Worker             struct PosAndUV {
514*c8dee2aaSAndroid Build Coastguard Worker                 SkPoint fPos;
515*c8dee2aaSAndroid Build Coastguard Worker                 SkPoint fUV;
516*c8dee2aaSAndroid Build Coastguard Worker             };
517*c8dee2aaSAndroid Build Coastguard Worker             PosAndUV posAndUVPoints[6];
518*c8dee2aaSAndroid Build Coastguard Worker             posAndUVPoints[0].fPos = fanPt;
519*c8dee2aaSAndroid Build Coastguard Worker             posAndUVPoints[1].fPos = qpts[0];
520*c8dee2aaSAndroid Build Coastguard Worker             posAndUVPoints[2].fPos = qpts[2];
521*c8dee2aaSAndroid Build Coastguard Worker             posAndUVPoints[3].fPos = qpts[0] + segb.fNorms[0];
522*c8dee2aaSAndroid Build Coastguard Worker             posAndUVPoints[4].fPos = qpts[2] + segb.fNorms[1];
523*c8dee2aaSAndroid Build Coastguard Worker             SkVector midVec = segb.fNorms[0] + segb.fNorms[1];
524*c8dee2aaSAndroid Build Coastguard Worker             midVec.normalize();
525*c8dee2aaSAndroid Build Coastguard Worker             posAndUVPoints[5].fPos = qpts[1] + midVec;
526*c8dee2aaSAndroid Build Coastguard Worker 
527*c8dee2aaSAndroid Build Coastguard Worker             GrPathUtils::QuadUVMatrix toUV(qpts);
528*c8dee2aaSAndroid Build Coastguard Worker             toUV.apply(posAndUVPoints, 6, sizeof(PosAndUV), sizeof(SkPoint));
529*c8dee2aaSAndroid Build Coastguard Worker 
530*c8dee2aaSAndroid Build Coastguard Worker             verts << posAndUVPoints[0].fPos << color << posAndUVPoints[0].fUV
531*c8dee2aaSAndroid Build Coastguard Worker                   << (-segb.fNorms[0].dot(fanPt) + c0)
532*c8dee2aaSAndroid Build Coastguard Worker                   << (-segb.fNorms[1].dot(fanPt) + c1);
533*c8dee2aaSAndroid Build Coastguard Worker 
534*c8dee2aaSAndroid Build Coastguard Worker             verts << posAndUVPoints[1].fPos << color << posAndUVPoints[1].fUV
535*c8dee2aaSAndroid Build Coastguard Worker                   << 0.0f
536*c8dee2aaSAndroid Build Coastguard Worker                   << (-segb.fNorms[1].dot(qpts[0]) + c1);
537*c8dee2aaSAndroid Build Coastguard Worker 
538*c8dee2aaSAndroid Build Coastguard Worker             verts << posAndUVPoints[2].fPos << color << posAndUVPoints[2].fUV
539*c8dee2aaSAndroid Build Coastguard Worker                   << (-segb.fNorms[0].dot(qpts[2]) + c0)
540*c8dee2aaSAndroid Build Coastguard Worker                   << 0.0f;
541*c8dee2aaSAndroid Build Coastguard Worker             // We need a negative value that is very large that it won't effect results if it is
542*c8dee2aaSAndroid Build Coastguard Worker             // interpolated with. However, the value can't be too large of a negative that it
543*c8dee2aaSAndroid Build Coastguard Worker             // effects numerical precision on less powerful GPUs.
544*c8dee2aaSAndroid Build Coastguard Worker             static const SkScalar kStableLargeNegativeValue = -SK_ScalarMax/1000000;
545*c8dee2aaSAndroid Build Coastguard Worker             verts << posAndUVPoints[3].fPos << color << posAndUVPoints[3].fUV
546*c8dee2aaSAndroid Build Coastguard Worker                   << kStableLargeNegativeValue
547*c8dee2aaSAndroid Build Coastguard Worker                   << kStableLargeNegativeValue;
548*c8dee2aaSAndroid Build Coastguard Worker 
549*c8dee2aaSAndroid Build Coastguard Worker             verts << posAndUVPoints[4].fPos << color << posAndUVPoints[4].fUV
550*c8dee2aaSAndroid Build Coastguard Worker                   << kStableLargeNegativeValue
551*c8dee2aaSAndroid Build Coastguard Worker                   << kStableLargeNegativeValue;
552*c8dee2aaSAndroid Build Coastguard Worker 
553*c8dee2aaSAndroid Build Coastguard Worker             verts << posAndUVPoints[5].fPos << color << posAndUVPoints[5].fUV
554*c8dee2aaSAndroid Build Coastguard Worker                   << kStableLargeNegativeValue
555*c8dee2aaSAndroid Build Coastguard Worker                   << kStableLargeNegativeValue;
556*c8dee2aaSAndroid Build Coastguard Worker 
557*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 0] = *v + 3;
558*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 1] = *v + 1;
559*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 2] = *v + 2;
560*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 3] = *v + 4;
561*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 4] = *v + 3;
562*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 5] = *v + 2;
563*c8dee2aaSAndroid Build Coastguard Worker 
564*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 6] = *v + 5;
565*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 7] = *v + 3;
566*c8dee2aaSAndroid Build Coastguard Worker             idxs[*i + 8] = *v + 4;
567*c8dee2aaSAndroid Build Coastguard Worker 
568*c8dee2aaSAndroid Build Coastguard Worker             *i += 9;
569*c8dee2aaSAndroid Build Coastguard Worker 
570*c8dee2aaSAndroid Build Coastguard Worker             // Draw the interior fan if it exists.
571*c8dee2aaSAndroid Build Coastguard Worker             // TODO: Detect and combine colinear segments. This will ensure we catch every case
572*c8dee2aaSAndroid Build Coastguard Worker             // with no interior, and that the resulting shared edge uses the same endpoints.
573*c8dee2aaSAndroid Build Coastguard Worker             if (count >= 3) {
574*c8dee2aaSAndroid Build Coastguard Worker                 idxs[*i + 0] = *v + 0;
575*c8dee2aaSAndroid Build Coastguard Worker                 idxs[*i + 1] = *v + 2;
576*c8dee2aaSAndroid Build Coastguard Worker                 idxs[*i + 2] = *v + 1;
577*c8dee2aaSAndroid Build Coastguard Worker 
578*c8dee2aaSAndroid Build Coastguard Worker                 *i += 3;
579*c8dee2aaSAndroid Build Coastguard Worker             }
580*c8dee2aaSAndroid Build Coastguard Worker 
581*c8dee2aaSAndroid Build Coastguard Worker             *v += 6;
582*c8dee2aaSAndroid Build Coastguard Worker         }
583*c8dee2aaSAndroid Build Coastguard Worker     }
584*c8dee2aaSAndroid Build Coastguard Worker }
585*c8dee2aaSAndroid Build Coastguard Worker 
586*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
587*c8dee2aaSAndroid Build Coastguard Worker 
588*c8dee2aaSAndroid Build Coastguard Worker /*
589*c8dee2aaSAndroid Build Coastguard Worker  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
590*c8dee2aaSAndroid Build Coastguard Worker  * two components of the vertex attribute. Coverage is based on signed
591*c8dee2aaSAndroid Build Coastguard Worker  * distance with negative being inside, positive outside. The edge is specified in
592*c8dee2aaSAndroid Build Coastguard Worker  * window space (y-down). If either the third or fourth component of the interpolated
593*c8dee2aaSAndroid Build Coastguard Worker  * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
594*c8dee2aaSAndroid Build Coastguard Worker  * attempt to trim to a portion of the infinite quad.
595*c8dee2aaSAndroid Build Coastguard Worker  * Requires shader derivative instruction support.
596*c8dee2aaSAndroid Build Coastguard Worker  */
597*c8dee2aaSAndroid Build Coastguard Worker 
598*c8dee2aaSAndroid Build Coastguard Worker class QuadEdgeEffect : public GrGeometryProcessor {
599*c8dee2aaSAndroid Build Coastguard Worker public:
Make(SkArenaAlloc * arena,const SkMatrix & localMatrix,bool usesLocalCoords,bool wideColor)600*c8dee2aaSAndroid Build Coastguard Worker     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
601*c8dee2aaSAndroid Build Coastguard Worker                                      const SkMatrix& localMatrix,
602*c8dee2aaSAndroid Build Coastguard Worker                                      bool usesLocalCoords,
603*c8dee2aaSAndroid Build Coastguard Worker                                      bool wideColor) {
604*c8dee2aaSAndroid Build Coastguard Worker         return arena->make([&](void* ptr) {
605*c8dee2aaSAndroid Build Coastguard Worker             return new (ptr) QuadEdgeEffect(localMatrix, usesLocalCoords, wideColor);
606*c8dee2aaSAndroid Build Coastguard Worker         });
607*c8dee2aaSAndroid Build Coastguard Worker     }
608*c8dee2aaSAndroid Build Coastguard Worker 
~QuadEdgeEffect()609*c8dee2aaSAndroid Build Coastguard Worker     ~QuadEdgeEffect() override {}
610*c8dee2aaSAndroid Build Coastguard Worker 
name() const611*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "QuadEdge"; }
612*c8dee2aaSAndroid Build Coastguard Worker 
addToKey(const GrShaderCaps & caps,KeyBuilder * b) const613*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const GrShaderCaps& caps, KeyBuilder* b) const override {
614*c8dee2aaSAndroid Build Coastguard Worker         b->addBool(fUsesLocalCoords, "usesLocalCoords");
615*c8dee2aaSAndroid Build Coastguard Worker         b->addBits(ProgramImpl::kMatrixKeyBits,
616*c8dee2aaSAndroid Build Coastguard Worker                    ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix),
617*c8dee2aaSAndroid Build Coastguard Worker                    "localMatrixType");
618*c8dee2aaSAndroid Build Coastguard Worker     }
619*c8dee2aaSAndroid Build Coastguard Worker 
620*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override;
621*c8dee2aaSAndroid Build Coastguard Worker 
622*c8dee2aaSAndroid Build Coastguard Worker private:
QuadEdgeEffect(const SkMatrix & localMatrix,bool usesLocalCoords,bool wideColor)623*c8dee2aaSAndroid Build Coastguard Worker     QuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords, bool wideColor)
624*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(kQuadEdgeEffect_ClassID)
625*c8dee2aaSAndroid Build Coastguard Worker             , fLocalMatrix(localMatrix)
626*c8dee2aaSAndroid Build Coastguard Worker             , fUsesLocalCoords(usesLocalCoords) {
627*c8dee2aaSAndroid Build Coastguard Worker         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
628*c8dee2aaSAndroid Build Coastguard Worker         fInColor = MakeColorAttribute("inColor", wideColor);
629*c8dee2aaSAndroid Build Coastguard Worker         // GL on iOS 14 needs more precision for the quadedge attributes
630*c8dee2aaSAndroid Build Coastguard Worker         fInQuadEdge = {"inQuadEdge", kFloat4_GrVertexAttribType, SkSLType::kFloat4};
631*c8dee2aaSAndroid Build Coastguard Worker         this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
632*c8dee2aaSAndroid Build Coastguard Worker     }
633*c8dee2aaSAndroid Build Coastguard Worker 
634*c8dee2aaSAndroid Build Coastguard Worker     Attribute fInPosition;
635*c8dee2aaSAndroid Build Coastguard Worker     Attribute fInColor;
636*c8dee2aaSAndroid Build Coastguard Worker     Attribute fInQuadEdge;
637*c8dee2aaSAndroid Build Coastguard Worker 
638*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix fLocalMatrix;
639*c8dee2aaSAndroid Build Coastguard Worker     bool fUsesLocalCoords;
640*c8dee2aaSAndroid Build Coastguard Worker 
641*c8dee2aaSAndroid Build Coastguard Worker     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
642*c8dee2aaSAndroid Build Coastguard Worker 
643*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrGeometryProcessor;
644*c8dee2aaSAndroid Build Coastguard Worker };
645*c8dee2aaSAndroid Build Coastguard Worker 
makeProgramImpl(const GrShaderCaps &) const646*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrGeometryProcessor::ProgramImpl> QuadEdgeEffect::makeProgramImpl(
647*c8dee2aaSAndroid Build Coastguard Worker         const GrShaderCaps&) const {
648*c8dee2aaSAndroid Build Coastguard Worker     class Impl : public ProgramImpl {
649*c8dee2aaSAndroid Build Coastguard Worker     public:
650*c8dee2aaSAndroid Build Coastguard Worker         void setData(const GrGLSLProgramDataManager& pdman,
651*c8dee2aaSAndroid Build Coastguard Worker                      const GrShaderCaps& shaderCaps,
652*c8dee2aaSAndroid Build Coastguard Worker                      const GrGeometryProcessor& geomProc) override {
653*c8dee2aaSAndroid Build Coastguard Worker             const QuadEdgeEffect& qe = geomProc.cast<QuadEdgeEffect>();
654*c8dee2aaSAndroid Build Coastguard Worker             SetTransform(pdman, shaderCaps, fLocalMatrixUniform, qe.fLocalMatrix, &fLocalMatrix);
655*c8dee2aaSAndroid Build Coastguard Worker         }
656*c8dee2aaSAndroid Build Coastguard Worker 
657*c8dee2aaSAndroid Build Coastguard Worker     private:
658*c8dee2aaSAndroid Build Coastguard Worker         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
659*c8dee2aaSAndroid Build Coastguard Worker             const QuadEdgeEffect& qe = args.fGeomProc.cast<QuadEdgeEffect>();
660*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
661*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
662*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
663*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
664*c8dee2aaSAndroid Build Coastguard Worker 
665*c8dee2aaSAndroid Build Coastguard Worker             // emit attributes
666*c8dee2aaSAndroid Build Coastguard Worker             varyingHandler->emitAttributes(qe);
667*c8dee2aaSAndroid Build Coastguard Worker 
668*c8dee2aaSAndroid Build Coastguard Worker             // GL on iOS 14 needs more precision for the quadedge attributes
669*c8dee2aaSAndroid Build Coastguard Worker             // We might as well enable it everywhere
670*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLVarying v(SkSLType::kFloat4);
671*c8dee2aaSAndroid Build Coastguard Worker             varyingHandler->addVarying("QuadEdge", &v);
672*c8dee2aaSAndroid Build Coastguard Worker             vertBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.fInQuadEdge.name());
673*c8dee2aaSAndroid Build Coastguard Worker 
674*c8dee2aaSAndroid Build Coastguard Worker             // Setup pass through color
675*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
676*c8dee2aaSAndroid Build Coastguard Worker             varyingHandler->addPassThroughAttribute(qe.fInColor.asShaderVar(), args.fOutputColor);
677*c8dee2aaSAndroid Build Coastguard Worker 
678*c8dee2aaSAndroid Build Coastguard Worker             // Setup position
679*c8dee2aaSAndroid Build Coastguard Worker             WriteOutputPosition(vertBuilder, gpArgs, qe.fInPosition.name());
680*c8dee2aaSAndroid Build Coastguard Worker             if (qe.fUsesLocalCoords) {
681*c8dee2aaSAndroid Build Coastguard Worker                 WriteLocalCoord(vertBuilder,
682*c8dee2aaSAndroid Build Coastguard Worker                                 uniformHandler,
683*c8dee2aaSAndroid Build Coastguard Worker                                 *args.fShaderCaps,
684*c8dee2aaSAndroid Build Coastguard Worker                                 gpArgs,
685*c8dee2aaSAndroid Build Coastguard Worker                                 qe.fInPosition.asShaderVar(),
686*c8dee2aaSAndroid Build Coastguard Worker                                 qe.fLocalMatrix,
687*c8dee2aaSAndroid Build Coastguard Worker                                 &fLocalMatrixUniform);
688*c8dee2aaSAndroid Build Coastguard Worker             }
689*c8dee2aaSAndroid Build Coastguard Worker 
690*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("half edgeAlpha;");
691*c8dee2aaSAndroid Build Coastguard Worker 
692*c8dee2aaSAndroid Build Coastguard Worker             // keep the derivative instructions outside the conditional
693*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn());
694*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn());
695*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn());
696*c8dee2aaSAndroid Build Coastguard Worker             // today we know z and w are in device space. We could use derivatives
697*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("edgeAlpha = half(min(min(%s.z, %s.w) + 0.5, 1.0));", v.fsIn(),
698*c8dee2aaSAndroid Build Coastguard Worker                                      v.fsIn());
699*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf ("} else {");
700*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("half2 gF = half2(half(2.0*%s.x*duvdx.x - duvdx.y),"
701*c8dee2aaSAndroid Build Coastguard Worker                                      "                 half(2.0*%s.x*duvdy.x - duvdy.y));",
702*c8dee2aaSAndroid Build Coastguard Worker                                      v.fsIn(), v.fsIn());
703*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("edgeAlpha = half(%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(),
704*c8dee2aaSAndroid Build Coastguard Worker                                      v.fsIn());
705*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("edgeAlpha = "
706*c8dee2aaSAndroid Build Coastguard Worker                                      "saturate(0.5 - edgeAlpha / length(gF));}");
707*c8dee2aaSAndroid Build Coastguard Worker 
708*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("half4 %s = half4(edgeAlpha);", args.fOutputCoverage);
709*c8dee2aaSAndroid Build Coastguard Worker         }
710*c8dee2aaSAndroid Build Coastguard Worker 
711*c8dee2aaSAndroid Build Coastguard Worker     private:
712*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix();
713*c8dee2aaSAndroid Build Coastguard Worker 
714*c8dee2aaSAndroid Build Coastguard Worker         UniformHandle fLocalMatrixUniform;
715*c8dee2aaSAndroid Build Coastguard Worker     };
716*c8dee2aaSAndroid Build Coastguard Worker 
717*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<Impl>();
718*c8dee2aaSAndroid Build Coastguard Worker }
719*c8dee2aaSAndroid Build Coastguard Worker 
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect)720*c8dee2aaSAndroid Build Coastguard Worker GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect)
721*c8dee2aaSAndroid Build Coastguard Worker 
722*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
723*c8dee2aaSAndroid Build Coastguard Worker GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
724*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
725*c8dee2aaSAndroid Build Coastguard Worker     bool usesLocalCoords = d->fRandom->nextBool();
726*c8dee2aaSAndroid Build Coastguard Worker     bool wideColor = d->fRandom->nextBool();
727*c8dee2aaSAndroid Build Coastguard Worker     // Doesn't work without derivative instructions.
728*c8dee2aaSAndroid Build Coastguard Worker     return d->caps()->shaderCaps()->fShaderDerivativeSupport
729*c8dee2aaSAndroid Build Coastguard Worker                    ? QuadEdgeEffect::Make(d->allocator(), localMatrix, usesLocalCoords, wideColor)
730*c8dee2aaSAndroid Build Coastguard Worker                    : nullptr;
731*c8dee2aaSAndroid Build Coastguard Worker }
732*c8dee2aaSAndroid Build Coastguard Worker #endif
733*c8dee2aaSAndroid Build Coastguard Worker 
734*c8dee2aaSAndroid Build Coastguard Worker class AAConvexPathOp final : public GrMeshDrawOp {
735*c8dee2aaSAndroid Build Coastguard Worker private:
736*c8dee2aaSAndroid Build Coastguard Worker     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
737*c8dee2aaSAndroid Build Coastguard Worker 
738*c8dee2aaSAndroid Build Coastguard Worker public:
739*c8dee2aaSAndroid Build Coastguard Worker     DEFINE_OP_CLASS_ID
740*c8dee2aaSAndroid Build Coastguard Worker 
Make(GrRecordingContext * context,GrPaint && paint,const SkMatrix & viewMatrix,const SkPath & path,const GrUserStencilSettings * stencilSettings)741*c8dee2aaSAndroid Build Coastguard Worker     static GrOp::Owner Make(GrRecordingContext* context,
742*c8dee2aaSAndroid Build Coastguard Worker                             GrPaint&& paint,
743*c8dee2aaSAndroid Build Coastguard Worker                             const SkMatrix& viewMatrix,
744*c8dee2aaSAndroid Build Coastguard Worker                             const SkPath& path,
745*c8dee2aaSAndroid Build Coastguard Worker                             const GrUserStencilSettings* stencilSettings) {
746*c8dee2aaSAndroid Build Coastguard Worker         return Helper::FactoryHelper<AAConvexPathOp>(context, std::move(paint), viewMatrix, path,
747*c8dee2aaSAndroid Build Coastguard Worker                                                      stencilSettings);
748*c8dee2aaSAndroid Build Coastguard Worker     }
749*c8dee2aaSAndroid Build Coastguard Worker 
AAConvexPathOp(GrProcessorSet * processorSet,const SkPMColor4f & color,const SkMatrix & viewMatrix,const SkPath & path,const GrUserStencilSettings * stencilSettings)750*c8dee2aaSAndroid Build Coastguard Worker     AAConvexPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color,
751*c8dee2aaSAndroid Build Coastguard Worker                    const SkMatrix& viewMatrix, const SkPath& path,
752*c8dee2aaSAndroid Build Coastguard Worker                    const GrUserStencilSettings* stencilSettings)
753*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(ClassID()), fHelper(processorSet, GrAAType::kCoverage, stencilSettings) {
754*c8dee2aaSAndroid Build Coastguard Worker         fPaths.emplace_back(PathData{viewMatrix, path, color});
755*c8dee2aaSAndroid Build Coastguard Worker         this->setTransformedBounds(path.getBounds(), viewMatrix, HasAABloat::kYes,
756*c8dee2aaSAndroid Build Coastguard Worker                                    IsHairline::kNo);
757*c8dee2aaSAndroid Build Coastguard Worker     }
758*c8dee2aaSAndroid Build Coastguard Worker 
name() const759*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "AAConvexPathOp"; }
760*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const761*c8dee2aaSAndroid Build Coastguard Worker     void visitProxies(const GrVisitProxyFunc& func) const override {
762*c8dee2aaSAndroid Build Coastguard Worker         if (fProgramInfo) {
763*c8dee2aaSAndroid Build Coastguard Worker             fProgramInfo->visitFPProxies(func);
764*c8dee2aaSAndroid Build Coastguard Worker         } else {
765*c8dee2aaSAndroid Build Coastguard Worker             fHelper.visitProxies(func);
766*c8dee2aaSAndroid Build Coastguard Worker         }
767*c8dee2aaSAndroid Build Coastguard Worker     }
768*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const769*c8dee2aaSAndroid Build Coastguard Worker     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
770*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)771*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
772*c8dee2aaSAndroid Build Coastguard Worker                                       GrClampType clampType) override {
773*c8dee2aaSAndroid Build Coastguard Worker         return fHelper.finalizeProcessors(
774*c8dee2aaSAndroid Build Coastguard Worker                 caps, clip, clampType, GrProcessorAnalysisCoverage::kSingleChannel,
775*c8dee2aaSAndroid Build Coastguard Worker                 &fPaths.back().fColor, &fWideColor);
776*c8dee2aaSAndroid Build Coastguard Worker     }
777*c8dee2aaSAndroid Build Coastguard Worker 
778*c8dee2aaSAndroid Build Coastguard Worker private:
programInfo()779*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* programInfo() override { return fProgramInfo; }
780*c8dee2aaSAndroid Build Coastguard Worker 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)781*c8dee2aaSAndroid Build Coastguard Worker     void onCreateProgramInfo(const GrCaps* caps,
782*c8dee2aaSAndroid Build Coastguard Worker                              SkArenaAlloc* arena,
783*c8dee2aaSAndroid Build Coastguard Worker                              const GrSurfaceProxyView& writeView,
784*c8dee2aaSAndroid Build Coastguard Worker                              bool usesMSAASurface,
785*c8dee2aaSAndroid Build Coastguard Worker                              GrAppliedClip&& appliedClip,
786*c8dee2aaSAndroid Build Coastguard Worker                              const GrDstProxyView& dstProxyView,
787*c8dee2aaSAndroid Build Coastguard Worker                              GrXferBarrierFlags renderPassXferBarriers,
788*c8dee2aaSAndroid Build Coastguard Worker                              GrLoadOp colorLoadOp) override {
789*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix invert;
790*c8dee2aaSAndroid Build Coastguard Worker         if (fHelper.usesLocalCoords() && !fPaths.back().fViewMatrix.invert(&invert)) {
791*c8dee2aaSAndroid Build Coastguard Worker             return;
792*c8dee2aaSAndroid Build Coastguard Worker         }
793*c8dee2aaSAndroid Build Coastguard Worker 
794*c8dee2aaSAndroid Build Coastguard Worker         GrGeometryProcessor* quadProcessor = QuadEdgeEffect::Make(arena, invert,
795*c8dee2aaSAndroid Build Coastguard Worker                                                                   fHelper.usesLocalCoords(),
796*c8dee2aaSAndroid Build Coastguard Worker                                                                   fWideColor);
797*c8dee2aaSAndroid Build Coastguard Worker 
798*c8dee2aaSAndroid Build Coastguard Worker         fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface,
799*c8dee2aaSAndroid Build Coastguard Worker                                                             std::move(appliedClip),
800*c8dee2aaSAndroid Build Coastguard Worker                                                             dstProxyView, quadProcessor,
801*c8dee2aaSAndroid Build Coastguard Worker                                                             GrPrimitiveType::kTriangles,
802*c8dee2aaSAndroid Build Coastguard Worker                                                             renderPassXferBarriers, colorLoadOp);
803*c8dee2aaSAndroid Build Coastguard Worker     }
804*c8dee2aaSAndroid Build Coastguard Worker 
onPrepareDraws(GrMeshDrawTarget * target)805*c8dee2aaSAndroid Build Coastguard Worker     void onPrepareDraws(GrMeshDrawTarget* target) override {
806*c8dee2aaSAndroid Build Coastguard Worker         int instanceCount = fPaths.size();
807*c8dee2aaSAndroid Build Coastguard Worker 
808*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo) {
809*c8dee2aaSAndroid Build Coastguard Worker             this->createProgramInfo(target);
810*c8dee2aaSAndroid Build Coastguard Worker             if (!fProgramInfo) {
811*c8dee2aaSAndroid Build Coastguard Worker                 return;
812*c8dee2aaSAndroid Build Coastguard Worker             }
813*c8dee2aaSAndroid Build Coastguard Worker         }
814*c8dee2aaSAndroid Build Coastguard Worker 
815*c8dee2aaSAndroid Build Coastguard Worker         const size_t kVertexStride = fProgramInfo->geomProc().vertexStride();
816*c8dee2aaSAndroid Build Coastguard Worker 
817*c8dee2aaSAndroid Build Coastguard Worker         fDraws.reserve(instanceCount);
818*c8dee2aaSAndroid Build Coastguard Worker 
819*c8dee2aaSAndroid Build Coastguard Worker         // TODO generate all segments for all paths and use one vertex buffer
820*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < instanceCount; i++) {
821*c8dee2aaSAndroid Build Coastguard Worker             const PathData& args = fPaths[i];
822*c8dee2aaSAndroid Build Coastguard Worker 
823*c8dee2aaSAndroid Build Coastguard Worker             // We use the fact that SkPath::transform path does subdivision based on
824*c8dee2aaSAndroid Build Coastguard Worker             // perspective. Otherwise, we apply the view matrix when copying to the
825*c8dee2aaSAndroid Build Coastguard Worker             // segment representation.
826*c8dee2aaSAndroid Build Coastguard Worker             const SkMatrix* viewMatrix = &args.fViewMatrix;
827*c8dee2aaSAndroid Build Coastguard Worker 
828*c8dee2aaSAndroid Build Coastguard Worker             // We avoid initializing the path unless we have to
829*c8dee2aaSAndroid Build Coastguard Worker             const SkPath* pathPtr = &args.fPath;
830*c8dee2aaSAndroid Build Coastguard Worker             SkTLazy<SkPath> tmpPath;
831*c8dee2aaSAndroid Build Coastguard Worker             if (viewMatrix->hasPerspective()) {
832*c8dee2aaSAndroid Build Coastguard Worker                 SkPath* tmpPathPtr = tmpPath.init(*pathPtr);
833*c8dee2aaSAndroid Build Coastguard Worker                 tmpPathPtr->setIsVolatile(true);
834*c8dee2aaSAndroid Build Coastguard Worker                 tmpPathPtr->transform(*viewMatrix);
835*c8dee2aaSAndroid Build Coastguard Worker                 viewMatrix = &SkMatrix::I();
836*c8dee2aaSAndroid Build Coastguard Worker                 pathPtr = tmpPathPtr;
837*c8dee2aaSAndroid Build Coastguard Worker             }
838*c8dee2aaSAndroid Build Coastguard Worker 
839*c8dee2aaSAndroid Build Coastguard Worker             int vertexCount;
840*c8dee2aaSAndroid Build Coastguard Worker             int indexCount;
841*c8dee2aaSAndroid Build Coastguard Worker             static constexpr size_t kPreallocSegmentCnt = 512 / sizeof(Segment);
842*c8dee2aaSAndroid Build Coastguard Worker             static constexpr size_t kPreallocDrawCnt = 4;
843*c8dee2aaSAndroid Build Coastguard Worker 
844*c8dee2aaSAndroid Build Coastguard Worker             STArray<kPreallocSegmentCnt, Segment, true> segments;
845*c8dee2aaSAndroid Build Coastguard Worker             SkPoint fanPt;
846*c8dee2aaSAndroid Build Coastguard Worker 
847*c8dee2aaSAndroid Build Coastguard Worker             if (!get_segments(*pathPtr, *viewMatrix, &segments, &fanPt, &vertexCount,
848*c8dee2aaSAndroid Build Coastguard Worker                               &indexCount)) {
849*c8dee2aaSAndroid Build Coastguard Worker                 continue;
850*c8dee2aaSAndroid Build Coastguard Worker             }
851*c8dee2aaSAndroid Build Coastguard Worker 
852*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<const GrBuffer> vertexBuffer;
853*c8dee2aaSAndroid Build Coastguard Worker             int firstVertex;
854*c8dee2aaSAndroid Build Coastguard Worker 
855*c8dee2aaSAndroid Build Coastguard Worker             VertexWriter verts = target->makeVertexWriter(kVertexStride,
856*c8dee2aaSAndroid Build Coastguard Worker                                                           vertexCount,
857*c8dee2aaSAndroid Build Coastguard Worker                                                           &vertexBuffer,
858*c8dee2aaSAndroid Build Coastguard Worker                                                           &firstVertex);
859*c8dee2aaSAndroid Build Coastguard Worker 
860*c8dee2aaSAndroid Build Coastguard Worker             if (!verts) {
861*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("Could not allocate vertices\n");
862*c8dee2aaSAndroid Build Coastguard Worker                 return;
863*c8dee2aaSAndroid Build Coastguard Worker             }
864*c8dee2aaSAndroid Build Coastguard Worker 
865*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<const GrBuffer> indexBuffer;
866*c8dee2aaSAndroid Build Coastguard Worker             int firstIndex;
867*c8dee2aaSAndroid Build Coastguard Worker 
868*c8dee2aaSAndroid Build Coastguard Worker             uint16_t *idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
869*c8dee2aaSAndroid Build Coastguard Worker             if (!idxs) {
870*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("Could not allocate indices\n");
871*c8dee2aaSAndroid Build Coastguard Worker                 return;
872*c8dee2aaSAndroid Build Coastguard Worker             }
873*c8dee2aaSAndroid Build Coastguard Worker 
874*c8dee2aaSAndroid Build Coastguard Worker             STArray<kPreallocDrawCnt, Draw, true> draws;
875*c8dee2aaSAndroid Build Coastguard Worker             VertexColor color(args.fColor, fWideColor);
876*c8dee2aaSAndroid Build Coastguard Worker             create_vertices(segments, fanPt, color, &draws, verts, idxs, kVertexStride);
877*c8dee2aaSAndroid Build Coastguard Worker 
878*c8dee2aaSAndroid Build Coastguard Worker             GrSimpleMesh* meshes = target->allocMeshes(draws.size());
879*c8dee2aaSAndroid Build Coastguard Worker             for (int j = 0; j < draws.size(); ++j) {
880*c8dee2aaSAndroid Build Coastguard Worker                 const Draw& draw = draws[j];
881*c8dee2aaSAndroid Build Coastguard Worker                 meshes[j].setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0,
882*c8dee2aaSAndroid Build Coastguard Worker                                      draw.fVertexCnt - 1, GrPrimitiveRestart::kNo, vertexBuffer,
883*c8dee2aaSAndroid Build Coastguard Worker                                      firstVertex);
884*c8dee2aaSAndroid Build Coastguard Worker                 firstIndex += draw.fIndexCnt;
885*c8dee2aaSAndroid Build Coastguard Worker                 firstVertex += draw.fVertexCnt;
886*c8dee2aaSAndroid Build Coastguard Worker             }
887*c8dee2aaSAndroid Build Coastguard Worker 
888*c8dee2aaSAndroid Build Coastguard Worker             fDraws.push_back({ meshes, draws.size() });
889*c8dee2aaSAndroid Build Coastguard Worker         }
890*c8dee2aaSAndroid Build Coastguard Worker     }
891*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)892*c8dee2aaSAndroid Build Coastguard Worker     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
893*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo || fDraws.empty()) {
894*c8dee2aaSAndroid Build Coastguard Worker             return;
895*c8dee2aaSAndroid Build Coastguard Worker         }
896*c8dee2aaSAndroid Build Coastguard Worker 
897*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
898*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
899*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fDraws.size(); ++i) {
900*c8dee2aaSAndroid Build Coastguard Worker             for (int j = 0; j < fDraws[i].fMeshCount; ++j) {
901*c8dee2aaSAndroid Build Coastguard Worker                 flushState->drawMesh(fDraws[i].fMeshes[j]);
902*c8dee2aaSAndroid Build Coastguard Worker             }
903*c8dee2aaSAndroid Build Coastguard Worker         }
904*c8dee2aaSAndroid Build Coastguard Worker     }
905*c8dee2aaSAndroid Build Coastguard Worker 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)906*c8dee2aaSAndroid Build Coastguard Worker     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
907*c8dee2aaSAndroid Build Coastguard Worker         AAConvexPathOp* that = t->cast<AAConvexPathOp>();
908*c8dee2aaSAndroid Build Coastguard Worker         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
909*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
910*c8dee2aaSAndroid Build Coastguard Worker         }
911*c8dee2aaSAndroid Build Coastguard Worker         if (fHelper.usesLocalCoords() &&
912*c8dee2aaSAndroid Build Coastguard Worker             !SkMatrixPriv::CheapEqual(fPaths[0].fViewMatrix, that->fPaths[0].fViewMatrix)) {
913*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
914*c8dee2aaSAndroid Build Coastguard Worker         }
915*c8dee2aaSAndroid Build Coastguard Worker 
916*c8dee2aaSAndroid Build Coastguard Worker         fPaths.push_back_n(that->fPaths.size(), that->fPaths.begin());
917*c8dee2aaSAndroid Build Coastguard Worker         fWideColor |= that->fWideColor;
918*c8dee2aaSAndroid Build Coastguard Worker         return CombineResult::kMerged;
919*c8dee2aaSAndroid Build Coastguard Worker     }
920*c8dee2aaSAndroid Build Coastguard Worker 
921*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const922*c8dee2aaSAndroid Build Coastguard Worker     SkString onDumpInfo() const override {
923*c8dee2aaSAndroid Build Coastguard Worker         return SkStringPrintf("Count: %d\n%s", fPaths.size(), fHelper.dumpInfo().c_str());
924*c8dee2aaSAndroid Build Coastguard Worker     }
925*c8dee2aaSAndroid Build Coastguard Worker #endif
926*c8dee2aaSAndroid Build Coastguard Worker 
927*c8dee2aaSAndroid Build Coastguard Worker     struct PathData {
928*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix    fViewMatrix;
929*c8dee2aaSAndroid Build Coastguard Worker         SkPath      fPath;
930*c8dee2aaSAndroid Build Coastguard Worker         SkPMColor4f fColor;
931*c8dee2aaSAndroid Build Coastguard Worker     };
932*c8dee2aaSAndroid Build Coastguard Worker 
933*c8dee2aaSAndroid Build Coastguard Worker     Helper fHelper;
934*c8dee2aaSAndroid Build Coastguard Worker     STArray<1, PathData, true> fPaths;
935*c8dee2aaSAndroid Build Coastguard Worker     bool fWideColor;
936*c8dee2aaSAndroid Build Coastguard Worker 
937*c8dee2aaSAndroid Build Coastguard Worker     struct MeshDraw {
938*c8dee2aaSAndroid Build Coastguard Worker         GrSimpleMesh* fMeshes;
939*c8dee2aaSAndroid Build Coastguard Worker         int fMeshCount;
940*c8dee2aaSAndroid Build Coastguard Worker     };
941*c8dee2aaSAndroid Build Coastguard Worker 
942*c8dee2aaSAndroid Build Coastguard Worker     SkTDArray<MeshDraw> fDraws;
943*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo*      fProgramInfo = nullptr;
944*c8dee2aaSAndroid Build Coastguard Worker 
945*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrMeshDrawOp;
946*c8dee2aaSAndroid Build Coastguard Worker };
947*c8dee2aaSAndroid Build Coastguard Worker 
948*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
949*c8dee2aaSAndroid Build Coastguard Worker 
950*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
951*c8dee2aaSAndroid Build Coastguard Worker 
onCanDrawPath(const CanDrawPathArgs & args) const952*c8dee2aaSAndroid Build Coastguard Worker PathRenderer::CanDrawPath AAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
953*c8dee2aaSAndroid Build Coastguard Worker     // This check requires convexity and known direction, since the direction is used to build
954*c8dee2aaSAndroid Build Coastguard Worker     // the geometry segments. Degenerate convex paths will fall through to some other path renderer.
955*c8dee2aaSAndroid Build Coastguard Worker     if (args.fCaps->shaderCaps()->fShaderDerivativeSupport &&
956*c8dee2aaSAndroid Build Coastguard Worker         (GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
957*c8dee2aaSAndroid Build Coastguard Worker         !args.fShape->inverseFilled() && args.fShape->knownToBeConvex() &&
958*c8dee2aaSAndroid Build Coastguard Worker         args.fShape->knownDirection()) {
959*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kYes;
960*c8dee2aaSAndroid Build Coastguard Worker     }
961*c8dee2aaSAndroid Build Coastguard Worker     return CanDrawPath::kNo;
962*c8dee2aaSAndroid Build Coastguard Worker }
963*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPath(const DrawPathArgs & args)964*c8dee2aaSAndroid Build Coastguard Worker bool AAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
965*c8dee2aaSAndroid Build Coastguard Worker     GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
966*c8dee2aaSAndroid Build Coastguard Worker                               "AAConvexPathRenderer::onDrawPath");
967*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
968*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!args.fShape->isEmpty());
969*c8dee2aaSAndroid Build Coastguard Worker 
970*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
971*c8dee2aaSAndroid Build Coastguard Worker     args.fShape->asPath(&path);
972*c8dee2aaSAndroid Build Coastguard Worker 
973*c8dee2aaSAndroid Build Coastguard Worker     GrOp::Owner op = AAConvexPathOp::Make(args.fContext, std::move(args.fPaint),
974*c8dee2aaSAndroid Build Coastguard Worker                                           *args.fViewMatrix,
975*c8dee2aaSAndroid Build Coastguard Worker                                           path, args.fUserStencilSettings);
976*c8dee2aaSAndroid Build Coastguard Worker     args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
977*c8dee2aaSAndroid Build Coastguard Worker     return true;
978*c8dee2aaSAndroid Build Coastguard Worker }
979*c8dee2aaSAndroid Build Coastguard Worker 
980*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh
981*c8dee2aaSAndroid Build Coastguard Worker 
982*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
983*c8dee2aaSAndroid Build Coastguard Worker 
GR_DRAW_OP_TEST_DEFINE(AAConvexPathOp)984*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(AAConvexPathOp) {
985*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
986*c8dee2aaSAndroid Build Coastguard Worker     const SkPath& path = GrTest::TestPathConvex(random);
987*c8dee2aaSAndroid Build Coastguard Worker     const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
988*c8dee2aaSAndroid Build Coastguard Worker     return skgpu::ganesh::AAConvexPathOp::Make(
989*c8dee2aaSAndroid Build Coastguard Worker             context, std::move(paint), viewMatrix, path, stencilSettings);
990*c8dee2aaSAndroid Build Coastguard Worker }
991*c8dee2aaSAndroid Build Coastguard Worker 
992*c8dee2aaSAndroid Build Coastguard Worker #endif
993