1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 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/AAHairLinePathRenderer.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkPoint3.h"
11cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
12cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
13cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h"
14cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h"
15cb93a386Sopenharmony_ci#include "src/core/SkRectPriv.h"
16cb93a386Sopenharmony_ci#include "src/core/SkStroke.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrBuffer.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h"
22cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
23cb93a386Sopenharmony_ci#include "src/gpu/GrProcessor.h"
24cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
25cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
26cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h"
27cb93a386Sopenharmony_ci#include "src/gpu/GrUtil.h"
28cb93a386Sopenharmony_ci#include "src/gpu/effects/GrBezierEffect.h"
29cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h"
30cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h"
31cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h"
32cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
33cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ciusing PtArray = SkTArray<SkPoint, true>;
38cb93a386Sopenharmony_ciusing IntArray = SkTArray<int, true>;
39cb93a386Sopenharmony_ciusing FloatArray = SkTArray<float, true>;
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_cinamespace {
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci// quadratics are rendered as 5-sided polys in order to bound the
44cb93a386Sopenharmony_ci// AA stroke around the center-curve. See comments in push_quad_index_buffer and
45cb93a386Sopenharmony_ci// bloat_quad. Quadratics and conics share an index buffer
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci// lines are rendered as:
48cb93a386Sopenharmony_ci//      *______________*
49cb93a386Sopenharmony_ci//      |\ -_______   /|
50cb93a386Sopenharmony_ci//      | \        \ / |
51cb93a386Sopenharmony_ci//      |  *--------*  |
52cb93a386Sopenharmony_ci//      | /  ______/ \ |
53cb93a386Sopenharmony_ci//      */_-__________\*
54cb93a386Sopenharmony_ci// For: 6 vertices and 18 indices (for 6 triangles)
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci// Each quadratic is rendered as a five sided polygon. This poly bounds
57cb93a386Sopenharmony_ci// the quadratic's bounding triangle but has been expanded so that the
58cb93a386Sopenharmony_ci// 1-pixel wide area around the curve is inside the poly.
59cb93a386Sopenharmony_ci// If a,b,c are the original control points then the poly a0,b0,c0,c1,a1
60cb93a386Sopenharmony_ci// that is rendered would look like this:
61cb93a386Sopenharmony_ci//              b0
62cb93a386Sopenharmony_ci//              b
63cb93a386Sopenharmony_ci//
64cb93a386Sopenharmony_ci//     a0              c0
65cb93a386Sopenharmony_ci//      a            c
66cb93a386Sopenharmony_ci//       a1       c1
67cb93a386Sopenharmony_ci// Each is drawn as three triangles ((a0,a1,b0), (b0,c1,c0), (a1,c1,b0))
68cb93a386Sopenharmony_ci// specified by these 9 indices:
69cb93a386Sopenharmony_cistatic const uint16_t kQuadIdxBufPattern[] = {
70cb93a386Sopenharmony_ci    0, 1, 2,
71cb93a386Sopenharmony_ci    2, 4, 3,
72cb93a386Sopenharmony_ci    1, 4, 2
73cb93a386Sopenharmony_ci};
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_cistatic const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern);
76cb93a386Sopenharmony_cistatic const int kQuadNumVertices = 5;
77cb93a386Sopenharmony_cistatic const int kQuadsNumInIdxBuffer = 256;
78cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_cisk_sp<const GrBuffer> get_quads_index_buffer(GrResourceProvider* resourceProvider) {
81cb93a386Sopenharmony_ci    GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
82cb93a386Sopenharmony_ci    return resourceProvider->findOrCreatePatternedIndexBuffer(
83cb93a386Sopenharmony_ci        kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices,
84cb93a386Sopenharmony_ci        gQuadsIndexBufferKey);
85cb93a386Sopenharmony_ci}
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci// Each line segment is rendered as two quads and two triangles.
89cb93a386Sopenharmony_ci// p0 and p1 have alpha = 1 while all other points have alpha = 0.
90cb93a386Sopenharmony_ci// The four external points are offset 1 pixel perpendicular to the
91cb93a386Sopenharmony_ci// line and half a pixel parallel to the line.
92cb93a386Sopenharmony_ci//
93cb93a386Sopenharmony_ci// p4                  p5
94cb93a386Sopenharmony_ci//      p0         p1
95cb93a386Sopenharmony_ci// p2                  p3
96cb93a386Sopenharmony_ci//
97cb93a386Sopenharmony_ci// Each is drawn as six triangles specified by these 18 indices:
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_cistatic const uint16_t kLineSegIdxBufPattern[] = {
100cb93a386Sopenharmony_ci    0, 1, 3,
101cb93a386Sopenharmony_ci    0, 3, 2,
102cb93a386Sopenharmony_ci    0, 4, 5,
103cb93a386Sopenharmony_ci    0, 5, 1,
104cb93a386Sopenharmony_ci    0, 2, 4,
105cb93a386Sopenharmony_ci    1, 5, 3
106cb93a386Sopenharmony_ci};
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_cistatic const int kIdxsPerLineSeg = SK_ARRAY_COUNT(kLineSegIdxBufPattern);
109cb93a386Sopenharmony_cistatic const int kLineSegNumVertices = 6;
110cb93a386Sopenharmony_cistatic const int kLineSegsNumInIdxBuffer = 256;
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ciGR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_cisk_sp<const GrBuffer> get_lines_index_buffer(GrResourceProvider* resourceProvider) {
115cb93a386Sopenharmony_ci    GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
116cb93a386Sopenharmony_ci    return resourceProvider->findOrCreatePatternedIndexBuffer(
117cb93a386Sopenharmony_ci        kLineSegIdxBufPattern, kIdxsPerLineSeg,  kLineSegsNumInIdxBuffer, kLineSegNumVertices,
118cb93a386Sopenharmony_ci        gLinesIndexBufferKey);
119cb93a386Sopenharmony_ci}
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci// Takes 178th time of logf on Z600 / VC2010
122cb93a386Sopenharmony_ciint get_float_exp(float x) {
123cb93a386Sopenharmony_ci    static_assert(sizeof(int) == sizeof(float));
124cb93a386Sopenharmony_ci#ifdef SK_DEBUG
125cb93a386Sopenharmony_ci    static bool tested;
126cb93a386Sopenharmony_ci    if (!tested) {
127cb93a386Sopenharmony_ci        tested = true;
128cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(0.25f) == -2);
129cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(0.3f) == -2);
130cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(0.5f) == -1);
131cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(1.f) == 0);
132cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(2.f) == 1);
133cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(2.5f) == 1);
134cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(8.f) == 3);
135cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(100.f) == 6);
136cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(1000.f) == 9);
137cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(1024.f) == 10);
138cb93a386Sopenharmony_ci        SkASSERT(get_float_exp(3000000.f) == 21);
139cb93a386Sopenharmony_ci    }
140cb93a386Sopenharmony_ci#endif
141cb93a386Sopenharmony_ci    const int* iptr = (const int*)&x;
142cb93a386Sopenharmony_ci    return (((*iptr) & 0x7f800000) >> 23) - 127;
143cb93a386Sopenharmony_ci}
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci// Uses the max curvature function for quads to estimate
146cb93a386Sopenharmony_ci// where to chop the conic. If the max curvature is not
147cb93a386Sopenharmony_ci// found along the curve segment it will return 1 and
148cb93a386Sopenharmony_ci// dst[0] is the original conic. If it returns 2 the dst[0]
149cb93a386Sopenharmony_ci// and dst[1] are the two new conics.
150cb93a386Sopenharmony_ciint split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
151cb93a386Sopenharmony_ci    SkScalar t = SkFindQuadMaxCurvature(src);
152cb93a386Sopenharmony_ci    if (t == 0 || t == 1) {
153cb93a386Sopenharmony_ci        if (dst) {
154cb93a386Sopenharmony_ci            dst[0].set(src, weight);
155cb93a386Sopenharmony_ci        }
156cb93a386Sopenharmony_ci        return 1;
157cb93a386Sopenharmony_ci    } else {
158cb93a386Sopenharmony_ci        if (dst) {
159cb93a386Sopenharmony_ci            SkConic conic;
160cb93a386Sopenharmony_ci            conic.set(src, weight);
161cb93a386Sopenharmony_ci            if (!conic.chopAt(t, dst)) {
162cb93a386Sopenharmony_ci                dst[0].set(src, weight);
163cb93a386Sopenharmony_ci                return 1;
164cb93a386Sopenharmony_ci            }
165cb93a386Sopenharmony_ci        }
166cb93a386Sopenharmony_ci        return 2;
167cb93a386Sopenharmony_ci    }
168cb93a386Sopenharmony_ci}
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci// Calls split_conic on the entire conic and then once more on each subsection.
171cb93a386Sopenharmony_ci// Most cases will result in either 1 conic (chop point is not within t range)
172cb93a386Sopenharmony_ci// or 3 points (split once and then one subsection is split again).
173cb93a386Sopenharmony_ciint chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
174cb93a386Sopenharmony_ci    SkConic dstTemp[2];
175cb93a386Sopenharmony_ci    int conicCnt = split_conic(src, dstTemp, weight);
176cb93a386Sopenharmony_ci    if (2 == conicCnt) {
177cb93a386Sopenharmony_ci        int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
178cb93a386Sopenharmony_ci        conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
179cb93a386Sopenharmony_ci    } else {
180cb93a386Sopenharmony_ci        dst[0] = dstTemp[0];
181cb93a386Sopenharmony_ci    }
182cb93a386Sopenharmony_ci    return conicCnt;
183cb93a386Sopenharmony_ci}
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci// returns 0 if quad/conic is degen or close to it
186cb93a386Sopenharmony_ci// in this case approx the path with lines
187cb93a386Sopenharmony_ci// otherwise returns 1
188cb93a386Sopenharmony_ciint is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
189cb93a386Sopenharmony_ci    static const SkScalar gDegenerateToLineTol = GrPathUtils::kDefaultTolerance;
190cb93a386Sopenharmony_ci    static const SkScalar gDegenerateToLineTolSqd =
191cb93a386Sopenharmony_ci        gDegenerateToLineTol * gDegenerateToLineTol;
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    if (SkPointPriv::DistanceToSqd(p[0], p[1]) < gDegenerateToLineTolSqd ||
194cb93a386Sopenharmony_ci        SkPointPriv::DistanceToSqd(p[1], p[2]) < gDegenerateToLineTolSqd) {
195cb93a386Sopenharmony_ci        return 1;
196cb93a386Sopenharmony_ci    }
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ci    *dsqd = SkPointPriv::DistanceToLineBetweenSqd(p[1], p[0], p[2]);
199cb93a386Sopenharmony_ci    if (*dsqd < gDegenerateToLineTolSqd) {
200cb93a386Sopenharmony_ci        return 1;
201cb93a386Sopenharmony_ci    }
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ci    if (SkPointPriv::DistanceToLineBetweenSqd(p[2], p[1], p[0]) < gDegenerateToLineTolSqd) {
204cb93a386Sopenharmony_ci        return 1;
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci    return 0;
207cb93a386Sopenharmony_ci}
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ciint is_degen_quad_or_conic(const SkPoint p[3]) {
210cb93a386Sopenharmony_ci    SkScalar dsqd;
211cb93a386Sopenharmony_ci    return is_degen_quad_or_conic(p, &dsqd);
212cb93a386Sopenharmony_ci}
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci// we subdivide the quads to avoid huge overfill
215cb93a386Sopenharmony_ci// if it returns -1 then should be drawn as lines
216cb93a386Sopenharmony_ciint num_quad_subdivs(const SkPoint p[3]) {
217cb93a386Sopenharmony_ci    SkScalar dsqd;
218cb93a386Sopenharmony_ci    if (is_degen_quad_or_conic(p, &dsqd)) {
219cb93a386Sopenharmony_ci        return -1;
220cb93a386Sopenharmony_ci    }
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_ci    // tolerance of triangle height in pixels
223cb93a386Sopenharmony_ci    // tuned on windows  Quadro FX 380 / Z600
224cb93a386Sopenharmony_ci    // trade off of fill vs cpu time on verts
225cb93a386Sopenharmony_ci    // maybe different when do this using gpu (geo or tess shaders)
226cb93a386Sopenharmony_ci    static const SkScalar gSubdivTol = 175 * SK_Scalar1;
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci    if (dsqd <= gSubdivTol * gSubdivTol) {
229cb93a386Sopenharmony_ci        return 0;
230cb93a386Sopenharmony_ci    } else {
231cb93a386Sopenharmony_ci        static const int kMaxSub = 4;
232cb93a386Sopenharmony_ci        // subdividing the quad reduces d by 4. so we want x = log4(d/tol)
233cb93a386Sopenharmony_ci        // = log4(d*d/tol*tol)/2
234cb93a386Sopenharmony_ci        // = log2(d*d/tol*tol)
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci        // +1 since we're ignoring the mantissa contribution.
237cb93a386Sopenharmony_ci        int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1;
238cb93a386Sopenharmony_ci        log = std::min(std::max(0, log), kMaxSub);
239cb93a386Sopenharmony_ci        return log;
240cb93a386Sopenharmony_ci    }
241cb93a386Sopenharmony_ci}
242cb93a386Sopenharmony_ci
243cb93a386Sopenharmony_ci/**
244cb93a386Sopenharmony_ci * Generates the lines and quads to be rendered. Lines are always recorded in
245cb93a386Sopenharmony_ci * device space. We will do a device space bloat to account for the 1pixel
246cb93a386Sopenharmony_ci * thickness.
247cb93a386Sopenharmony_ci * Quads are recorded in device space unless m contains
248cb93a386Sopenharmony_ci * perspective, then in they are in src space. We do this because we will
249cb93a386Sopenharmony_ci * subdivide large quads to reduce over-fill. This subdivision has to be
250cb93a386Sopenharmony_ci * performed before applying the perspective matrix.
251cb93a386Sopenharmony_ci */
252cb93a386Sopenharmony_ciint gather_lines_and_quads(const SkPath& path,
253cb93a386Sopenharmony_ci                           const SkMatrix& m,
254cb93a386Sopenharmony_ci                           const SkIRect& devClipBounds,
255cb93a386Sopenharmony_ci                           SkScalar capLength,
256cb93a386Sopenharmony_ci                           bool convertConicsToQuads,
257cb93a386Sopenharmony_ci                           PtArray* lines,
258cb93a386Sopenharmony_ci                           PtArray* quads,
259cb93a386Sopenharmony_ci                           PtArray* conics,
260cb93a386Sopenharmony_ci                           IntArray* quadSubdivCnts,
261cb93a386Sopenharmony_ci                           FloatArray* conicWeights) {
262cb93a386Sopenharmony_ci    SkPath::Iter iter(path, false);
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci    int totalQuadCount = 0;
265cb93a386Sopenharmony_ci    SkRect bounds;
266cb93a386Sopenharmony_ci    SkIRect ibounds;
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci    bool persp = m.hasPerspective();
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci    // Whenever a degenerate, zero-length contour is encountered, this code will insert a
271cb93a386Sopenharmony_ci    // 'capLength' x-aligned line segment. Since this is rendering hairlines it is hoped this will
272cb93a386Sopenharmony_ci    // suffice for AA square & circle capping.
273cb93a386Sopenharmony_ci    int verbsInContour = 0; // Does not count moves
274cb93a386Sopenharmony_ci    bool seenZeroLengthVerb = false;
275cb93a386Sopenharmony_ci    SkPoint zeroVerbPt;
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci    // Adds a quad that has already been chopped to the list and checks for quads that are close to
278cb93a386Sopenharmony_ci    // lines. Also does a bounding box check. It takes points that are in src space and device
279cb93a386Sopenharmony_ci    // space. The src points are only required if the view matrix has perspective.
280cb93a386Sopenharmony_ci    auto addChoppedQuad = [&](const SkPoint srcPts[3], const SkPoint devPts[4],
281cb93a386Sopenharmony_ci                              bool isContourStart) {
282cb93a386Sopenharmony_ci        SkRect bounds;
283cb93a386Sopenharmony_ci        SkIRect ibounds;
284cb93a386Sopenharmony_ci        bounds.setBounds(devPts, 3);
285cb93a386Sopenharmony_ci        bounds.outset(SK_Scalar1, SK_Scalar1);
286cb93a386Sopenharmony_ci        bounds.roundOut(&ibounds);
287cb93a386Sopenharmony_ci        // We only need the src space space pts when not in perspective.
288cb93a386Sopenharmony_ci        SkASSERT(srcPts || !persp);
289cb93a386Sopenharmony_ci        if (SkIRect::Intersects(devClipBounds, ibounds)) {
290cb93a386Sopenharmony_ci            int subdiv = num_quad_subdivs(devPts);
291cb93a386Sopenharmony_ci            SkASSERT(subdiv >= -1);
292cb93a386Sopenharmony_ci            if (-1 == subdiv) {
293cb93a386Sopenharmony_ci                SkPoint* pts = lines->push_back_n(4);
294cb93a386Sopenharmony_ci                pts[0] = devPts[0];
295cb93a386Sopenharmony_ci                pts[1] = devPts[1];
296cb93a386Sopenharmony_ci                pts[2] = devPts[1];
297cb93a386Sopenharmony_ci                pts[3] = devPts[2];
298cb93a386Sopenharmony_ci                if (isContourStart && pts[0] == pts[1] && pts[2] == pts[3]) {
299cb93a386Sopenharmony_ci                    seenZeroLengthVerb = true;
300cb93a386Sopenharmony_ci                    zeroVerbPt = pts[0];
301cb93a386Sopenharmony_ci                }
302cb93a386Sopenharmony_ci            } else {
303cb93a386Sopenharmony_ci                // when in perspective keep quads in src space
304cb93a386Sopenharmony_ci                const SkPoint* qPts = persp ? srcPts : devPts;
305cb93a386Sopenharmony_ci                SkPoint* pts = quads->push_back_n(3);
306cb93a386Sopenharmony_ci                pts[0] = qPts[0];
307cb93a386Sopenharmony_ci                pts[1] = qPts[1];
308cb93a386Sopenharmony_ci                pts[2] = qPts[2];
309cb93a386Sopenharmony_ci                quadSubdivCnts->push_back() = subdiv;
310cb93a386Sopenharmony_ci                totalQuadCount += 1 << subdiv;
311cb93a386Sopenharmony_ci            }
312cb93a386Sopenharmony_ci        }
313cb93a386Sopenharmony_ci    };
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ci    // Applies the view matrix to quad src points and calls the above helper.
316cb93a386Sopenharmony_ci    auto addSrcChoppedQuad = [&](const SkPoint srcSpaceQuadPts[3], bool isContourStart) {
317cb93a386Sopenharmony_ci        SkPoint devPts[3];
318cb93a386Sopenharmony_ci        m.mapPoints(devPts, srcSpaceQuadPts, 3);
319cb93a386Sopenharmony_ci        addChoppedQuad(srcSpaceQuadPts, devPts, isContourStart);
320cb93a386Sopenharmony_ci    };
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ci    for (;;) {
323cb93a386Sopenharmony_ci        SkPoint pathPts[4];
324cb93a386Sopenharmony_ci        SkPath::Verb verb = iter.next(pathPts);
325cb93a386Sopenharmony_ci        switch (verb) {
326cb93a386Sopenharmony_ci            case SkPath::kConic_Verb:
327cb93a386Sopenharmony_ci                if (convertConicsToQuads) {
328cb93a386Sopenharmony_ci                    SkScalar weight = iter.conicWeight();
329cb93a386Sopenharmony_ci                    SkAutoConicToQuads converter;
330cb93a386Sopenharmony_ci                    const SkPoint* quadPts = converter.computeQuads(pathPts, weight, 0.25f);
331cb93a386Sopenharmony_ci                    for (int i = 0; i < converter.countQuads(); ++i) {
332cb93a386Sopenharmony_ci                        addSrcChoppedQuad(quadPts + 2 * i, !verbsInContour && 0 == i);
333cb93a386Sopenharmony_ci                    }
334cb93a386Sopenharmony_ci                } else {
335cb93a386Sopenharmony_ci                    SkConic dst[4];
336cb93a386Sopenharmony_ci                    // We chop the conics to create tighter clipping to hide error
337cb93a386Sopenharmony_ci                    // that appears near max curvature of very thin conics. Thin
338cb93a386Sopenharmony_ci                    // hyperbolas with high weight still show error.
339cb93a386Sopenharmony_ci                    int conicCnt = chop_conic(pathPts, dst, iter.conicWeight());
340cb93a386Sopenharmony_ci                    for (int i = 0; i < conicCnt; ++i) {
341cb93a386Sopenharmony_ci                        SkPoint devPts[4];
342cb93a386Sopenharmony_ci                        SkPoint* chopPnts = dst[i].fPts;
343cb93a386Sopenharmony_ci                        m.mapPoints(devPts, chopPnts, 3);
344cb93a386Sopenharmony_ci                        bounds.setBounds(devPts, 3);
345cb93a386Sopenharmony_ci                        bounds.outset(SK_Scalar1, SK_Scalar1);
346cb93a386Sopenharmony_ci                        bounds.roundOut(&ibounds);
347cb93a386Sopenharmony_ci                        if (SkIRect::Intersects(devClipBounds, ibounds)) {
348cb93a386Sopenharmony_ci                            if (is_degen_quad_or_conic(devPts)) {
349cb93a386Sopenharmony_ci                                SkPoint* pts = lines->push_back_n(4);
350cb93a386Sopenharmony_ci                                pts[0] = devPts[0];
351cb93a386Sopenharmony_ci                                pts[1] = devPts[1];
352cb93a386Sopenharmony_ci                                pts[2] = devPts[1];
353cb93a386Sopenharmony_ci                                pts[3] = devPts[2];
354cb93a386Sopenharmony_ci                                if (verbsInContour == 0 && i == 0 && pts[0] == pts[1] &&
355cb93a386Sopenharmony_ci                                    pts[2] == pts[3]) {
356cb93a386Sopenharmony_ci                                    seenZeroLengthVerb = true;
357cb93a386Sopenharmony_ci                                    zeroVerbPt = pts[0];
358cb93a386Sopenharmony_ci                                }
359cb93a386Sopenharmony_ci                            } else {
360cb93a386Sopenharmony_ci                                // when in perspective keep conics in src space
361cb93a386Sopenharmony_ci                                SkPoint* cPts = persp ? chopPnts : devPts;
362cb93a386Sopenharmony_ci                                SkPoint* pts = conics->push_back_n(3);
363cb93a386Sopenharmony_ci                                pts[0] = cPts[0];
364cb93a386Sopenharmony_ci                                pts[1] = cPts[1];
365cb93a386Sopenharmony_ci                                pts[2] = cPts[2];
366cb93a386Sopenharmony_ci                                conicWeights->push_back() = dst[i].fW;
367cb93a386Sopenharmony_ci                            }
368cb93a386Sopenharmony_ci                        }
369cb93a386Sopenharmony_ci                    }
370cb93a386Sopenharmony_ci                }
371cb93a386Sopenharmony_ci                verbsInContour++;
372cb93a386Sopenharmony_ci                break;
373cb93a386Sopenharmony_ci            case SkPath::kMove_Verb:
374cb93a386Sopenharmony_ci                // New contour (and last one was unclosed). If it was just a zero length drawing
375cb93a386Sopenharmony_ci                // operation, and we're supposed to draw caps, then add a tiny line.
376cb93a386Sopenharmony_ci                if (seenZeroLengthVerb && verbsInContour == 1 && capLength > 0) {
377cb93a386Sopenharmony_ci                    SkPoint* pts = lines->push_back_n(2);
378cb93a386Sopenharmony_ci                    pts[0] = SkPoint::Make(zeroVerbPt.fX - capLength, zeroVerbPt.fY);
379cb93a386Sopenharmony_ci                    pts[1] = SkPoint::Make(zeroVerbPt.fX + capLength, zeroVerbPt.fY);
380cb93a386Sopenharmony_ci                }
381cb93a386Sopenharmony_ci                verbsInContour = 0;
382cb93a386Sopenharmony_ci                seenZeroLengthVerb = false;
383cb93a386Sopenharmony_ci                break;
384cb93a386Sopenharmony_ci            case SkPath::kLine_Verb: {
385cb93a386Sopenharmony_ci                SkPoint devPts[2];
386cb93a386Sopenharmony_ci                m.mapPoints(devPts, pathPts, 2);
387cb93a386Sopenharmony_ci                bounds.setBounds(devPts, 2);
388cb93a386Sopenharmony_ci                bounds.outset(SK_Scalar1, SK_Scalar1);
389cb93a386Sopenharmony_ci                bounds.roundOut(&ibounds);
390cb93a386Sopenharmony_ci                if (SkIRect::Intersects(devClipBounds, ibounds)) {
391cb93a386Sopenharmony_ci                    SkPoint* pts = lines->push_back_n(2);
392cb93a386Sopenharmony_ci                    pts[0] = devPts[0];
393cb93a386Sopenharmony_ci                    pts[1] = devPts[1];
394cb93a386Sopenharmony_ci                    if (verbsInContour == 0 && pts[0] == pts[1]) {
395cb93a386Sopenharmony_ci                        seenZeroLengthVerb = true;
396cb93a386Sopenharmony_ci                        zeroVerbPt = pts[0];
397cb93a386Sopenharmony_ci                    }
398cb93a386Sopenharmony_ci                }
399cb93a386Sopenharmony_ci                verbsInContour++;
400cb93a386Sopenharmony_ci                break;
401cb93a386Sopenharmony_ci            }
402cb93a386Sopenharmony_ci            case SkPath::kQuad_Verb: {
403cb93a386Sopenharmony_ci                SkPoint choppedPts[5];
404cb93a386Sopenharmony_ci                // Chopping the quad helps when the quad is either degenerate or nearly degenerate.
405cb93a386Sopenharmony_ci                // When it is degenerate it allows the approximation with lines to work since the
406cb93a386Sopenharmony_ci                // chop point (if there is one) will be at the parabola's vertex. In the nearly
407cb93a386Sopenharmony_ci                // degenerate the QuadUVMatrix computed for the points is almost singular which
408cb93a386Sopenharmony_ci                // can cause rendering artifacts.
409cb93a386Sopenharmony_ci                int n = SkChopQuadAtMaxCurvature(pathPts, choppedPts);
410cb93a386Sopenharmony_ci                for (int i = 0; i < n; ++i) {
411cb93a386Sopenharmony_ci                    addSrcChoppedQuad(choppedPts + i * 2, !verbsInContour && 0 == i);
412cb93a386Sopenharmony_ci                }
413cb93a386Sopenharmony_ci                verbsInContour++;
414cb93a386Sopenharmony_ci                break;
415cb93a386Sopenharmony_ci            }
416cb93a386Sopenharmony_ci            case SkPath::kCubic_Verb: {
417cb93a386Sopenharmony_ci                SkPoint devPts[4];
418cb93a386Sopenharmony_ci                m.mapPoints(devPts, pathPts, 4);
419cb93a386Sopenharmony_ci                bounds.setBounds(devPts, 4);
420cb93a386Sopenharmony_ci                bounds.outset(SK_Scalar1, SK_Scalar1);
421cb93a386Sopenharmony_ci                bounds.roundOut(&ibounds);
422cb93a386Sopenharmony_ci                if (SkIRect::Intersects(devClipBounds, ibounds)) {
423cb93a386Sopenharmony_ci                    PREALLOC_PTARRAY(32) q;
424cb93a386Sopenharmony_ci                    // We convert cubics to quadratics (for now).
425cb93a386Sopenharmony_ci                    // In perspective have to do conversion in src space.
426cb93a386Sopenharmony_ci                    if (persp) {
427cb93a386Sopenharmony_ci                        SkScalar tolScale =
428cb93a386Sopenharmony_ci                            GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m, path.getBounds());
429cb93a386Sopenharmony_ci                        GrPathUtils::convertCubicToQuads(pathPts, tolScale, &q);
430cb93a386Sopenharmony_ci                    } else {
431cb93a386Sopenharmony_ci                        GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, &q);
432cb93a386Sopenharmony_ci                    }
433cb93a386Sopenharmony_ci                    for (int i = 0; i < q.count(); i += 3) {
434cb93a386Sopenharmony_ci                        if (persp) {
435cb93a386Sopenharmony_ci                            addSrcChoppedQuad(&q[i], !verbsInContour && 0 == i);
436cb93a386Sopenharmony_ci                        } else {
437cb93a386Sopenharmony_ci                            addChoppedQuad(nullptr, &q[i], !verbsInContour && 0 == i);
438cb93a386Sopenharmony_ci                        }
439cb93a386Sopenharmony_ci                    }
440cb93a386Sopenharmony_ci                }
441cb93a386Sopenharmony_ci                verbsInContour++;
442cb93a386Sopenharmony_ci                break;
443cb93a386Sopenharmony_ci            }
444cb93a386Sopenharmony_ci            case SkPath::kClose_Verb:
445cb93a386Sopenharmony_ci                // Contour is closed, so we don't need to grow the starting line, unless it's
446cb93a386Sopenharmony_ci                // *just* a zero length subpath. (SVG Spec 11.4, 'stroke').
447cb93a386Sopenharmony_ci                if (capLength > 0) {
448cb93a386Sopenharmony_ci                    if (seenZeroLengthVerb && verbsInContour == 1) {
449cb93a386Sopenharmony_ci                        SkPoint* pts = lines->push_back_n(2);
450cb93a386Sopenharmony_ci                        pts[0] = SkPoint::Make(zeroVerbPt.fX - capLength, zeroVerbPt.fY);
451cb93a386Sopenharmony_ci                        pts[1] = SkPoint::Make(zeroVerbPt.fX + capLength, zeroVerbPt.fY);
452cb93a386Sopenharmony_ci                    } else if (verbsInContour == 0) {
453cb93a386Sopenharmony_ci                        // Contour was (moveTo, close). Add a line.
454cb93a386Sopenharmony_ci                        SkPoint devPts[2];
455cb93a386Sopenharmony_ci                        m.mapPoints(devPts, pathPts, 1);
456cb93a386Sopenharmony_ci                        devPts[1] = devPts[0];
457cb93a386Sopenharmony_ci                        bounds.setBounds(devPts, 2);
458cb93a386Sopenharmony_ci                        bounds.outset(SK_Scalar1, SK_Scalar1);
459cb93a386Sopenharmony_ci                        bounds.roundOut(&ibounds);
460cb93a386Sopenharmony_ci                        if (SkIRect::Intersects(devClipBounds, ibounds)) {
461cb93a386Sopenharmony_ci                            SkPoint* pts = lines->push_back_n(2);
462cb93a386Sopenharmony_ci                            pts[0] = SkPoint::Make(devPts[0].fX - capLength, devPts[0].fY);
463cb93a386Sopenharmony_ci                            pts[1] = SkPoint::Make(devPts[1].fX + capLength, devPts[1].fY);
464cb93a386Sopenharmony_ci                        }
465cb93a386Sopenharmony_ci                    }
466cb93a386Sopenharmony_ci                }
467cb93a386Sopenharmony_ci                break;
468cb93a386Sopenharmony_ci            case SkPath::kDone_Verb:
469cb93a386Sopenharmony_ci                if (seenZeroLengthVerb && verbsInContour == 1 && capLength > 0) {
470cb93a386Sopenharmony_ci                    // Path ended with a dangling (moveTo, line|quad|etc). If the final verb is
471cb93a386Sopenharmony_ci                    // degenerate, we need to draw a line.
472cb93a386Sopenharmony_ci                    SkPoint* pts = lines->push_back_n(2);
473cb93a386Sopenharmony_ci                    pts[0] = SkPoint::Make(zeroVerbPt.fX - capLength, zeroVerbPt.fY);
474cb93a386Sopenharmony_ci                    pts[1] = SkPoint::Make(zeroVerbPt.fX + capLength, zeroVerbPt.fY);
475cb93a386Sopenharmony_ci                }
476cb93a386Sopenharmony_ci                return totalQuadCount;
477cb93a386Sopenharmony_ci        }
478cb93a386Sopenharmony_ci    }
479cb93a386Sopenharmony_ci}
480cb93a386Sopenharmony_ci
481cb93a386Sopenharmony_cistruct LineVertex {
482cb93a386Sopenharmony_ci    SkPoint fPos;
483cb93a386Sopenharmony_ci    float fCoverage;
484cb93a386Sopenharmony_ci};
485cb93a386Sopenharmony_ci
486cb93a386Sopenharmony_cistruct BezierVertex {
487cb93a386Sopenharmony_ci    SkPoint fPos;
488cb93a386Sopenharmony_ci    union {
489cb93a386Sopenharmony_ci        struct {
490cb93a386Sopenharmony_ci            SkScalar fKLM[3];
491cb93a386Sopenharmony_ci        } fConic;
492cb93a386Sopenharmony_ci        SkVector   fQuadCoord;
493cb93a386Sopenharmony_ci        struct {
494cb93a386Sopenharmony_ci            SkScalar fBogus[4];
495cb93a386Sopenharmony_ci        };
496cb93a386Sopenharmony_ci    };
497cb93a386Sopenharmony_ci};
498cb93a386Sopenharmony_ci
499cb93a386Sopenharmony_cistatic_assert(sizeof(BezierVertex) == 3 * sizeof(SkPoint));
500cb93a386Sopenharmony_ci
501cb93a386Sopenharmony_civoid intersect_lines(const SkPoint& ptA, const SkVector& normA,
502cb93a386Sopenharmony_ci                     const SkPoint& ptB, const SkVector& normB,
503cb93a386Sopenharmony_ci                     SkPoint* result) {
504cb93a386Sopenharmony_ci
505cb93a386Sopenharmony_ci    SkScalar lineAW = -normA.dot(ptA);
506cb93a386Sopenharmony_ci    SkScalar lineBW = -normB.dot(ptB);
507cb93a386Sopenharmony_ci
508cb93a386Sopenharmony_ci    SkScalar wInv = normA.fX * normB.fY - normA.fY * normB.fX;
509cb93a386Sopenharmony_ci    wInv = SkScalarInvert(wInv);
510cb93a386Sopenharmony_ci    if (!SkScalarIsFinite(wInv)) {
511cb93a386Sopenharmony_ci        // lines are parallel, pick the point in between
512cb93a386Sopenharmony_ci        *result = (ptA + ptB)*SK_ScalarHalf;
513cb93a386Sopenharmony_ci        *result += normA;
514cb93a386Sopenharmony_ci    } else {
515cb93a386Sopenharmony_ci        result->fX = normA.fY * lineBW - lineAW * normB.fY;
516cb93a386Sopenharmony_ci        result->fX *= wInv;
517cb93a386Sopenharmony_ci
518cb93a386Sopenharmony_ci        result->fY = lineAW * normB.fX - normA.fX * lineBW;
519cb93a386Sopenharmony_ci        result->fY *= wInv;
520cb93a386Sopenharmony_ci    }
521cb93a386Sopenharmony_ci}
522cb93a386Sopenharmony_ci
523cb93a386Sopenharmony_civoid set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
524cb93a386Sopenharmony_ci    // this should be in the src space, not dev coords, when we have perspective
525cb93a386Sopenharmony_ci    GrPathUtils::QuadUVMatrix DevToUV(qpts);
526cb93a386Sopenharmony_ci    DevToUV.apply(verts, kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint));
527cb93a386Sopenharmony_ci}
528cb93a386Sopenharmony_ci
529cb93a386Sopenharmony_civoid bloat_quad(const SkPoint qpts[3],
530cb93a386Sopenharmony_ci                const SkMatrix* toDevice,
531cb93a386Sopenharmony_ci                const SkMatrix* toSrc,
532cb93a386Sopenharmony_ci                BezierVertex verts[kQuadNumVertices]) {
533cb93a386Sopenharmony_ci    SkASSERT(!toDevice == !toSrc);
534cb93a386Sopenharmony_ci    // original quad is specified by tri a,b,c
535cb93a386Sopenharmony_ci    SkPoint a = qpts[0];
536cb93a386Sopenharmony_ci    SkPoint b = qpts[1];
537cb93a386Sopenharmony_ci    SkPoint c = qpts[2];
538cb93a386Sopenharmony_ci
539cb93a386Sopenharmony_ci    if (toDevice) {
540cb93a386Sopenharmony_ci        toDevice->mapPoints(&a, 1);
541cb93a386Sopenharmony_ci        toDevice->mapPoints(&b, 1);
542cb93a386Sopenharmony_ci        toDevice->mapPoints(&c, 1);
543cb93a386Sopenharmony_ci    }
544cb93a386Sopenharmony_ci    // make a new poly where we replace a and c by a 1-pixel wide edges orthog
545cb93a386Sopenharmony_ci    // to edges ab and bc:
546cb93a386Sopenharmony_ci    //
547cb93a386Sopenharmony_ci    //   before       |        after
548cb93a386Sopenharmony_ci    //                |              b0
549cb93a386Sopenharmony_ci    //         b      |
550cb93a386Sopenharmony_ci    //                |
551cb93a386Sopenharmony_ci    //                |     a0            c0
552cb93a386Sopenharmony_ci    // a         c    |        a1       c1
553cb93a386Sopenharmony_ci    //
554cb93a386Sopenharmony_ci    // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c,
555cb93a386Sopenharmony_ci    // respectively.
556cb93a386Sopenharmony_ci    BezierVertex& a0 = verts[0];
557cb93a386Sopenharmony_ci    BezierVertex& a1 = verts[1];
558cb93a386Sopenharmony_ci    BezierVertex& b0 = verts[2];
559cb93a386Sopenharmony_ci    BezierVertex& c0 = verts[3];
560cb93a386Sopenharmony_ci    BezierVertex& c1 = verts[4];
561cb93a386Sopenharmony_ci
562cb93a386Sopenharmony_ci    SkVector ab = b;
563cb93a386Sopenharmony_ci    ab -= a;
564cb93a386Sopenharmony_ci    SkVector ac = c;
565cb93a386Sopenharmony_ci    ac -= a;
566cb93a386Sopenharmony_ci    SkVector cb = b;
567cb93a386Sopenharmony_ci    cb -= c;
568cb93a386Sopenharmony_ci
569cb93a386Sopenharmony_ci    // After the transform (or due to floating point math) we might have a line,
570cb93a386Sopenharmony_ci    // try to do something reasonable
571cb93a386Sopenharmony_ci    if (SkPointPriv::LengthSqd(ab) <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
572cb93a386Sopenharmony_ci        ab = cb;
573cb93a386Sopenharmony_ci    }
574cb93a386Sopenharmony_ci    if (SkPointPriv::LengthSqd(cb) <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
575cb93a386Sopenharmony_ci        cb = ab;
576cb93a386Sopenharmony_ci    }
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_ci    // We should have already handled degenerates
579cb93a386Sopenharmony_ci    SkASSERT(ab.length() > 0 && cb.length() > 0);
580cb93a386Sopenharmony_ci
581cb93a386Sopenharmony_ci    ab.normalize();
582cb93a386Sopenharmony_ci    SkVector abN = SkPointPriv::MakeOrthog(ab, SkPointPriv::kLeft_Side);
583cb93a386Sopenharmony_ci    if (abN.dot(ac) > 0) {
584cb93a386Sopenharmony_ci        abN.negate();
585cb93a386Sopenharmony_ci    }
586cb93a386Sopenharmony_ci
587cb93a386Sopenharmony_ci    cb.normalize();
588cb93a386Sopenharmony_ci    SkVector cbN = SkPointPriv::MakeOrthog(cb, SkPointPriv::kLeft_Side);
589cb93a386Sopenharmony_ci    if (cbN.dot(ac) < 0) {
590cb93a386Sopenharmony_ci        cbN.negate();
591cb93a386Sopenharmony_ci    }
592cb93a386Sopenharmony_ci
593cb93a386Sopenharmony_ci    a0.fPos = a;
594cb93a386Sopenharmony_ci    a0.fPos += abN;
595cb93a386Sopenharmony_ci    a1.fPos = a;
596cb93a386Sopenharmony_ci    a1.fPos -= abN;
597cb93a386Sopenharmony_ci
598cb93a386Sopenharmony_ci    if (toDevice && SkPointPriv::LengthSqd(ac) <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
599cb93a386Sopenharmony_ci        c = b;
600cb93a386Sopenharmony_ci    }
601cb93a386Sopenharmony_ci    c0.fPos = c;
602cb93a386Sopenharmony_ci    c0.fPos += cbN;
603cb93a386Sopenharmony_ci    c1.fPos = c;
604cb93a386Sopenharmony_ci    c1.fPos -= cbN;
605cb93a386Sopenharmony_ci
606cb93a386Sopenharmony_ci    intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
607cb93a386Sopenharmony_ci
608cb93a386Sopenharmony_ci    if (toSrc) {
609cb93a386Sopenharmony_ci        SkMatrixPriv::MapPointsWithStride(*toSrc, &verts[0].fPos, sizeof(BezierVertex),
610cb93a386Sopenharmony_ci                                          kQuadNumVertices);
611cb93a386Sopenharmony_ci    }
612cb93a386Sopenharmony_ci}
613cb93a386Sopenharmony_ci
614cb93a386Sopenharmony_ci// Equations based off of Loop-Blinn Quadratic GPU Rendering
615cb93a386Sopenharmony_ci// Input Parametric:
616cb93a386Sopenharmony_ci// P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2)
617cb93a386Sopenharmony_ci// Output Implicit:
618cb93a386Sopenharmony_ci// f(x, y, w) = f(P) = K^2 - LM
619cb93a386Sopenharmony_ci// K = dot(k, P), L = dot(l, P), M = dot(m, P)
620cb93a386Sopenharmony_ci// k, l, m are calculated in function GrPathUtils::getConicKLM
621cb93a386Sopenharmony_civoid set_conic_coeffs(const SkPoint p[3],
622cb93a386Sopenharmony_ci                      BezierVertex verts[kQuadNumVertices],
623cb93a386Sopenharmony_ci                      const SkScalar weight) {
624cb93a386Sopenharmony_ci    SkMatrix klm;
625cb93a386Sopenharmony_ci
626cb93a386Sopenharmony_ci    GrPathUtils::getConicKLM(p, weight, &klm);
627cb93a386Sopenharmony_ci
628cb93a386Sopenharmony_ci    for (int i = 0; i < kQuadNumVertices; ++i) {
629cb93a386Sopenharmony_ci        const SkPoint3 pt3 = {verts[i].fPos.x(), verts[i].fPos.y(), 1.f};
630cb93a386Sopenharmony_ci        klm.mapHomogeneousPoints((SkPoint3* ) verts[i].fConic.fKLM, &pt3, 1);
631cb93a386Sopenharmony_ci    }
632cb93a386Sopenharmony_ci}
633cb93a386Sopenharmony_ci
634cb93a386Sopenharmony_civoid add_conics(const SkPoint p[3],
635cb93a386Sopenharmony_ci                const SkScalar weight,
636cb93a386Sopenharmony_ci                const SkMatrix* toDevice,
637cb93a386Sopenharmony_ci                const SkMatrix* toSrc,
638cb93a386Sopenharmony_ci                BezierVertex** vert) {
639cb93a386Sopenharmony_ci    bloat_quad(p, toDevice, toSrc, *vert);
640cb93a386Sopenharmony_ci    set_conic_coeffs(p, *vert, weight);
641cb93a386Sopenharmony_ci    *vert += kQuadNumVertices;
642cb93a386Sopenharmony_ci}
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_civoid add_quads(const SkPoint p[3],
645cb93a386Sopenharmony_ci               int subdiv,
646cb93a386Sopenharmony_ci               const SkMatrix* toDevice,
647cb93a386Sopenharmony_ci               const SkMatrix* toSrc,
648cb93a386Sopenharmony_ci               BezierVertex** vert) {
649cb93a386Sopenharmony_ci    SkASSERT(subdiv >= 0);
650cb93a386Sopenharmony_ci    // temporary vertex storage to avoid reading the vertex buffer
651cb93a386Sopenharmony_ci    BezierVertex outVerts[kQuadNumVertices] = {};
652cb93a386Sopenharmony_ci
653cb93a386Sopenharmony_ci    // storage for the chopped quad
654cb93a386Sopenharmony_ci    // pts 0,1,2 are the first quad, and 2,3,4 the second quad
655cb93a386Sopenharmony_ci    SkPoint choppedQuadPts[5];
656cb93a386Sopenharmony_ci    // start off with our original curve in the second quad slot
657cb93a386Sopenharmony_ci    memcpy(&choppedQuadPts[2], p, 3*sizeof(SkPoint));
658cb93a386Sopenharmony_ci
659cb93a386Sopenharmony_ci    int stepCount = 1 << subdiv;
660cb93a386Sopenharmony_ci    while (stepCount > 1) {
661cb93a386Sopenharmony_ci        // The general idea is:
662cb93a386Sopenharmony_ci        // * chop the quad using pts 2,3,4 as the input
663cb93a386Sopenharmony_ci        // * write out verts using pts 0,1,2
664cb93a386Sopenharmony_ci        // * now 2,3,4 is the remainder of the curve, chop again until all subdivisions are done
665cb93a386Sopenharmony_ci        SkScalar h = 1.f / stepCount;
666cb93a386Sopenharmony_ci        SkChopQuadAt(&choppedQuadPts[2], choppedQuadPts, h);
667cb93a386Sopenharmony_ci
668cb93a386Sopenharmony_ci        bloat_quad(choppedQuadPts, toDevice, toSrc, outVerts);
669cb93a386Sopenharmony_ci        set_uv_quad(choppedQuadPts, outVerts);
670cb93a386Sopenharmony_ci        memcpy(*vert, outVerts, kQuadNumVertices*sizeof(BezierVertex));
671cb93a386Sopenharmony_ci        *vert += kQuadNumVertices;
672cb93a386Sopenharmony_ci        --stepCount;
673cb93a386Sopenharmony_ci    }
674cb93a386Sopenharmony_ci
675cb93a386Sopenharmony_ci    // finish up, write out the final quad
676cb93a386Sopenharmony_ci    bloat_quad(&choppedQuadPts[2], toDevice, toSrc, outVerts);
677cb93a386Sopenharmony_ci    set_uv_quad(&choppedQuadPts[2], outVerts);
678cb93a386Sopenharmony_ci    memcpy(*vert, outVerts, kQuadNumVertices * sizeof(BezierVertex));
679cb93a386Sopenharmony_ci    *vert += kQuadNumVertices;
680cb93a386Sopenharmony_ci}
681cb93a386Sopenharmony_ci
682cb93a386Sopenharmony_civoid add_line(const SkPoint p[2],
683cb93a386Sopenharmony_ci              const SkMatrix* toSrc,
684cb93a386Sopenharmony_ci              uint8_t coverage,
685cb93a386Sopenharmony_ci              LineVertex** vert) {
686cb93a386Sopenharmony_ci    const SkPoint& a = p[0];
687cb93a386Sopenharmony_ci    const SkPoint& b = p[1];
688cb93a386Sopenharmony_ci
689cb93a386Sopenharmony_ci    SkVector ortho, vec = b;
690cb93a386Sopenharmony_ci    vec -= a;
691cb93a386Sopenharmony_ci
692cb93a386Sopenharmony_ci    SkScalar lengthSqd = SkPointPriv::LengthSqd(vec);
693cb93a386Sopenharmony_ci
694cb93a386Sopenharmony_ci    if (vec.setLength(SK_ScalarHalf)) {
695cb93a386Sopenharmony_ci        // Create a vector orthogonal to 'vec' and of unit length
696cb93a386Sopenharmony_ci        ortho.fX = 2.0f * vec.fY;
697cb93a386Sopenharmony_ci        ortho.fY = -2.0f * vec.fX;
698cb93a386Sopenharmony_ci
699cb93a386Sopenharmony_ci        float floatCoverage = GrNormalizeByteToFloat(coverage);
700cb93a386Sopenharmony_ci
701cb93a386Sopenharmony_ci        if (lengthSqd >= 1.0f) {
702cb93a386Sopenharmony_ci            // Relative to points a and b:
703cb93a386Sopenharmony_ci            // The inner vertices are inset half a pixel along the line a,b
704cb93a386Sopenharmony_ci            (*vert)[0].fPos = a + vec;
705cb93a386Sopenharmony_ci            (*vert)[0].fCoverage = floatCoverage;
706cb93a386Sopenharmony_ci            (*vert)[1].fPos = b - vec;
707cb93a386Sopenharmony_ci            (*vert)[1].fCoverage = floatCoverage;
708cb93a386Sopenharmony_ci        } else {
709cb93a386Sopenharmony_ci            // The inner vertices are inset a distance of length(a,b) from the outer edge of
710cb93a386Sopenharmony_ci            // geometry. For the "a" inset this is the same as insetting from b by half a pixel.
711cb93a386Sopenharmony_ci            // The coverage is then modulated by the length. This gives us the correct
712cb93a386Sopenharmony_ci            // coverage for rects shorter than a pixel as they get translated subpixel amounts
713cb93a386Sopenharmony_ci            // inside of a pixel.
714cb93a386Sopenharmony_ci            SkScalar length = SkScalarSqrt(lengthSqd);
715cb93a386Sopenharmony_ci            (*vert)[0].fPos = b - vec;
716cb93a386Sopenharmony_ci            (*vert)[0].fCoverage = floatCoverage * length;
717cb93a386Sopenharmony_ci            (*vert)[1].fPos = a + vec;
718cb93a386Sopenharmony_ci            (*vert)[1].fCoverage = floatCoverage * length;
719cb93a386Sopenharmony_ci        }
720cb93a386Sopenharmony_ci        // Relative to points a and b:
721cb93a386Sopenharmony_ci        // The outer vertices are outset half a pixel along the line a,b and then a whole pixel
722cb93a386Sopenharmony_ci        // orthogonally.
723cb93a386Sopenharmony_ci        (*vert)[2].fPos = a - vec + ortho;
724cb93a386Sopenharmony_ci        (*vert)[2].fCoverage = 0;
725cb93a386Sopenharmony_ci        (*vert)[3].fPos = b + vec + ortho;
726cb93a386Sopenharmony_ci        (*vert)[3].fCoverage = 0;
727cb93a386Sopenharmony_ci        (*vert)[4].fPos = a - vec - ortho;
728cb93a386Sopenharmony_ci        (*vert)[4].fCoverage = 0;
729cb93a386Sopenharmony_ci        (*vert)[5].fPos = b + vec - ortho;
730cb93a386Sopenharmony_ci        (*vert)[5].fCoverage = 0;
731cb93a386Sopenharmony_ci
732cb93a386Sopenharmony_ci        if (toSrc) {
733cb93a386Sopenharmony_ci            SkMatrixPriv::MapPointsWithStride(*toSrc, &(*vert)->fPos, sizeof(LineVertex),
734cb93a386Sopenharmony_ci                                              kLineSegNumVertices);
735cb93a386Sopenharmony_ci        }
736cb93a386Sopenharmony_ci    } else {
737cb93a386Sopenharmony_ci        // just make it degenerate and likely offscreen
738cb93a386Sopenharmony_ci        for (int i = 0; i < kLineSegNumVertices; ++i) {
739cb93a386Sopenharmony_ci            (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax);
740cb93a386Sopenharmony_ci        }
741cb93a386Sopenharmony_ci    }
742cb93a386Sopenharmony_ci
743cb93a386Sopenharmony_ci    *vert += kLineSegNumVertices;
744cb93a386Sopenharmony_ci}
745cb93a386Sopenharmony_ci
746cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
747cb93a386Sopenharmony_ci
748cb93a386Sopenharmony_ciclass AAHairlineOp final : public GrMeshDrawOp {
749cb93a386Sopenharmony_ciprivate:
750cb93a386Sopenharmony_ci    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
751cb93a386Sopenharmony_ci
752cb93a386Sopenharmony_cipublic:
753cb93a386Sopenharmony_ci    DEFINE_OP_CLASS_ID
754cb93a386Sopenharmony_ci
755cb93a386Sopenharmony_ci    static GrOp::Owner Make(GrRecordingContext* context,
756cb93a386Sopenharmony_ci                            GrPaint&& paint,
757cb93a386Sopenharmony_ci                            const SkMatrix& viewMatrix,
758cb93a386Sopenharmony_ci                            const SkPath& path,
759cb93a386Sopenharmony_ci                            const GrStyle& style,
760cb93a386Sopenharmony_ci                            const SkIRect& devClipBounds,
761cb93a386Sopenharmony_ci                            const GrUserStencilSettings* stencilSettings) {
762cb93a386Sopenharmony_ci        SkScalar hairlineCoverage;
763cb93a386Sopenharmony_ci        uint8_t newCoverage = 0xff;
764cb93a386Sopenharmony_ci        if (GrIsStrokeHairlineOrEquivalent(style, viewMatrix, &hairlineCoverage)) {
765cb93a386Sopenharmony_ci            newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
766cb93a386Sopenharmony_ci        }
767cb93a386Sopenharmony_ci
768cb93a386Sopenharmony_ci        const SkStrokeRec& stroke = style.strokeRec();
769cb93a386Sopenharmony_ci        SkScalar capLength = SkPaint::kButt_Cap != stroke.getCap() ? hairlineCoverage * 0.5f : 0.0f;
770cb93a386Sopenharmony_ci
771cb93a386Sopenharmony_ci        return Helper::FactoryHelper<AAHairlineOp>(context, std::move(paint), newCoverage,
772cb93a386Sopenharmony_ci                                                   viewMatrix, path,
773cb93a386Sopenharmony_ci                                                   devClipBounds, capLength, stencilSettings);
774cb93a386Sopenharmony_ci    }
775cb93a386Sopenharmony_ci
776cb93a386Sopenharmony_ci    AAHairlineOp(GrProcessorSet* processorSet,
777cb93a386Sopenharmony_ci                 const SkPMColor4f& color,
778cb93a386Sopenharmony_ci                 uint8_t coverage,
779cb93a386Sopenharmony_ci                 const SkMatrix& viewMatrix,
780cb93a386Sopenharmony_ci                 const SkPath& path,
781cb93a386Sopenharmony_ci                 SkIRect devClipBounds,
782cb93a386Sopenharmony_ci                 SkScalar capLength,
783cb93a386Sopenharmony_ci                 const GrUserStencilSettings* stencilSettings)
784cb93a386Sopenharmony_ci            : INHERITED(ClassID())
785cb93a386Sopenharmony_ci            , fHelper(processorSet, GrAAType::kCoverage, stencilSettings)
786cb93a386Sopenharmony_ci            , fColor(color)
787cb93a386Sopenharmony_ci            , fCoverage(coverage) {
788cb93a386Sopenharmony_ci        fPaths.emplace_back(PathData{viewMatrix, path, devClipBounds, capLength});
789cb93a386Sopenharmony_ci
790cb93a386Sopenharmony_ci        this->setTransformedBounds(path.getBounds(), viewMatrix, HasAABloat::kYes,
791cb93a386Sopenharmony_ci                                   IsHairline::kYes);
792cb93a386Sopenharmony_ci    }
793cb93a386Sopenharmony_ci
794cb93a386Sopenharmony_ci    const char* name() const override { return "AAHairlineOp"; }
795cb93a386Sopenharmony_ci
796cb93a386Sopenharmony_ci    void visitProxies(const GrVisitProxyFunc& func) const override {
797cb93a386Sopenharmony_ci
798cb93a386Sopenharmony_ci        bool visited = false;
799cb93a386Sopenharmony_ci        for (int i = 0; i < 3; ++i) {
800cb93a386Sopenharmony_ci            if (fProgramInfos[i]) {
801cb93a386Sopenharmony_ci                fProgramInfos[i]->visitFPProxies(func);
802cb93a386Sopenharmony_ci                visited = true;
803cb93a386Sopenharmony_ci            }
804cb93a386Sopenharmony_ci        }
805cb93a386Sopenharmony_ci
806cb93a386Sopenharmony_ci        if (!visited) {
807cb93a386Sopenharmony_ci            fHelper.visitProxies(func);
808cb93a386Sopenharmony_ci        }
809cb93a386Sopenharmony_ci    }
810cb93a386Sopenharmony_ci
811cb93a386Sopenharmony_ci    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
812cb93a386Sopenharmony_ci
813cb93a386Sopenharmony_ci    GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
814cb93a386Sopenharmony_ci                                      GrClampType clampType) override {
815cb93a386Sopenharmony_ci        // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
816cb93a386Sopenharmony_ci        return fHelper.finalizeProcessors(caps, clip, clampType,
817cb93a386Sopenharmony_ci                                          GrProcessorAnalysisCoverage::kSingleChannel, &fColor,
818cb93a386Sopenharmony_ci                                          nullptr);
819cb93a386Sopenharmony_ci    }
820cb93a386Sopenharmony_ci
821cb93a386Sopenharmony_ci    enum class Program : uint8_t {
822cb93a386Sopenharmony_ci        kNone  = 0x0,
823cb93a386Sopenharmony_ci        kLine  = 0x1,
824cb93a386Sopenharmony_ci        kQuad  = 0x2,
825cb93a386Sopenharmony_ci        kConic = 0x4,
826cb93a386Sopenharmony_ci    };
827cb93a386Sopenharmony_ci
828cb93a386Sopenharmony_ciprivate:
829cb93a386Sopenharmony_ci    void makeLineProgramInfo(const GrCaps&, SkArenaAlloc*, const GrPipeline*,
830cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
831cb93a386Sopenharmony_ci                             bool usesMSAASurface,
832cb93a386Sopenharmony_ci                             const SkMatrix* geometryProcessorViewM,
833cb93a386Sopenharmony_ci                             const SkMatrix* geometryProcessorLocalM,
834cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
835cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp);
836cb93a386Sopenharmony_ci    void makeQuadProgramInfo(const GrCaps&, SkArenaAlloc*, const GrPipeline*,
837cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
838cb93a386Sopenharmony_ci                             bool usesMSAASurface,
839cb93a386Sopenharmony_ci                             const SkMatrix* geometryProcessorViewM,
840cb93a386Sopenharmony_ci                             const SkMatrix* geometryProcessorLocalM,
841cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
842cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp);
843cb93a386Sopenharmony_ci    void makeConicProgramInfo(const GrCaps&, SkArenaAlloc*, const GrPipeline*,
844cb93a386Sopenharmony_ci                              const GrSurfaceProxyView& writeView,
845cb93a386Sopenharmony_ci                              bool usesMSAASurface,
846cb93a386Sopenharmony_ci                              const SkMatrix* geometryProcessorViewM,
847cb93a386Sopenharmony_ci                              const SkMatrix* geometryProcessorLocalM,
848cb93a386Sopenharmony_ci                              GrXferBarrierFlags renderPassXferBarriers,
849cb93a386Sopenharmony_ci                              GrLoadOp colorLoadOp);
850cb93a386Sopenharmony_ci
851cb93a386Sopenharmony_ci    GrProgramInfo* programInfo() override {
852cb93a386Sopenharmony_ci        // This Op has 3 programInfos and implements its own onPrePrepareDraws so this entry point
853cb93a386Sopenharmony_ci        // should really never be called.
854cb93a386Sopenharmony_ci        SkASSERT(0);
855cb93a386Sopenharmony_ci        return nullptr;
856cb93a386Sopenharmony_ci    }
857cb93a386Sopenharmony_ci
858cb93a386Sopenharmony_ci    Program predictPrograms(const GrCaps*) const;
859cb93a386Sopenharmony_ci
860cb93a386Sopenharmony_ci    void onCreateProgramInfo(const GrCaps*,
861cb93a386Sopenharmony_ci                             SkArenaAlloc*,
862cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
863cb93a386Sopenharmony_ci                             bool usesMSAASurface,
864cb93a386Sopenharmony_ci                             GrAppliedClip&&,
865cb93a386Sopenharmony_ci                             const GrDstProxyView&,
866cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
867cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp) override;
868cb93a386Sopenharmony_ci
869cb93a386Sopenharmony_ci    void onPrePrepareDraws(GrRecordingContext*,
870cb93a386Sopenharmony_ci                           const GrSurfaceProxyView& writeView,
871cb93a386Sopenharmony_ci                           GrAppliedClip*,
872cb93a386Sopenharmony_ci                           const GrDstProxyView&,
873cb93a386Sopenharmony_ci                           GrXferBarrierFlags renderPassXferBarriers,
874cb93a386Sopenharmony_ci                           GrLoadOp colorLoadOp) override;
875cb93a386Sopenharmony_ci
876cb93a386Sopenharmony_ci    void onPrepareDraws(GrMeshDrawTarget*) override;
877cb93a386Sopenharmony_ci    void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
878cb93a386Sopenharmony_ci
879cb93a386Sopenharmony_ci    CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
880cb93a386Sopenharmony_ci        AAHairlineOp* that = t->cast<AAHairlineOp>();
881cb93a386Sopenharmony_ci
882cb93a386Sopenharmony_ci        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
883cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
884cb93a386Sopenharmony_ci        }
885cb93a386Sopenharmony_ci
886cb93a386Sopenharmony_ci        if (this->viewMatrix().hasPerspective() != that->viewMatrix().hasPerspective()) {
887cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
888cb93a386Sopenharmony_ci        }
889cb93a386Sopenharmony_ci
890cb93a386Sopenharmony_ci        // We go to identity if we don't have perspective
891cb93a386Sopenharmony_ci        if (this->viewMatrix().hasPerspective() &&
892cb93a386Sopenharmony_ci            !SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix())) {
893cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
894cb93a386Sopenharmony_ci        }
895cb93a386Sopenharmony_ci
896cb93a386Sopenharmony_ci        // TODO we can actually combine hairlines if they are the same color in a kind of bulk
897cb93a386Sopenharmony_ci        // method but we haven't implemented this yet
898cb93a386Sopenharmony_ci        // TODO investigate going to vertex color and coverage?
899cb93a386Sopenharmony_ci        if (this->coverage() != that->coverage()) {
900cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
901cb93a386Sopenharmony_ci        }
902cb93a386Sopenharmony_ci
903cb93a386Sopenharmony_ci        if (this->color() != that->color()) {
904cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
905cb93a386Sopenharmony_ci        }
906cb93a386Sopenharmony_ci
907cb93a386Sopenharmony_ci        if (fHelper.usesLocalCoords() && !SkMatrixPriv::CheapEqual(this->viewMatrix(),
908cb93a386Sopenharmony_ci                                                                   that->viewMatrix())) {
909cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
910cb93a386Sopenharmony_ci        }
911cb93a386Sopenharmony_ci
912cb93a386Sopenharmony_ci        fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
913cb93a386Sopenharmony_ci        return CombineResult::kMerged;
914cb93a386Sopenharmony_ci    }
915cb93a386Sopenharmony_ci
916cb93a386Sopenharmony_ci#if GR_TEST_UTILS
917cb93a386Sopenharmony_ci    SkString onDumpInfo() const override {
918cb93a386Sopenharmony_ci        return SkStringPrintf("Color: 0x%08x Coverage: 0x%02x, Count: %d\n%s",
919cb93a386Sopenharmony_ci                              fColor.toBytes_RGBA(), fCoverage, fPaths.count(),
920cb93a386Sopenharmony_ci                              fHelper.dumpInfo().c_str());
921cb93a386Sopenharmony_ci    }
922cb93a386Sopenharmony_ci#endif
923cb93a386Sopenharmony_ci
924cb93a386Sopenharmony_ci    const SkPMColor4f& color() const { return fColor; }
925cb93a386Sopenharmony_ci    uint8_t coverage() const { return fCoverage; }
926cb93a386Sopenharmony_ci    const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
927cb93a386Sopenharmony_ci
928cb93a386Sopenharmony_ci    struct PathData {
929cb93a386Sopenharmony_ci        SkMatrix fViewMatrix;
930cb93a386Sopenharmony_ci        SkPath fPath;
931cb93a386Sopenharmony_ci        SkIRect fDevClipBounds;
932cb93a386Sopenharmony_ci        SkScalar fCapLength;
933cb93a386Sopenharmony_ci    };
934cb93a386Sopenharmony_ci
935cb93a386Sopenharmony_ci    SkSTArray<1, PathData, true> fPaths;
936cb93a386Sopenharmony_ci    Helper fHelper;
937cb93a386Sopenharmony_ci    SkPMColor4f fColor;
938cb93a386Sopenharmony_ci    uint8_t fCoverage;
939cb93a386Sopenharmony_ci
940cb93a386Sopenharmony_ci    Program        fCharacterization = Program::kNone;       // holds a mask of required programs
941cb93a386Sopenharmony_ci    GrSimpleMesh*  fMeshes[3] = { nullptr };
942cb93a386Sopenharmony_ci    GrProgramInfo* fProgramInfos[3] = { nullptr };
943cb93a386Sopenharmony_ci
944cb93a386Sopenharmony_ci    using INHERITED = GrMeshDrawOp;
945cb93a386Sopenharmony_ci};
946cb93a386Sopenharmony_ci
947cb93a386Sopenharmony_ciGR_MAKE_BITFIELD_CLASS_OPS(AAHairlineOp::Program)
948cb93a386Sopenharmony_ci
949cb93a386Sopenharmony_civoid AAHairlineOp::makeLineProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
950cb93a386Sopenharmony_ci                                       const GrPipeline* pipeline,
951cb93a386Sopenharmony_ci                                       const GrSurfaceProxyView& writeView,
952cb93a386Sopenharmony_ci                                       bool usesMSAASurface,
953cb93a386Sopenharmony_ci                                       const SkMatrix* geometryProcessorViewM,
954cb93a386Sopenharmony_ci                                       const SkMatrix* geometryProcessorLocalM,
955cb93a386Sopenharmony_ci                                       GrXferBarrierFlags renderPassXferBarriers,
956cb93a386Sopenharmony_ci                                       GrLoadOp colorLoadOp) {
957cb93a386Sopenharmony_ci    if (fProgramInfos[0]) {
958cb93a386Sopenharmony_ci        return;
959cb93a386Sopenharmony_ci    }
960cb93a386Sopenharmony_ci
961cb93a386Sopenharmony_ci    GrGeometryProcessor* lineGP;
962cb93a386Sopenharmony_ci    {
963cb93a386Sopenharmony_ci        using namespace GrDefaultGeoProcFactory;
964cb93a386Sopenharmony_ci
965cb93a386Sopenharmony_ci        Color color(this->color());
966cb93a386Sopenharmony_ci        LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
967cb93a386Sopenharmony_ci                                                          : LocalCoords::kUnused_Type);
968cb93a386Sopenharmony_ci        localCoords.fMatrix = geometryProcessorLocalM;
969cb93a386Sopenharmony_ci
970cb93a386Sopenharmony_ci        lineGP = GrDefaultGeoProcFactory::Make(arena,
971cb93a386Sopenharmony_ci                                               color,
972cb93a386Sopenharmony_ci                                               Coverage::kAttribute_Type,
973cb93a386Sopenharmony_ci                                               localCoords,
974cb93a386Sopenharmony_ci                                               *geometryProcessorViewM);
975cb93a386Sopenharmony_ci        SkASSERT(sizeof(LineVertex) == lineGP->vertexStride());
976cb93a386Sopenharmony_ci    }
977cb93a386Sopenharmony_ci
978cb93a386Sopenharmony_ci    fProgramInfos[0] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
979cb93a386Sopenharmony_ci            &caps, arena, pipeline, writeView, usesMSAASurface, lineGP, GrPrimitiveType::kTriangles,
980cb93a386Sopenharmony_ci            renderPassXferBarriers, colorLoadOp, fHelper.stencilSettings());
981cb93a386Sopenharmony_ci}
982cb93a386Sopenharmony_ci
983cb93a386Sopenharmony_civoid AAHairlineOp::makeQuadProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
984cb93a386Sopenharmony_ci                                       const GrPipeline* pipeline,
985cb93a386Sopenharmony_ci                                       const GrSurfaceProxyView& writeView,
986cb93a386Sopenharmony_ci                                       bool usesMSAASurface,
987cb93a386Sopenharmony_ci                                       const SkMatrix* geometryProcessorViewM,
988cb93a386Sopenharmony_ci                                       const SkMatrix* geometryProcessorLocalM,
989cb93a386Sopenharmony_ci                                       GrXferBarrierFlags renderPassXferBarriers,
990cb93a386Sopenharmony_ci                                       GrLoadOp colorLoadOp) {
991cb93a386Sopenharmony_ci    if (fProgramInfos[1]) {
992cb93a386Sopenharmony_ci        return;
993cb93a386Sopenharmony_ci    }
994cb93a386Sopenharmony_ci
995cb93a386Sopenharmony_ci    GrGeometryProcessor* quadGP = GrQuadEffect::Make(arena,
996cb93a386Sopenharmony_ci                                                     this->color(),
997cb93a386Sopenharmony_ci                                                     *geometryProcessorViewM,
998cb93a386Sopenharmony_ci                                                     caps,
999cb93a386Sopenharmony_ci                                                     *geometryProcessorLocalM,
1000cb93a386Sopenharmony_ci                                                     fHelper.usesLocalCoords(),
1001cb93a386Sopenharmony_ci                                                     this->coverage());
1002cb93a386Sopenharmony_ci    SkASSERT(sizeof(BezierVertex) == quadGP->vertexStride());
1003cb93a386Sopenharmony_ci
1004cb93a386Sopenharmony_ci    fProgramInfos[1] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
1005cb93a386Sopenharmony_ci            &caps, arena, pipeline, writeView, usesMSAASurface, quadGP, GrPrimitiveType::kTriangles,
1006cb93a386Sopenharmony_ci            renderPassXferBarriers, colorLoadOp, fHelper.stencilSettings());
1007cb93a386Sopenharmony_ci}
1008cb93a386Sopenharmony_ci
1009cb93a386Sopenharmony_civoid AAHairlineOp::makeConicProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
1010cb93a386Sopenharmony_ci                                        const GrPipeline* pipeline,
1011cb93a386Sopenharmony_ci                                        const GrSurfaceProxyView& writeView,
1012cb93a386Sopenharmony_ci                                        bool usesMSAASurface,
1013cb93a386Sopenharmony_ci                                        const SkMatrix* geometryProcessorViewM,
1014cb93a386Sopenharmony_ci                                        const SkMatrix* geometryProcessorLocalM,
1015cb93a386Sopenharmony_ci                                        GrXferBarrierFlags renderPassXferBarriers,
1016cb93a386Sopenharmony_ci                                        GrLoadOp colorLoadOp) {
1017cb93a386Sopenharmony_ci    if (fProgramInfos[2]) {
1018cb93a386Sopenharmony_ci        return;
1019cb93a386Sopenharmony_ci    }
1020cb93a386Sopenharmony_ci
1021cb93a386Sopenharmony_ci    GrGeometryProcessor* conicGP = GrConicEffect::Make(arena,
1022cb93a386Sopenharmony_ci                                                       this->color(),
1023cb93a386Sopenharmony_ci                                                       *geometryProcessorViewM,
1024cb93a386Sopenharmony_ci                                                       caps,
1025cb93a386Sopenharmony_ci                                                       *geometryProcessorLocalM,
1026cb93a386Sopenharmony_ci                                                       fHelper.usesLocalCoords(),
1027cb93a386Sopenharmony_ci                                                       this->coverage());
1028cb93a386Sopenharmony_ci    SkASSERT(sizeof(BezierVertex) == conicGP->vertexStride());
1029cb93a386Sopenharmony_ci
1030cb93a386Sopenharmony_ci    fProgramInfos[2] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
1031cb93a386Sopenharmony_ci            &caps, arena, pipeline, writeView, usesMSAASurface, conicGP,
1032cb93a386Sopenharmony_ci            GrPrimitiveType::kTriangles, renderPassXferBarriers, colorLoadOp,
1033cb93a386Sopenharmony_ci            fHelper.stencilSettings());
1034cb93a386Sopenharmony_ci}
1035cb93a386Sopenharmony_ci
1036cb93a386Sopenharmony_ciAAHairlineOp::Program AAHairlineOp::predictPrograms(const GrCaps* caps) const {
1037cb93a386Sopenharmony_ci    bool convertConicsToQuads = !caps->shaderCaps()->floatIs32Bits();
1038cb93a386Sopenharmony_ci
1039cb93a386Sopenharmony_ci    // When predicting the programs we always include the lineProgram bc it is used as a fallback
1040cb93a386Sopenharmony_ci    // for quads and conics. In non-DDL mode there are cases where it sometimes isn't needed for a
1041cb93a386Sopenharmony_ci    // given path.
1042cb93a386Sopenharmony_ci    Program neededPrograms = Program::kLine;
1043cb93a386Sopenharmony_ci
1044cb93a386Sopenharmony_ci    for (int i = 0; i < fPaths.count(); i++) {
1045cb93a386Sopenharmony_ci        uint32_t mask = fPaths[i].fPath.getSegmentMasks();
1046cb93a386Sopenharmony_ci
1047cb93a386Sopenharmony_ci        if (mask & (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)) {
1048cb93a386Sopenharmony_ci            neededPrograms |= Program::kQuad;
1049cb93a386Sopenharmony_ci        }
1050cb93a386Sopenharmony_ci        if (mask & SkPath::kConic_SegmentMask) {
1051cb93a386Sopenharmony_ci            if (convertConicsToQuads) {
1052cb93a386Sopenharmony_ci                neededPrograms |= Program::kQuad;
1053cb93a386Sopenharmony_ci            } else {
1054cb93a386Sopenharmony_ci                neededPrograms |= Program::kConic;
1055cb93a386Sopenharmony_ci            }
1056cb93a386Sopenharmony_ci        }
1057cb93a386Sopenharmony_ci    }
1058cb93a386Sopenharmony_ci
1059cb93a386Sopenharmony_ci    return neededPrograms;
1060cb93a386Sopenharmony_ci}
1061cb93a386Sopenharmony_ci
1062cb93a386Sopenharmony_civoid AAHairlineOp::onCreateProgramInfo(const GrCaps* caps,
1063cb93a386Sopenharmony_ci                                       SkArenaAlloc* arena,
1064cb93a386Sopenharmony_ci                                       const GrSurfaceProxyView& writeView,
1065cb93a386Sopenharmony_ci                                       bool usesMSAASurface,
1066cb93a386Sopenharmony_ci                                       GrAppliedClip&& appliedClip,
1067cb93a386Sopenharmony_ci                                       const GrDstProxyView& dstProxyView,
1068cb93a386Sopenharmony_ci                                       GrXferBarrierFlags renderPassXferBarriers,
1069cb93a386Sopenharmony_ci                                       GrLoadOp colorLoadOp) {
1070cb93a386Sopenharmony_ci    // Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
1071cb93a386Sopenharmony_ci    SkMatrix invert;
1072cb93a386Sopenharmony_ci    if (!this->viewMatrix().invert(&invert)) {
1073cb93a386Sopenharmony_ci        return;
1074cb93a386Sopenharmony_ci    }
1075cb93a386Sopenharmony_ci
1076cb93a386Sopenharmony_ci    // we will transform to identity space if the viewmatrix does not have perspective
1077cb93a386Sopenharmony_ci    bool hasPerspective = this->viewMatrix().hasPerspective();
1078cb93a386Sopenharmony_ci    const SkMatrix* geometryProcessorViewM = &SkMatrix::I();
1079cb93a386Sopenharmony_ci    const SkMatrix* geometryProcessorLocalM = &invert;
1080cb93a386Sopenharmony_ci    if (hasPerspective) {
1081cb93a386Sopenharmony_ci        geometryProcessorViewM = &this->viewMatrix();
1082cb93a386Sopenharmony_ci        geometryProcessorLocalM = &SkMatrix::I();
1083cb93a386Sopenharmony_ci    }
1084cb93a386Sopenharmony_ci
1085cb93a386Sopenharmony_ci    auto pipeline = fHelper.createPipeline(caps, arena, writeView.swizzle(),
1086cb93a386Sopenharmony_ci                                           std::move(appliedClip), dstProxyView);
1087cb93a386Sopenharmony_ci
1088cb93a386Sopenharmony_ci    if (fCharacterization & Program::kLine) {
1089cb93a386Sopenharmony_ci        this->makeLineProgramInfo(*caps, arena, pipeline, writeView, usesMSAASurface,
1090cb93a386Sopenharmony_ci                                  geometryProcessorViewM, geometryProcessorLocalM,
1091cb93a386Sopenharmony_ci                                  renderPassXferBarriers, colorLoadOp);
1092cb93a386Sopenharmony_ci    }
1093cb93a386Sopenharmony_ci    if (fCharacterization & Program::kQuad) {
1094cb93a386Sopenharmony_ci        this->makeQuadProgramInfo(*caps, arena, pipeline, writeView, usesMSAASurface,
1095cb93a386Sopenharmony_ci                                  geometryProcessorViewM, geometryProcessorLocalM,
1096cb93a386Sopenharmony_ci                                  renderPassXferBarriers, colorLoadOp);
1097cb93a386Sopenharmony_ci    }
1098cb93a386Sopenharmony_ci    if (fCharacterization & Program::kConic) {
1099cb93a386Sopenharmony_ci        this->makeConicProgramInfo(*caps, arena, pipeline, writeView, usesMSAASurface,
1100cb93a386Sopenharmony_ci                                   geometryProcessorViewM, geometryProcessorLocalM,
1101cb93a386Sopenharmony_ci                                   renderPassXferBarriers, colorLoadOp);
1102cb93a386Sopenharmony_ci
1103cb93a386Sopenharmony_ci    }
1104cb93a386Sopenharmony_ci}
1105cb93a386Sopenharmony_ci
1106cb93a386Sopenharmony_civoid AAHairlineOp::onPrePrepareDraws(GrRecordingContext* context,
1107cb93a386Sopenharmony_ci                                     const GrSurfaceProxyView& writeView,
1108cb93a386Sopenharmony_ci                                     GrAppliedClip* clip,
1109cb93a386Sopenharmony_ci                                     const GrDstProxyView& dstProxyView,
1110cb93a386Sopenharmony_ci                                     GrXferBarrierFlags renderPassXferBarriers,
1111cb93a386Sopenharmony_ci                                     GrLoadOp colorLoadOp) {
1112cb93a386Sopenharmony_ci    SkArenaAlloc* arena = context->priv().recordTimeAllocator();
1113cb93a386Sopenharmony_ci    const GrCaps* caps = context->priv().caps();
1114cb93a386Sopenharmony_ci
1115cb93a386Sopenharmony_ci    // http://skbug.com/12201 -- DDL does not yet support DMSAA.
1116cb93a386Sopenharmony_ci    bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
1117cb93a386Sopenharmony_ci
1118cb93a386Sopenharmony_ci    // This is equivalent to a GrOpFlushState::detachAppliedClip
1119cb93a386Sopenharmony_ci    GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
1120cb93a386Sopenharmony_ci
1121cb93a386Sopenharmony_ci    // Conservatively predict which programs will be required
1122cb93a386Sopenharmony_ci    fCharacterization = this->predictPrograms(caps);
1123cb93a386Sopenharmony_ci
1124cb93a386Sopenharmony_ci    this->createProgramInfo(caps, arena, writeView, usesMSAASurface, std::move(appliedClip),
1125cb93a386Sopenharmony_ci                            dstProxyView, renderPassXferBarriers, colorLoadOp);
1126cb93a386Sopenharmony_ci
1127cb93a386Sopenharmony_ci    context->priv().recordProgramInfo(fProgramInfos[0]);
1128cb93a386Sopenharmony_ci    context->priv().recordProgramInfo(fProgramInfos[1]);
1129cb93a386Sopenharmony_ci    context->priv().recordProgramInfo(fProgramInfos[2]);
1130cb93a386Sopenharmony_ci}
1131cb93a386Sopenharmony_ci
1132cb93a386Sopenharmony_civoid AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
1133cb93a386Sopenharmony_ci    // Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
1134cb93a386Sopenharmony_ci    SkMatrix invert;
1135cb93a386Sopenharmony_ci    if (!this->viewMatrix().invert(&invert)) {
1136cb93a386Sopenharmony_ci        return;
1137cb93a386Sopenharmony_ci    }
1138cb93a386Sopenharmony_ci
1139cb93a386Sopenharmony_ci    // we will transform to identity space if the viewmatrix does not have perspective
1140cb93a386Sopenharmony_ci    const SkMatrix* toDevice = nullptr;
1141cb93a386Sopenharmony_ci    const SkMatrix* toSrc = nullptr;
1142cb93a386Sopenharmony_ci    if (this->viewMatrix().hasPerspective()) {
1143cb93a386Sopenharmony_ci        toDevice = &this->viewMatrix();
1144cb93a386Sopenharmony_ci        toSrc = &invert;
1145cb93a386Sopenharmony_ci    }
1146cb93a386Sopenharmony_ci
1147cb93a386Sopenharmony_ci    SkDEBUGCODE(Program predictedPrograms = this->predictPrograms(&target->caps()));
1148cb93a386Sopenharmony_ci    Program actualPrograms = Program::kNone;
1149cb93a386Sopenharmony_ci
1150cb93a386Sopenharmony_ci    // This is hand inlined for maximum performance.
1151cb93a386Sopenharmony_ci    PREALLOC_PTARRAY(128) lines;
1152cb93a386Sopenharmony_ci    PREALLOC_PTARRAY(128) quads;
1153cb93a386Sopenharmony_ci    PREALLOC_PTARRAY(128) conics;
1154cb93a386Sopenharmony_ci    IntArray qSubdivs;
1155cb93a386Sopenharmony_ci    FloatArray cWeights;
1156cb93a386Sopenharmony_ci    int quadCount = 0;
1157cb93a386Sopenharmony_ci
1158cb93a386Sopenharmony_ci    int instanceCount = fPaths.count();
1159cb93a386Sopenharmony_ci    bool convertConicsToQuads = !target->caps().shaderCaps()->floatIs32Bits();
1160cb93a386Sopenharmony_ci    for (int i = 0; i < instanceCount; i++) {
1161cb93a386Sopenharmony_ci        const PathData& args = fPaths[i];
1162cb93a386Sopenharmony_ci        quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds,
1163cb93a386Sopenharmony_ci                                            args.fCapLength, convertConicsToQuads, &lines, &quads,
1164cb93a386Sopenharmony_ci                                            &conics, &qSubdivs, &cWeights);
1165cb93a386Sopenharmony_ci    }
1166cb93a386Sopenharmony_ci
1167cb93a386Sopenharmony_ci    int lineCount = lines.count() / 2;
1168cb93a386Sopenharmony_ci    int conicCount = conics.count() / 3;
1169cb93a386Sopenharmony_ci    int quadAndConicCount = conicCount + quadCount;
1170cb93a386Sopenharmony_ci
1171cb93a386Sopenharmony_ci    static constexpr int kMaxLines = SK_MaxS32 / kLineSegNumVertices;
1172cb93a386Sopenharmony_ci    static constexpr int kMaxQuadsAndConics = SK_MaxS32 / kQuadNumVertices;
1173cb93a386Sopenharmony_ci    if (lineCount > kMaxLines || quadAndConicCount > kMaxQuadsAndConics) {
1174cb93a386Sopenharmony_ci        return;
1175cb93a386Sopenharmony_ci    }
1176cb93a386Sopenharmony_ci
1177cb93a386Sopenharmony_ci    // do lines first
1178cb93a386Sopenharmony_ci    if (lineCount) {
1179cb93a386Sopenharmony_ci        SkASSERT(predictedPrograms & Program::kLine);
1180cb93a386Sopenharmony_ci        actualPrograms |= Program::kLine;
1181cb93a386Sopenharmony_ci
1182cb93a386Sopenharmony_ci        sk_sp<const GrBuffer> linesIndexBuffer = get_lines_index_buffer(target->resourceProvider());
1183cb93a386Sopenharmony_ci
1184cb93a386Sopenharmony_ci        GrMeshDrawOp::PatternHelper helper(target, GrPrimitiveType::kTriangles, sizeof(LineVertex),
1185cb93a386Sopenharmony_ci                                           std::move(linesIndexBuffer), kLineSegNumVertices,
1186cb93a386Sopenharmony_ci                                           kIdxsPerLineSeg, lineCount, kLineSegsNumInIdxBuffer);
1187cb93a386Sopenharmony_ci
1188cb93a386Sopenharmony_ci        LineVertex* verts = reinterpret_cast<LineVertex*>(helper.vertices());
1189cb93a386Sopenharmony_ci        if (!verts) {
1190cb93a386Sopenharmony_ci            SkDebugf("Could not allocate vertices\n");
1191cb93a386Sopenharmony_ci            return;
1192cb93a386Sopenharmony_ci        }
1193cb93a386Sopenharmony_ci
1194cb93a386Sopenharmony_ci        for (int i = 0; i < lineCount; ++i) {
1195cb93a386Sopenharmony_ci            add_line(&lines[2*i], toSrc, this->coverage(), &verts);
1196cb93a386Sopenharmony_ci        }
1197cb93a386Sopenharmony_ci
1198cb93a386Sopenharmony_ci        fMeshes[0] = helper.mesh();
1199cb93a386Sopenharmony_ci    }
1200cb93a386Sopenharmony_ci
1201cb93a386Sopenharmony_ci    if (quadCount || conicCount) {
1202cb93a386Sopenharmony_ci        sk_sp<const GrBuffer> vertexBuffer;
1203cb93a386Sopenharmony_ci        int firstVertex;
1204cb93a386Sopenharmony_ci
1205cb93a386Sopenharmony_ci        sk_sp<const GrBuffer> quadsIndexBuffer = get_quads_index_buffer(target->resourceProvider());
1206cb93a386Sopenharmony_ci
1207cb93a386Sopenharmony_ci        int vertexCount = kQuadNumVertices * quadAndConicCount;
1208cb93a386Sopenharmony_ci        void* vertices = target->makeVertexSpace(sizeof(BezierVertex), vertexCount, &vertexBuffer,
1209cb93a386Sopenharmony_ci                                                 &firstVertex);
1210cb93a386Sopenharmony_ci
1211cb93a386Sopenharmony_ci        if (!vertices || !quadsIndexBuffer) {
1212cb93a386Sopenharmony_ci            SkDebugf("Could not allocate vertices\n");
1213cb93a386Sopenharmony_ci            return;
1214cb93a386Sopenharmony_ci        }
1215cb93a386Sopenharmony_ci
1216cb93a386Sopenharmony_ci        // Setup vertices
1217cb93a386Sopenharmony_ci        BezierVertex* bezVerts = reinterpret_cast<BezierVertex*>(vertices);
1218cb93a386Sopenharmony_ci
1219cb93a386Sopenharmony_ci        int unsubdivQuadCnt = quads.count() / 3;
1220cb93a386Sopenharmony_ci        for (int i = 0; i < unsubdivQuadCnt; ++i) {
1221cb93a386Sopenharmony_ci            SkASSERT(qSubdivs[i] >= 0);
1222cb93a386Sopenharmony_ci            if (!quads[3*i].isFinite() || !quads[3*i+1].isFinite() || !quads[3*i+2].isFinite()) {
1223cb93a386Sopenharmony_ci                return;
1224cb93a386Sopenharmony_ci            }
1225cb93a386Sopenharmony_ci            add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &bezVerts);
1226cb93a386Sopenharmony_ci        }
1227cb93a386Sopenharmony_ci
1228cb93a386Sopenharmony_ci        // Start Conics
1229cb93a386Sopenharmony_ci        for (int i = 0; i < conicCount; ++i) {
1230cb93a386Sopenharmony_ci            add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &bezVerts);
1231cb93a386Sopenharmony_ci        }
1232cb93a386Sopenharmony_ci
1233cb93a386Sopenharmony_ci        if (quadCount > 0) {
1234cb93a386Sopenharmony_ci            SkASSERT(predictedPrograms & Program::kQuad);
1235cb93a386Sopenharmony_ci            actualPrograms |= Program::kQuad;
1236cb93a386Sopenharmony_ci
1237cb93a386Sopenharmony_ci            fMeshes[1] = target->allocMesh();
1238cb93a386Sopenharmony_ci            fMeshes[1]->setIndexedPatterned(quadsIndexBuffer, kIdxsPerQuad, quadCount,
1239cb93a386Sopenharmony_ci                                            kQuadsNumInIdxBuffer, vertexBuffer, kQuadNumVertices,
1240cb93a386Sopenharmony_ci                                            firstVertex);
1241cb93a386Sopenharmony_ci            firstVertex += quadCount * kQuadNumVertices;
1242cb93a386Sopenharmony_ci        }
1243cb93a386Sopenharmony_ci
1244cb93a386Sopenharmony_ci        if (conicCount > 0) {
1245cb93a386Sopenharmony_ci            SkASSERT(predictedPrograms & Program::kConic);
1246cb93a386Sopenharmony_ci            actualPrograms |= Program::kConic;
1247cb93a386Sopenharmony_ci
1248cb93a386Sopenharmony_ci            fMeshes[2] = target->allocMesh();
1249cb93a386Sopenharmony_ci            fMeshes[2]->setIndexedPatterned(std::move(quadsIndexBuffer), kIdxsPerQuad, conicCount,
1250cb93a386Sopenharmony_ci                                            kQuadsNumInIdxBuffer, std::move(vertexBuffer),
1251cb93a386Sopenharmony_ci                                            kQuadNumVertices, firstVertex);
1252cb93a386Sopenharmony_ci        }
1253cb93a386Sopenharmony_ci    }
1254cb93a386Sopenharmony_ci
1255cb93a386Sopenharmony_ci    // In DDL mode this will replace the predicted program requirements with the actual ones.
1256cb93a386Sopenharmony_ci    // However, we will already have surfaced the predicted programs to the DDL.
1257cb93a386Sopenharmony_ci    fCharacterization = actualPrograms;
1258cb93a386Sopenharmony_ci}
1259cb93a386Sopenharmony_ci
1260cb93a386Sopenharmony_civoid AAHairlineOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
1261cb93a386Sopenharmony_ci    this->createProgramInfo(flushState);
1262cb93a386Sopenharmony_ci
1263cb93a386Sopenharmony_ci    for (int i = 0; i < 3; ++i) {
1264cb93a386Sopenharmony_ci        if (fProgramInfos[i] && fMeshes[i]) {
1265cb93a386Sopenharmony_ci            flushState->bindPipelineAndScissorClip(*fProgramInfos[i], chainBounds);
1266cb93a386Sopenharmony_ci            flushState->bindTextures(fProgramInfos[i]->geomProc(), nullptr,
1267cb93a386Sopenharmony_ci                                     fProgramInfos[i]->pipeline());
1268cb93a386Sopenharmony_ci            flushState->drawMesh(*fMeshes[i]);
1269cb93a386Sopenharmony_ci        }
1270cb93a386Sopenharmony_ci    }
1271cb93a386Sopenharmony_ci}
1272cb93a386Sopenharmony_ci
1273cb93a386Sopenharmony_ci} // anonymous namespace
1274cb93a386Sopenharmony_ci
1275cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
1276cb93a386Sopenharmony_ci
1277cb93a386Sopenharmony_ci#if GR_TEST_UTILS
1278cb93a386Sopenharmony_ci
1279cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(AAHairlineOp) {
1280cb93a386Sopenharmony_ci    SkMatrix viewMatrix = GrTest::TestMatrix(random);
1281cb93a386Sopenharmony_ci    const SkPath& path = GrTest::TestPath(random);
1282cb93a386Sopenharmony_ci    SkIRect devClipBounds;
1283cb93a386Sopenharmony_ci    devClipBounds.setEmpty();
1284cb93a386Sopenharmony_ci    return AAHairlineOp::Make(context, std::move(paint), viewMatrix, path,
1285cb93a386Sopenharmony_ci                              GrStyle::SimpleHairline(), devClipBounds,
1286cb93a386Sopenharmony_ci                              GrGetRandomStencil(random, context));
1287cb93a386Sopenharmony_ci}
1288cb93a386Sopenharmony_ci
1289cb93a386Sopenharmony_ci#endif
1290cb93a386Sopenharmony_ci
1291cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
1292cb93a386Sopenharmony_ci
1293cb93a386Sopenharmony_cinamespace skgpu::v1 {
1294cb93a386Sopenharmony_ci
1295cb93a386Sopenharmony_ciPathRenderer::CanDrawPath AAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
1296cb93a386Sopenharmony_ci    if (GrAAType::kCoverage != args.fAAType) {
1297cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
1298cb93a386Sopenharmony_ci    }
1299cb93a386Sopenharmony_ci
1300cb93a386Sopenharmony_ci    if (!GrIsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr)) {
1301cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
1302cb93a386Sopenharmony_ci    }
1303cb93a386Sopenharmony_ci
1304cb93a386Sopenharmony_ci    // We don't currently handle dashing in this class though perhaps we should.
1305cb93a386Sopenharmony_ci    if (args.fShape->style().pathEffect()) {
1306cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
1307cb93a386Sopenharmony_ci    }
1308cb93a386Sopenharmony_ci
1309cb93a386Sopenharmony_ci    if (SkPath::kLine_SegmentMask == args.fShape->segmentMask() ||
1310cb93a386Sopenharmony_ci        args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
1311cb93a386Sopenharmony_ci        return CanDrawPath::kYes;
1312cb93a386Sopenharmony_ci    }
1313cb93a386Sopenharmony_ci
1314cb93a386Sopenharmony_ci    return CanDrawPath::kNo;
1315cb93a386Sopenharmony_ci}
1316cb93a386Sopenharmony_ci
1317cb93a386Sopenharmony_ci
1318cb93a386Sopenharmony_cibool AAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
1319cb93a386Sopenharmony_ci    GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
1320cb93a386Sopenharmony_ci                              "AAHairlinePathRenderer::onDrawPath");
1321cb93a386Sopenharmony_ci    SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
1322cb93a386Sopenharmony_ci
1323cb93a386Sopenharmony_ci    SkPath path;
1324cb93a386Sopenharmony_ci    args.fShape->asPath(&path);
1325cb93a386Sopenharmony_ci    GrOp::Owner op =
1326cb93a386Sopenharmony_ci            AAHairlineOp::Make(args.fContext, std::move(args.fPaint), *args.fViewMatrix, path,
1327cb93a386Sopenharmony_ci                               args.fShape->style(), *args.fClipConservativeBounds,
1328cb93a386Sopenharmony_ci                               args.fUserStencilSettings);
1329cb93a386Sopenharmony_ci    args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
1330cb93a386Sopenharmony_ci    return true;
1331cb93a386Sopenharmony_ci}
1332cb93a386Sopenharmony_ci
1333cb93a386Sopenharmony_ci} // namespace skgpu::v1
1334cb93a386Sopenharmony_ci
1335