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