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