xref: /aosp_15_r20/external/skia/src/gpu/ganesh/tessellate/GrPathTessellationShader.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2019 Google LLC.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #ifndef GrPathTessellationShader_DEFINED
8 #define GrPathTessellationShader_DEFINED
9 
10 #include "include/core/SkString.h"
11 #include "include/private/SkColorData.h"
12 #include "include/private/gpu/ganesh/GrTypesPriv.h"
13 #include "src/gpu/ganesh/GrGeometryProcessor.h"
14 #include "src/gpu/ganesh/GrPipeline.h"
15 #include "src/gpu/ganesh/GrUserStencilSettings.h"
16 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
17 #include "src/gpu/ganesh/tessellate/GrTessellationShader.h"
18 
19 #include <cstddef>
20 
21 class GrAppliedHardClip;
22 class GrGLSLProgramDataManager;
23 class GrGLSLVaryingHandler;
24 class GrGLSLVertexBuilder;
25 class SkArenaAlloc;
26 class SkMatrix;
27 struct GrShaderCaps;
28 
29 namespace skgpu::tess {
30 enum class PatchAttribs;
31 }
32 
33 // This is the base class for shaders in the GPU tessellator that fill paths.
34 class GrPathTessellationShader : public GrTessellationShader {
35 protected:
36     using PatchAttribs = skgpu::tess::PatchAttribs;
37 
38 public:
39     // Draws a simple array of triangles.
40     static GrPathTessellationShader* MakeSimpleTriangleShader(SkArenaAlloc*,
41                                                               const SkMatrix& viewMatrix,
42                                                               const SkPMColor4f&);
43 
44     // Uses instanced draws to triangulate curves with a "middle-out" topology. Middle-out draws a
45     // triangle with vertices at T=[0, 1/2, 1] and then recurses breadth first:
46     //
47     //   depth=0: T=[0, 1/2, 1]
48     //   depth=1: T=[0, 1/4, 2/4], T=[2/4, 3/4, 1]
49     //   depth=2: T=[0, 1/8, 2/8], T=[2/8, 3/8, 4/8], T=[4/8, 5/8, 6/8], T=[6/8, 7/8, 1]
50     //   ...
51     //
52     // The shader determines how many segments are required to render each individual curve
53     // smoothly, and emits empty triangles at any vertices whose sk_VertexIDs are higher than
54     // necessary. It is the caller's responsibility to draw enough vertices per instance for the
55     // most complex curve in the batch to render smoothly (i.e., NumTrianglesAtResolveLevel() * 3).
56     //
57     // If PatchAttribs::kFanPoint is set, an additional triangle is added, connecting the base of
58     // the curve to the fan point.
59     static GrPathTessellationShader* Make(const GrShaderCaps&,
60                                           SkArenaAlloc*,
61                                           const SkMatrix& viewMatrix,
62                                           const SkPMColor4f&,
63                                           PatchAttribs);
64 
65     // Returns the stencil settings to use for a standard Redbook "stencil" pass.
StencilPathSettings(GrFillRule fillRule)66     static const GrUserStencilSettings* StencilPathSettings(GrFillRule fillRule) {
67         // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
68         constexpr static GrUserStencilSettings kIncrDecrStencil(
69             GrUserStencilSettings::StaticInitSeparate<
70                 0x0000,                                0x0000,
71                 GrUserStencilTest::kAlwaysIfInClip,    GrUserStencilTest::kAlwaysIfInClip,
72                 0xffff,                                0xffff,
73                 GrUserStencilOp::kIncWrap,             GrUserStencilOp::kDecWrap,
74                 GrUserStencilOp::kKeep,                GrUserStencilOp::kKeep,
75                 0xffff,                                0xffff>());
76 
77         // Inverts the bottom stencil bit. Used for "even/odd" fill.
78         constexpr static GrUserStencilSettings kInvertStencil(
79             GrUserStencilSettings::StaticInit<
80                 0x0000,
81                 GrUserStencilTest::kAlwaysIfInClip,
82                 0xffff,
83                 GrUserStencilOp::kInvert,
84                 GrUserStencilOp::kKeep,
85                 0x0001>());
86 
87         return (fillRule == GrFillRule::kNonzero) ? &kIncrDecrStencil : &kInvertStencil;
88     }
89 
90     // Returns the stencil settings to use for a standard Redbook "fill" pass. Allows non-zero
91     // stencil values to pass and write a color, and resets the stencil value back to zero; discards
92     // immediately on stencil values of zero.
93     static const GrUserStencilSettings* TestAndResetStencilSettings(bool isInverseFill = false) {
94         constexpr static GrUserStencilSettings kTestAndResetStencil(
95             GrUserStencilSettings::StaticInit<
96                 0x0000,
97                 // No need to check the clip because the previous stencil pass will have only
98                 // written to samples already inside the clip.
99                 GrUserStencilTest::kNotEqual,
100                 0xffff,
101                 GrUserStencilOp::kZero,
102                 GrUserStencilOp::kKeep,
103                 0xffff>());
104 
105         constexpr static GrUserStencilSettings kTestAndResetStencilInverted(
106             GrUserStencilSettings::StaticInit<
107                 0x0000,
108                 // No need to check the clip because the previous stencil pass will have only
109                 // written to samples already inside the clip.
110                 GrUserStencilTest::kEqual,
111                 0xffff,
112                 GrUserStencilOp::kKeep,
113                 GrUserStencilOp::kZero,
114                 0xffff>());
115 
116         return isInverseFill ? &kTestAndResetStencilInverted : &kTestAndResetStencil;
117     }
118 
119     // Creates a pipeline that does not write to the color buffer.
120     static const GrPipeline* MakeStencilOnlyPipeline(
121             const ProgramArgs&,
122             GrAAType,
123             const GrAppliedHardClip&,
124             GrPipeline::InputFlags = GrPipeline::InputFlags::kNone);
125 
126 protected:
127     constexpr static size_t kMiddleOutVertexStride = 2 * sizeof(float);
128 
GrPathTessellationShader(ClassID classID,GrPrimitiveType primitiveType,const SkMatrix & viewMatrix,const SkPMColor4f & color,PatchAttribs attribs)129     GrPathTessellationShader(ClassID classID,
130                              GrPrimitiveType primitiveType,
131                              const SkMatrix& viewMatrix,
132                              const SkPMColor4f& color,
133                              PatchAttribs attribs)
134             : GrTessellationShader(classID, primitiveType, viewMatrix, color)
135             , fAttribs(attribs) {
136     }
137 
138     // Default path tessellation shader implementation that manages a uniform matrix and color.
139     class Impl : public ProgramImpl {
140     public:
141         void onEmitCode(EmitArgs&, GrGPArgs*) final;
142         void setData(const GrGLSLProgramDataManager&, const GrShaderCaps&,
143                      const GrGeometryProcessor&) override;
144 
145     protected:
146         // float4x3 unpack_rational_cubic(float2 p0, float2 p1, float2 p2, float2 p3) { ...
147         //
148         // Evaluate our point of interest using numerically stable linear interpolations. We add our
149         // own "safe_mix" method to guarantee we get exactly "b" when T=1. The builtin mix()
150         // function seems spec'd to behave this way, but empirical results results have shown it
151         // does not always.
152         static const char* kEvalRationalCubicFn;
153 
154         virtual void emitVertexCode(const GrShaderCaps&,
155                                     const GrPathTessellationShader&,
156                                     GrGLSLVertexBuilder*,
157                                     GrGLSLVaryingHandler*,
158                                     GrGPArgs*) = 0;
159 
160         GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
161         GrGLSLUniformHandler::UniformHandle fTranslateUniform;
162         GrGLSLUniformHandler::UniformHandle fColorUniform;
163         SkString fVaryingColorName;
164     };
165 
166     const PatchAttribs fAttribs;
167 };
168 
169 #endif
170