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