xref: /aosp_15_r20/external/skia/src/gpu/tessellate/Tessellation.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 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 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_tessellate_Tessellation_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_tessellate_Tessellation_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStrokeRec.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMacros.h"
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker #include <math.h>
18*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
19*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
20*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker class SkMatrix;
23*c8dee2aaSAndroid Build Coastguard Worker class SkPath;
24*c8dee2aaSAndroid Build Coastguard Worker struct SkRect;
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::tess {
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker // Don't allow linearized segments to be off by more than 1/4th of a pixel from the true curve.
29*c8dee2aaSAndroid Build Coastguard Worker constexpr static float kPrecision = 4;
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker // This is the maximum number of subdivisions of a Bezier curve that can be represented in the fixed
32*c8dee2aaSAndroid Build Coastguard Worker // count vertex and index buffers. If rendering a curve that requires more subdivisions, it must be
33*c8dee2aaSAndroid Build Coastguard Worker // chopped.
34*c8dee2aaSAndroid Build Coastguard Worker constexpr static int kMaxResolveLevel = 5;
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker // This is the maximum number of parametric segments (linear sections) that a curve can be split
37*c8dee2aaSAndroid Build Coastguard Worker // into. This is the same for path filling and stroking, although fixed-count stroking also uses
38*c8dee2aaSAndroid Build Coastguard Worker // additional vertices to handle radial segments, joins, and caps. Additionally the fixed-count
39*c8dee2aaSAndroid Build Coastguard Worker // path filling algorithms snap their dynamic vertex counts to powers-of-two, whereas the stroking
40*c8dee2aaSAndroid Build Coastguard Worker // algorithm does not.
41*c8dee2aaSAndroid Build Coastguard Worker constexpr static int kMaxParametricSegments = 1 << kMaxResolveLevel;
42*c8dee2aaSAndroid Build Coastguard Worker constexpr static int kMaxParametricSegments_p2 = kMaxParametricSegments * kMaxParametricSegments;
43*c8dee2aaSAndroid Build Coastguard Worker constexpr static int kMaxParametricSegments_p4 = kMaxParametricSegments_p2 *
44*c8dee2aaSAndroid Build Coastguard Worker                                                  kMaxParametricSegments_p2;
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker // Don't tessellate paths that might have an individual curve that requires more than 1024 segments.
47*c8dee2aaSAndroid Build Coastguard Worker // (See wangs_formula::worst_case_cubic). If this is the case, call "PreChopPathCurves" first.
48*c8dee2aaSAndroid Build Coastguard Worker // Standard chopping, when Wang's formula is between kMaxParametricSegments and
49*c8dee2aaSAndroid Build Coastguard Worker // kMaxTessellationSegmentsPerCurve is handled automatically by PatchWriter. It differs from
50*c8dee2aaSAndroid Build Coastguard Worker // PreChopPathCurves in that it does no culling of offscreen chopped paths.
51*c8dee2aaSAndroid Build Coastguard Worker constexpr static float kMaxSegmentsPerCurve = 1024;
52*c8dee2aaSAndroid Build Coastguard Worker constexpr static float kMaxSegmentsPerCurve_p2 = kMaxSegmentsPerCurve * kMaxSegmentsPerCurve;
53*c8dee2aaSAndroid Build Coastguard Worker constexpr static float kMaxSegmentsPerCurve_p4 = kMaxSegmentsPerCurve_p2 * kMaxSegmentsPerCurve_p2;
54*c8dee2aaSAndroid Build Coastguard Worker 
55*c8dee2aaSAndroid Build Coastguard Worker // Returns a new path, equivalent to 'path' within the given viewport, whose verbs can all be drawn
56*c8dee2aaSAndroid Build Coastguard Worker // with 'maxSegments' tessellation segments or fewer, while staying within '1/tessellationPrecision'
57*c8dee2aaSAndroid Build Coastguard Worker // pixels of the true curve. Curves and chops that fall completely outside the viewport are
58*c8dee2aaSAndroid Build Coastguard Worker // flattened into lines.
59*c8dee2aaSAndroid Build Coastguard Worker SkPath PreChopPathCurves(float tessellationPrecision,
60*c8dee2aaSAndroid Build Coastguard Worker                          const SkPath&,
61*c8dee2aaSAndroid Build Coastguard Worker                          const SkMatrix&,
62*c8dee2aaSAndroid Build Coastguard Worker                          const SkRect& viewport);
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker // How many triangles are in a curve with 2^resolveLevel line segments?
65*c8dee2aaSAndroid Build Coastguard Worker // Resolve level defines the tessellation factor for filled paths drawn using curves or wedges.
NumCurveTrianglesAtResolveLevel(int resolveLevel)66*c8dee2aaSAndroid Build Coastguard Worker constexpr static int NumCurveTrianglesAtResolveLevel(int resolveLevel) {
67*c8dee2aaSAndroid Build Coastguard Worker     // resolveLevel=0 -> 0 line segments -> 0 triangles
68*c8dee2aaSAndroid Build Coastguard Worker     // resolveLevel=1 -> 2 line segments -> 1 triangle
69*c8dee2aaSAndroid Build Coastguard Worker     // resolveLevel=2 -> 4 line segments -> 3 triangles
70*c8dee2aaSAndroid Build Coastguard Worker     // resolveLevel=3 -> 8 line segments -> 7 triangles
71*c8dee2aaSAndroid Build Coastguard Worker     // ...
72*c8dee2aaSAndroid Build Coastguard Worker     return (1 << resolveLevel) - 1;
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker // Optional attribs that are included in tessellation patches, following the control points and in
76*c8dee2aaSAndroid Build Coastguard Worker // the same order as they appear here.
77*c8dee2aaSAndroid Build Coastguard Worker enum class PatchAttribs {
78*c8dee2aaSAndroid Build Coastguard Worker     // Attribs.
79*c8dee2aaSAndroid Build Coastguard Worker     kNone = 0,
80*c8dee2aaSAndroid Build Coastguard Worker     kJoinControlPoint = 1 << 0, // [float2] Used by strokes. This defines tangent direction.
81*c8dee2aaSAndroid Build Coastguard Worker     kFanPoint = 1 << 1,  // [float2] Used by wedges. This is the center point the wedges fan around.
82*c8dee2aaSAndroid Build Coastguard Worker     kStrokeParams = 1 << 2,  // [float2] Used when strokes have different widths or join types.
83*c8dee2aaSAndroid Build Coastguard Worker     kColor = 1 << 3,  // [ubyte4 or float4] Used when patches have different colors.
84*c8dee2aaSAndroid Build Coastguard Worker     kPaintDepth = 1 << 4, // [float] Used in Graphite to specify depth attachment value for draw.
85*c8dee2aaSAndroid Build Coastguard Worker     kExplicitCurveType = 1 << 5,  // [float] Used when GPU can't infer curve type based on infinity.
86*c8dee2aaSAndroid Build Coastguard Worker     kSsboIndex = 1 << 7,  // [int] Used to index into a shared storage buffer for this patch's
87*c8dee2aaSAndroid Build Coastguard Worker                           //       uniform values.
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker     // Extra flags.
90*c8dee2aaSAndroid Build Coastguard Worker     kWideColorIfEnabled = 1 << 6,  // If kColor is set, specifies it to be float4 wide color.
91*c8dee2aaSAndroid Build Coastguard Worker };
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker SK_MAKE_BITFIELD_CLASS_OPS(PatchAttribs)
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker // When PatchAttribs::kExplicitCurveType is set, these are the values that tell the GPU what type of
96*c8dee2aaSAndroid Build Coastguard Worker // curve is being drawn.
97*c8dee2aaSAndroid Build Coastguard Worker constexpr static float kCubicCurveType [[maybe_unused]] = 0;
98*c8dee2aaSAndroid Build Coastguard Worker constexpr static float kConicCurveType [[maybe_unused]] = 1;
99*c8dee2aaSAndroid Build Coastguard Worker constexpr static float kTriangularConicCurveType [[maybe_unused]] = 2;  // Conic curve with w=Inf.
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker // Returns the packed size in bytes of the attribs portion of tessellation patches (or instances) in
102*c8dee2aaSAndroid Build Coastguard Worker // GPU buffers.
PatchAttribsStride(PatchAttribs attribs)103*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t PatchAttribsStride(PatchAttribs attribs) {
104*c8dee2aaSAndroid Build Coastguard Worker     return (attribs & PatchAttribs::kJoinControlPoint ? sizeof(float) * 2 : 0) +
105*c8dee2aaSAndroid Build Coastguard Worker            (attribs & PatchAttribs::kFanPoint ? sizeof(float) * 2 : 0) +
106*c8dee2aaSAndroid Build Coastguard Worker            (attribs & PatchAttribs::kStrokeParams ? sizeof(float) * 2 : 0) +
107*c8dee2aaSAndroid Build Coastguard Worker            (attribs & PatchAttribs::kColor
108*c8dee2aaSAndroid Build Coastguard Worker                     ? (attribs & PatchAttribs::kWideColorIfEnabled ? sizeof(float)
109*c8dee2aaSAndroid Build Coastguard Worker                                                                    : sizeof(uint8_t)) * 4 : 0) +
110*c8dee2aaSAndroid Build Coastguard Worker            (attribs & PatchAttribs::kPaintDepth ? sizeof(float) : 0) +
111*c8dee2aaSAndroid Build Coastguard Worker            (attribs & PatchAttribs::kExplicitCurveType ? sizeof(float) : 0) +
112*c8dee2aaSAndroid Build Coastguard Worker            (attribs & PatchAttribs::kSsboIndex ? (sizeof(uint32_t) * 2) : 0);
113*c8dee2aaSAndroid Build Coastguard Worker }
PatchStride(PatchAttribs attribs)114*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t PatchStride(PatchAttribs attribs) {
115*c8dee2aaSAndroid Build Coastguard Worker     return 4*sizeof(SkPoint) + PatchAttribsStride(attribs);
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker // Finds 0, 1, or 2 T values at which to chop the given curve in order to guarantee the resulting
119*c8dee2aaSAndroid Build Coastguard Worker // cubics are convex and rotate no more than 180 degrees.
120*c8dee2aaSAndroid Build Coastguard Worker //
121*c8dee2aaSAndroid Build Coastguard Worker //   - If the cubic is "serpentine", then the T values are any inflection points in [0 < T < 1].
122*c8dee2aaSAndroid Build Coastguard Worker //   - If the cubic is linear, then the T values are any 180-degree cusp points in [0 < T < 1].
123*c8dee2aaSAndroid Build Coastguard Worker //   - Otherwise the T value is the point at which rotation reaches 180 degrees, iff in [0 < T < 1].
124*c8dee2aaSAndroid Build Coastguard Worker //
125*c8dee2aaSAndroid Build Coastguard Worker // 'areCusps' is set to true if the chop point occurred at a cusp (within tolerance), or if the chop
126*c8dee2aaSAndroid Build Coastguard Worker // point(s) occurred at 180-degree turnaround points on a degenerate flat line.
127*c8dee2aaSAndroid Build Coastguard Worker int FindCubicConvex180Chops(const SkPoint[], float T[2], bool* areCusps);
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker // Returns true if the given conic (or quadratic) has a cusp point. The w value is not necessary in
130*c8dee2aaSAndroid Build Coastguard Worker // determining this. If there is a cusp, it can be found at the midtangent.
ConicHasCusp(const SkPoint p[3])131*c8dee2aaSAndroid Build Coastguard Worker inline bool ConicHasCusp(const SkPoint p[3]) {
132*c8dee2aaSAndroid Build Coastguard Worker     SkVector a = p[1] - p[0];
133*c8dee2aaSAndroid Build Coastguard Worker     SkVector b = p[2] - p[1];
134*c8dee2aaSAndroid Build Coastguard Worker     // A conic of any class can only have a cusp if it is a degenerate flat line with a 180 degree
135*c8dee2aaSAndroid Build Coastguard Worker     // turnarund. To detect this, the beginning and ending tangents must be parallel
136*c8dee2aaSAndroid Build Coastguard Worker     // (a.cross(b) == 0) and pointing in opposite directions (a.dot(b) < 0).
137*c8dee2aaSAndroid Build Coastguard Worker     return a.cross(b) == 0 && a.dot(b) < 0;
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker // We encode all of a join's information in a single float value:
141*c8dee2aaSAndroid Build Coastguard Worker //
142*c8dee2aaSAndroid Build Coastguard Worker //     Negative => Round Join
143*c8dee2aaSAndroid Build Coastguard Worker //     Zero     => Bevel Join
144*c8dee2aaSAndroid Build Coastguard Worker //     Positive => Miter join, and the value is also the miter limit
145*c8dee2aaSAndroid Build Coastguard Worker //
GetJoinType(const SkStrokeRec & stroke)146*c8dee2aaSAndroid Build Coastguard Worker inline float GetJoinType(const SkStrokeRec& stroke) {
147*c8dee2aaSAndroid Build Coastguard Worker     switch (stroke.getJoin()) {
148*c8dee2aaSAndroid Build Coastguard Worker         case SkPaint::kRound_Join: return -1;
149*c8dee2aaSAndroid Build Coastguard Worker         case SkPaint::kBevel_Join: return 0;
150*c8dee2aaSAndroid Build Coastguard Worker         case SkPaint::kMiter_Join: SkASSERT(stroke.getMiter() >= 0); return stroke.getMiter();
151*c8dee2aaSAndroid Build Coastguard Worker     }
152*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker 
155*c8dee2aaSAndroid Build Coastguard Worker // This float2 gets written out with each patch/instance if PatchAttribs::kStrokeParams is enabled.
156*c8dee2aaSAndroid Build Coastguard Worker struct StrokeParams {
157*c8dee2aaSAndroid Build Coastguard Worker     StrokeParams() = default;
StrokeParamsStrokeParams158*c8dee2aaSAndroid Build Coastguard Worker     StrokeParams(float radius, float joinType) : fRadius(radius), fJoinType(joinType) {}
StrokeParamsStrokeParams159*c8dee2aaSAndroid Build Coastguard Worker     StrokeParams(const SkStrokeRec& stroke) {
160*c8dee2aaSAndroid Build Coastguard Worker         this->set(stroke);
161*c8dee2aaSAndroid Build Coastguard Worker     }
setStrokeParams162*c8dee2aaSAndroid Build Coastguard Worker     void set(const SkStrokeRec& stroke) {
163*c8dee2aaSAndroid Build Coastguard Worker         fRadius = stroke.getWidth() * .5f;
164*c8dee2aaSAndroid Build Coastguard Worker         fJoinType = GetJoinType(stroke);
165*c8dee2aaSAndroid Build Coastguard Worker     }
166*c8dee2aaSAndroid Build Coastguard Worker 
167*c8dee2aaSAndroid Build Coastguard Worker     float fRadius;
168*c8dee2aaSAndroid Build Coastguard Worker     float fJoinType;  // See GetJoinType().
169*c8dee2aaSAndroid Build Coastguard Worker };
170*c8dee2aaSAndroid Build Coastguard Worker 
StrokesHaveEqualParams(const SkStrokeRec & a,const SkStrokeRec & b)171*c8dee2aaSAndroid Build Coastguard Worker inline bool StrokesHaveEqualParams(const SkStrokeRec& a, const SkStrokeRec& b) {
172*c8dee2aaSAndroid Build Coastguard Worker     return a.getWidth() == b.getWidth() && a.getJoin() == b.getJoin() &&
173*c8dee2aaSAndroid Build Coastguard Worker             (a.getJoin() != SkPaint::kMiter_Join || a.getMiter() == b.getMiter());
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker // Returns the fixed number of edges that are always emitted with the given join type. If the
177*c8dee2aaSAndroid Build Coastguard Worker // join is round, the caller needs to account for the additional radial edges on their own.
178*c8dee2aaSAndroid Build Coastguard Worker // Specifically, each join always emits:
179*c8dee2aaSAndroid Build Coastguard Worker //
180*c8dee2aaSAndroid Build Coastguard Worker //   * Two colocated edges at the beginning (a full-width edge to seam with the preceding stroke
181*c8dee2aaSAndroid Build Coastguard Worker //     and a half-width edge to begin the join).
182*c8dee2aaSAndroid Build Coastguard Worker //
183*c8dee2aaSAndroid Build Coastguard Worker //   * An extra edge in the middle for miter joins, or else a variable number of radial edges
184*c8dee2aaSAndroid Build Coastguard Worker //     for round joins (the caller is responsible for counting radial edges from round joins).
185*c8dee2aaSAndroid Build Coastguard Worker //
186*c8dee2aaSAndroid Build Coastguard Worker //   * A half-width edge at the end of the join that will be colocated with the first
187*c8dee2aaSAndroid Build Coastguard Worker //     (full-width) edge of the stroke.
188*c8dee2aaSAndroid Build Coastguard Worker //
NumFixedEdgesInJoin(SkPaint::Join joinType)189*c8dee2aaSAndroid Build Coastguard Worker constexpr int NumFixedEdgesInJoin(SkPaint::Join joinType) {
190*c8dee2aaSAndroid Build Coastguard Worker     switch (joinType) {
191*c8dee2aaSAndroid Build Coastguard Worker         case SkPaint::kMiter_Join:
192*c8dee2aaSAndroid Build Coastguard Worker             return 4;
193*c8dee2aaSAndroid Build Coastguard Worker         case SkPaint::kRound_Join:
194*c8dee2aaSAndroid Build Coastguard Worker             // The caller is responsible for counting the variable number of middle, radial
195*c8dee2aaSAndroid Build Coastguard Worker             // segments on round joins.
196*c8dee2aaSAndroid Build Coastguard Worker             [[fallthrough]];
197*c8dee2aaSAndroid Build Coastguard Worker         case SkPaint::kBevel_Join:
198*c8dee2aaSAndroid Build Coastguard Worker             return 3;
199*c8dee2aaSAndroid Build Coastguard Worker     }
200*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
201*c8dee2aaSAndroid Build Coastguard Worker }
NumFixedEdgesInJoin(const StrokeParams & strokeParams)202*c8dee2aaSAndroid Build Coastguard Worker constexpr int NumFixedEdgesInJoin(const StrokeParams& strokeParams) {
203*c8dee2aaSAndroid Build Coastguard Worker     // The caller is responsible for counting the variable number of segments for round joins.
204*c8dee2aaSAndroid Build Coastguard Worker     return strokeParams.fJoinType > 0.f ? /* miter */ 4 : /* round or bevel */ 3;
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker // Decides the number of radial segments the tessellator adds for each curve. (Uniform steps
208*c8dee2aaSAndroid Build Coastguard Worker // in tangent angle.) The tessellator will add this number of radial segments for each
209*c8dee2aaSAndroid Build Coastguard Worker // radian of rotation in local path space.
CalcNumRadialSegmentsPerRadian(float approxDevStrokeRadius)210*c8dee2aaSAndroid Build Coastguard Worker inline float CalcNumRadialSegmentsPerRadian(float approxDevStrokeRadius) {
211*c8dee2aaSAndroid Build Coastguard Worker     float cosTheta = 1.f - (1.f / kPrecision) / approxDevStrokeRadius;
212*c8dee2aaSAndroid Build Coastguard Worker     return .5f / acosf(std::max(cosTheta, -1.f));
213*c8dee2aaSAndroid Build Coastguard Worker }
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::tess
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker #endif  // skgpu_tessellate_Tessellation_DEFINED
218