• 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 GrStencilPathShader_DEFINED
9 #define GrStencilPathShader_DEFINED
10 
11 #include "src/gpu/GrDrawIndirectCommand.h"
12 #include "src/gpu/tessellate/GrPathShader.h"
13 #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
14 
15 // This is the base class for shaders that stencil path elements, namely, triangles, standalone
16 // cubics, and wedges.
17 class GrStencilPathShader : public GrPathShader {
18 public:
19     GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType,
20                         int tessellationPatchVertexCount = 0)
GrPathShader(classID,viewMatrix,primitiveType,tessellationPatchVertexCount)21             : GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) {
22     }
23 
24     // Creates a pipeline that can be used for normal Redbook stencil draws.
MakeStencilPassPipeline(const GrPathShader::ProgramArgs & args,GrAAType aaType,GrTessellationPathRenderer::OpFlags opFlags,const GrAppliedHardClip & hardClip)25     static const GrPipeline* MakeStencilPassPipeline(const GrPathShader::ProgramArgs& args,
26                                                      GrAAType aaType,
27                                                      GrTessellationPathRenderer::OpFlags opFlags,
28                                                      const GrAppliedHardClip& hardClip) {
29         using OpFlags = GrTessellationPathRenderer::OpFlags;
30         GrPipeline::InitArgs pipelineArgs;
31         if (aaType != GrAAType::kNone) {
32             pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
33         }
34         if (args.fCaps->wireframeSupport() && (opFlags & OpFlags::kWireframe)) {
35             pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
36         }
37         pipelineArgs.fCaps = args.fCaps;
38         return args.fArena->make<GrPipeline>(pipelineArgs,
39                                              GrDisableColorXPFactory::MakeXferProcessor(),
40                                              hardClip);
41     }
42 
43     // Returns the stencil settings to use for a standard Redbook stencil draw.
StencilPassSettings(SkPathFillType fillType)44     static const GrUserStencilSettings* StencilPassSettings(SkPathFillType fillType) {
45         // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
46         constexpr static GrUserStencilSettings kIncrDecrStencil(
47             GrUserStencilSettings::StaticInitSeparate<
48                 0x0000,                                0x0000,
49                 GrUserStencilTest::kAlwaysIfInClip,    GrUserStencilTest::kAlwaysIfInClip,
50                 0xffff,                                0xffff,
51                 GrUserStencilOp::kIncWrap,             GrUserStencilOp::kDecWrap,
52                 GrUserStencilOp::kKeep,                GrUserStencilOp::kKeep,
53                 0xffff,                                0xffff>());
54 
55         // Inverts the bottom stencil bit. Used for "even/odd" fill.
56         constexpr static GrUserStencilSettings kInvertStencil(
57             GrUserStencilSettings::StaticInit<
58                 0x0000,
59                 GrUserStencilTest::kAlwaysIfInClip,
60                 0xffff,
61                 GrUserStencilOp::kInvert,
62                 GrUserStencilOp::kKeep,
63                 0x0001>());
64 
65         SkASSERT(fillType == SkPathFillType::kWinding || fillType == SkPathFillType::kEvenOdd);
66         return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil;
67     }
68 
69     template<typename ShaderType>
MakeStencilProgram(const ProgramArgs & args,const SkMatrix & viewMatrix,const GrPipeline * pipeline,const GrUserStencilSettings * stencil)70     static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix,
71                                              const GrPipeline* pipeline,
72                                              const GrUserStencilSettings* stencil) {
73         const auto* shader = args.fArena->make<ShaderType>(viewMatrix);
74         return GrPathShader::MakeProgram(args, shader, pipeline, stencil);
75     }
76 
77     template<typename ShaderType>
MakeStencilProgram(const ProgramArgs & args,const SkMatrix & viewMatrix,const GrPipeline * pipeline,const SkPathFillType fillType)78     static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix,
79                                              const GrPipeline* pipeline,
80                                              const SkPathFillType fillType) {
81         return MakeStencilProgram<ShaderType>(args, viewMatrix, pipeline,
82                                               StencilPassSettings(fillType));
83     }
84 
85 protected:
86     constexpr static Attribute kSinglePointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
87                                                   kFloat2_GrSLType};
getGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b)88     void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
89         b->add32(this->viewMatrix().isIdentity());
90     }
91     GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
92 
93     class Impl;
94 };
95 
96 // Draws simple triangles to the stencil buffer.
97 class GrStencilTriangleShader : public GrStencilPathShader {
98 public:
GrStencilTriangleShader(const SkMatrix & viewMatrix)99     GrStencilTriangleShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
100             kTessellate_GrStencilTriangleShader_ClassID, viewMatrix, GrPrimitiveType::kTriangles) {
101         this->setVertexAttributes(&kSinglePointAttrib, 1);
102     }
name()103     const char* name() const override { return "tessellate_GrStencilTriangleShader"; }
104 };
105 
106 // Uses GPU tessellation shaders to linearize, triangulate, and render standalone closed cubics.
107 // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics.
108 class GrCubicTessellateShader : public GrStencilPathShader {
109 public:
GrCubicTessellateShader(const SkMatrix & viewMatrix)110     GrCubicTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
111             kTessellate_GrCubicTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) {
112         this->setVertexAttributes(&kSinglePointAttrib, 1);
113     }
name()114     const char* name() const override { return "tessellate_GrCubicTessellateShader"; }
115 
116 private:
117     GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
118 };
119 
120 // Uses GPU tessellation shaders to linearize, triangulate, and render cubic "wedge" patches. A
121 // wedge is a 5-point patch consisting of 4 cubic control points, plus an anchor point fanning from
122 // the center of the curve's resident contour.
123 // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics.
124 class GrWedgeTessellateShader : public GrStencilPathShader {
125 public:
GrWedgeTessellateShader(const SkMatrix & viewMatrix)126     GrWedgeTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
127             kTessellate_GrWedgeTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 5) {
128         this->setVertexAttributes(&kSinglePointAttrib, 1);
129     }
name()130     const char* name() const override { return "tessellate_GrWedgeTessellateShader"; }
131 
132 private:
133     GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
134 };
135 
136 // Uses indirect (instanced) draws to triangulate standalone closed cubics with a "middle-out"
137 // topology. The caller must compute each cubic's resolveLevel on the CPU (i.e., the log2 number of
138 // line segments it will be divided into; see GrWangsFormula::cubic_log2/quadratic_log2), and then
139 // sort the instance buffer by resolveLevel for efficient batching of indirect draws.
140 class GrMiddleOutCubicShader : public GrStencilPathShader {
141 public:
142     // How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel
143     // line segments?
NumVerticesAtResolveLevel(int resolveLevel)144     constexpr static int NumVerticesAtResolveLevel(int resolveLevel) {
145         // resolveLevel=0 -> 0 line segments -> 0 triangles -> 0 vertices
146         // resolveLevel=1 -> 2 line segments -> 1 triangle -> 3 vertices
147         // resolveLevel=2 -> 4 line segments -> 3 triangles -> 9 vertices
148         // resolveLevel=3 -> 8 line segments -> 7 triangles -> 21 vertices
149         // ...
150         return ((1 << resolveLevel) - 1) * 3;
151     }
152 
153     // Configures an indirect draw to render cubic instances with 2^resolveLevel evenly-spaced (in
154     // the parametric sense) line segments.
WriteDrawCubicsIndirectCmd(GrDrawIndexedIndirectWriter * indirectWriter,int resolveLevel,uint32_t instanceCount,uint32_t baseInstance)155     static void WriteDrawCubicsIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter,
156                                            int resolveLevel, uint32_t instanceCount,
157                                            uint32_t baseInstance) {
158         SkASSERT(resolveLevel > 0 && resolveLevel <= GrTessellationPathRenderer::kMaxResolveLevel);
159         // Starting at baseIndex=3, the index buffer triangulates a cubic with 2^kMaxResolveLevel
160         // line segments. Each index value corresponds to a parametric T value on the curve. Since
161         // the triangles are arranged in "middle-out" order, we can conveniently control the
162         // resolveLevel by changing only the indexCount.
163         uint32_t indexCount = NumVerticesAtResolveLevel(resolveLevel);
164         indirectWriter->writeIndexed(indexCount, 3, instanceCount, baseInstance, 0);
165     }
166 
167     // For performance reasons we can often express triangles as an indirect cubic draw and sneak
168     // them in alongside the other indirect draws. This method configures an indirect draw to emit
169     // the triangle [P0, P1, P2] from a 4-point instance.
WriteDrawTrianglesIndirectCmd(GrDrawIndexedIndirectWriter * indirectWriter,uint32_t instanceCount,uint32_t baseInstance)170     static void WriteDrawTrianglesIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter,
171                                               uint32_t instanceCount, uint32_t baseInstance) {
172         // Indices 0,1,2 have special index values that emit points P0, P1, and P2 respectively.
173         indirectWriter->writeIndexed(3, 0, instanceCount, baseInstance, 0);
174     }
175 
176     // Returns the index buffer that should be bound when drawing with this shader.
177     // (Our vertex shader uses raw index values directly, so there is no vertex buffer.)
178     static sk_sp<const GrGpuBuffer> FindOrMakeMiddleOutIndexBuffer(GrResourceProvider*);
179 
GrMiddleOutCubicShader(const SkMatrix & viewMatrix)180     GrMiddleOutCubicShader(const SkMatrix& viewMatrix)
181             : GrStencilPathShader(kTessellate_GrMiddleOutCubicShader_ClassID, viewMatrix,
182                                   GrPrimitiveType::kTriangles) {
183         constexpr static Attribute kInputPtsAttribs[] = {
184                 {"inputPoints_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
185                 {"inputPoints_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
186         this->setInstanceAttributes(kInputPtsAttribs, 2);
187     }
188 
name()189     const char* name() const override { return "tessellate_GrMiddleOutCubicShader"; }
190 
191 private:
192     GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
193 
194     class Impl;
195 };
196 
197 #endif
198