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.
16class GrStencilPathShader : public GrPathShader {
17public:
18 GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType,
19 int tessellationPatchVertexCount = 0)
20 : GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) {
21 }
22
23protected:
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.
35class GrStencilTriangleShader : public GrStencilPathShader {
36public:
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.
46class GrCubicTessellateShader : public GrStencilPathShader {
47public:
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
54private:
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.
69class GrWedgeTessellateShader : public GrStencilPathShader {
70public:
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
77private:
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.
92class GrMiddleOutCubicShader : public GrStencilPathShader {
93public:
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
143private:
144 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
145
146 class Impl;
147};
148
149#endif
150