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/tessellate/GrPathShader.h" |
12 | #include "src/gpu/tessellate/GrTessellationPathRenderer.h" |
13 | |
14 | // This is the base class for shaders that stencil path elements, namely, triangles, standalone |
15 | // cubics, and wedges. |
16 | class GrStencilPathShader : public GrPathShader { |
17 | public: |
18 | GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType, |
19 | int tessellationPatchVertexCount = 0) |
20 | : GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) { |
21 | } |
22 | |
23 | protected: |
24 | constexpr static Attribute kSinglePointAttrib{"inputPoint" , kFloat2_GrVertexAttribType, |
25 | kFloat2_GrSLType}; |
26 | void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { |
27 | b->add32(this->viewMatrix().isIdentity()); |
28 | } |
29 | GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; |
30 | |
31 | class Impl; |
32 | }; |
33 | |
34 | // Draws simple triangles to the stencil buffer. |
35 | class GrStencilTriangleShader : public GrStencilPathShader { |
36 | public: |
37 | GrStencilTriangleShader(const SkMatrix& viewMatrix) : GrStencilPathShader( |
38 | kTessellate_GrStencilTriangleShader_ClassID, viewMatrix, GrPrimitiveType::kTriangles) { |
39 | this->setVertexAttributes(&kSinglePointAttrib, 1); |
40 | } |
41 | const char* name() const override { return "tessellate_GrStencilTriangleShader" ; } |
42 | }; |
43 | |
44 | // Uses GPU tessellation shaders to linearize, triangulate, and render standalone closed cubics. |
45 | // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. |
46 | class GrCubicTessellateShader : public GrStencilPathShader { |
47 | public: |
48 | GrCubicTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader( |
49 | kTessellate_GrCubicTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) { |
50 | this->setVertexAttributes(&kSinglePointAttrib, 1); |
51 | } |
52 | const char* name() const override { return "tessellate_GrCubicTessellateShader" ; } |
53 | |
54 | private: |
55 | SkString getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*, |
56 | const char* versionAndExtensionDecls, |
57 | const GrGLSLUniformHandler&, |
58 | const GrShaderCaps&) const override; |
59 | SkString getTessEvaluationShaderGLSL(const GrGLSLPrimitiveProcessor*, |
60 | const char* versionAndExtensionDecls, |
61 | const GrGLSLUniformHandler&, |
62 | const GrShaderCaps&) const override; |
63 | }; |
64 | |
65 | // Uses GPU tessellation shaders to linearize, triangulate, and render cubic "wedge" patches. A |
66 | // wedge is a 5-point patch consisting of 4 cubic control points, plus an anchor point fanning from |
67 | // the center of the curve's resident contour. |
68 | // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. |
69 | class GrWedgeTessellateShader : public GrStencilPathShader { |
70 | public: |
71 | GrWedgeTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader( |
72 | kTessellate_GrWedgeTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 5) { |
73 | this->setVertexAttributes(&kSinglePointAttrib, 1); |
74 | } |
75 | const char* name() const override { return "tessellate_GrWedgeTessellateShader" ; } |
76 | |
77 | private: |
78 | SkString getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*, |
79 | const char* versionAndExtensionDecls, |
80 | const GrGLSLUniformHandler&, |
81 | const GrShaderCaps&) const override; |
82 | SkString getTessEvaluationShaderGLSL(const GrGLSLPrimitiveProcessor*, |
83 | const char* versionAndExtensionDecls, |
84 | const GrGLSLUniformHandler&, |
85 | const GrShaderCaps&) const override; |
86 | }; |
87 | |
88 | // Uses indirect (instanced) draws to triangulate standalone closed cubics with a "middle-out" |
89 | // topology. The caller must compute each cubic's resolveLevel on the CPU (i.e., the log2 number of |
90 | // line segments it will be divided into; see GrWangsFormula::cubic_log2/quadratic_log2), and then |
91 | // sort the instance buffer by resolveLevel for efficient batching of indirect draws. |
92 | class GrMiddleOutCubicShader : public GrStencilPathShader { |
93 | public: |
94 | // How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel |
95 | // line segments? |
96 | constexpr static int NumVerticesAtResolveLevel(int resolveLevel) { |
97 | // resolveLevel=0 -> 0 line segments -> 0 triangles -> 0 vertices |
98 | // resolveLevel=1 -> 2 line segments -> 1 triangle -> 3 vertices |
99 | // resolveLevel=2 -> 4 line segments -> 3 triangles -> 9 vertices |
100 | // resolveLevel=3 -> 8 line segments -> 7 triangles -> 21 vertices |
101 | // ... |
102 | return ((1 << resolveLevel) - 1) * 3; |
103 | } |
104 | |
105 | // Configures an indirect draw to render cubic instances with 2^resolveLevel evenly-spaced (in |
106 | // the parametric sense) line segments. |
107 | static GrDrawIndexedIndirectCommand MakeDrawCubicsIndirectCmd(int resolveLevel, |
108 | uint32_t instanceCount, |
109 | uint32_t baseInstance) { |
110 | SkASSERT(resolveLevel > 0 && resolveLevel <= GrTessellationPathRenderer::kMaxResolveLevel); |
111 | // Starting at baseIndex=3, the index buffer triangulates a cubic with 2^kMaxResolveLevel |
112 | // line segments. Each index value corresponds to a parametric T value on the curve. Since |
113 | // the triangles are arranged in "middle-out" order, we can conveniently control the |
114 | // resolveLevel by changing only the indexCount. |
115 | uint32_t indexCount = NumVerticesAtResolveLevel(resolveLevel); |
116 | return {indexCount, instanceCount, 3, 0, baseInstance}; |
117 | } |
118 | |
119 | // For performance reasons we can often express triangles as an indirect cubic draw and sneak |
120 | // them in alongside the other indirect draws. This method configures an indirect draw to emit |
121 | // the triangle [P0, P1, P2] from a 4-point instance. |
122 | static GrDrawIndexedIndirectCommand MakeDrawTrianglesIndirectCmd(uint32_t instanceCount, |
123 | uint32_t baseInstance) { |
124 | // Indices 0,1,2 have special index values that emit points P0, P1, and P2 respectively. |
125 | return {3, instanceCount, 0, 0, baseInstance}; |
126 | } |
127 | |
128 | // Returns the index buffer that should be bound when drawing with this shader. |
129 | // (Our vertex shader uses raw index values directly, so there is no vertex buffer.) |
130 | static sk_sp<const GrGpuBuffer> FindOrMakeMiddleOutIndexBuffer(GrResourceProvider*); |
131 | |
132 | GrMiddleOutCubicShader(const SkMatrix& viewMatrix) |
133 | : GrStencilPathShader(kTessellate_GrMiddleOutCubicShader_ClassID, viewMatrix, |
134 | GrPrimitiveType::kTriangles) { |
135 | constexpr static Attribute kInputPtsAttribs[] = { |
136 | {"inputPoints_0_1" , kFloat4_GrVertexAttribType, kFloat4_GrSLType}, |
137 | {"inputPoints_2_3" , kFloat4_GrVertexAttribType, kFloat4_GrSLType}}; |
138 | this->setInstanceAttributes(kInputPtsAttribs, 2); |
139 | } |
140 | |
141 | const char* name() const override { return "tessellate_GrMiddleOutCubicShader" ; } |
142 | |
143 | private: |
144 | GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; |
145 | |
146 | class Impl; |
147 | }; |
148 | |
149 | #endif |
150 | |