1 | /* |
2 | * Copyright 2015 Google Inc. |
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 GrGLSLVarying_DEFINED |
9 | #define GrGLSLVarying_DEFINED |
10 | |
11 | #include "include/private/GrTypesPriv.h" |
12 | #include "src/gpu/GrGeometryProcessor.h" |
13 | #include "src/gpu/GrShaderVar.h" |
14 | #include "src/gpu/GrTAllocator.h" |
15 | #include "src/gpu/glsl/GrGLSLProgramDataManager.h" |
16 | |
17 | class GrGLSLProgramBuilder; |
18 | |
19 | #ifdef SK_DEBUG |
20 | static bool is_matrix(GrSLType type) { |
21 | switch (type) { |
22 | case kFloat2x2_GrSLType: |
23 | case kFloat3x3_GrSLType: |
24 | case kFloat4x4_GrSLType: |
25 | case kHalf2x2_GrSLType: |
26 | case kHalf3x3_GrSLType: |
27 | case kHalf4x4_GrSLType: |
28 | return true; |
29 | default: |
30 | return false; |
31 | } |
32 | } |
33 | #endif |
34 | |
35 | class GrGLSLVarying { |
36 | public: |
37 | enum class Scope { |
38 | kVertToFrag, |
39 | kVertToGeo, |
40 | kGeoToFrag |
41 | }; |
42 | |
43 | GrGLSLVarying() = default; |
44 | GrGLSLVarying(GrSLType type, Scope scope = Scope::kVertToFrag) |
45 | : fType(type) |
46 | , fScope(scope) { |
47 | // Metal doesn't support varying matrices, so we disallow them everywhere for consistency |
48 | SkASSERT(!is_matrix(type)); |
49 | } |
50 | |
51 | void reset(GrSLType type, Scope scope = Scope::kVertToFrag) { |
52 | // Metal doesn't support varying matrices, so we disallow them everywhere for consistency |
53 | SkASSERT(!is_matrix(type)); |
54 | *this = GrGLSLVarying(); |
55 | fType = type; |
56 | fScope = scope; |
57 | } |
58 | |
59 | GrSLType type() const { return fType; } |
60 | Scope scope() const { return fScope; } |
61 | bool isInVertexShader() const { return Scope::kGeoToFrag != fScope; } |
62 | bool isInFragmentShader() const { return Scope::kVertToGeo != fScope; } |
63 | |
64 | const char* vsOut() const { SkASSERT(this->isInVertexShader()); return fVsOut; } |
65 | const char* gsIn() const { return fGsIn; } |
66 | const char* gsOut() const { return fGsOut; } |
67 | const char* fsIn() const { SkASSERT(this->isInFragmentShader()); return fFsIn; } |
68 | |
69 | private: |
70 | GrSLType fType = kVoid_GrSLType; |
71 | Scope fScope = Scope::kVertToFrag; |
72 | const char* fVsOut = nullptr; |
73 | const char* fGsIn = nullptr; |
74 | const char* fGsOut = nullptr; |
75 | const char* fFsIn = nullptr; |
76 | |
77 | friend class GrGLSLVaryingHandler; |
78 | }; |
79 | |
80 | static const int kVaryingsPerBlock = 8; |
81 | |
82 | class GrGLSLVaryingHandler { |
83 | public: |
84 | explicit GrGLSLVaryingHandler(GrGLSLProgramBuilder* program) |
85 | : fVaryings(kVaryingsPerBlock) |
86 | , fVertexInputs(kVaryingsPerBlock) |
87 | , fVertexOutputs(kVaryingsPerBlock) |
88 | , fGeomInputs(kVaryingsPerBlock) |
89 | , fGeomOutputs(kVaryingsPerBlock) |
90 | , fFragInputs(kVaryingsPerBlock) |
91 | , fFragOutputs(kVaryingsPerBlock) |
92 | , fProgramBuilder(program) |
93 | , fDefaultInterpolationModifier(nullptr) {} |
94 | |
95 | virtual ~GrGLSLVaryingHandler() {} |
96 | |
97 | /* |
98 | * Notifies the varying handler that this shader will never emit geometry in perspective and |
99 | * therefore does not require perspective-correct interpolation. When supported, this allows |
100 | * varyings to use the "noperspective" keyword, which means the GPU can use cheaper math for |
101 | * interpolation. |
102 | */ |
103 | void setNoPerspective(); |
104 | |
105 | enum class Interpolation { |
106 | kInterpolated, |
107 | kCanBeFlat, // Use "flat" if it will be faster. |
108 | kMustBeFlat // Use "flat" even if it is known to be slow. |
109 | }; |
110 | |
111 | /* |
112 | * addVarying allows fine grained control for setting up varyings between stages. Calling this |
113 | * function will make sure all necessary decls are setup for the client. The client however is |
114 | * responsible for setting up all shader code (e.g "vOut = vIn;") If you just need to take an |
115 | * attribute and pass it through to an output value in a fragment shader, use |
116 | * addPassThroughAttribute. |
117 | * TODO convert most uses of addVarying to addPassThroughAttribute |
118 | */ |
119 | void addVarying(const char* name, GrGLSLVarying* varying, |
120 | Interpolation = Interpolation::kInterpolated); |
121 | |
122 | /* |
123 | * The GP can use these calls to pass an attribute through all shaders directly to 'output' in |
124 | * the fragment shader. Though these calls affect both the vertex shader and fragment shader, |
125 | * they expect 'output' to be defined in the fragment shader before the call is made. If there |
126 | * is a geometry shader, we will simply take the value of the varying from the first vertex and |
127 | * that will be set as the output varying for all emitted vertices. |
128 | * TODO it might be nicer behavior to have a flag to declare output inside these calls |
129 | */ |
130 | void addPassThroughAttribute(const GrGeometryProcessor::Attribute&, const char* output, |
131 | Interpolation = Interpolation::kInterpolated); |
132 | |
133 | void emitAttributes(const GrGeometryProcessor& gp); |
134 | |
135 | // This should be called once all attributes and varyings have been added to the |
136 | // GrGLSLVaryingHanlder and before getting/adding any of the declarations to the shaders. |
137 | void finalize(); |
138 | |
139 | void getVertexDecls(SkString* inputDecls, SkString* outputDecls) const; |
140 | void getGeomDecls(SkString* inputDecls, SkString* outputDecls) const; |
141 | void getFragDecls(SkString* inputDecls, SkString* outputDecls) const; |
142 | |
143 | protected: |
144 | struct VaryingInfo { |
145 | GrSLType fType; |
146 | bool fIsFlat; |
147 | SkString fVsOut; |
148 | SkString fGsOut; |
149 | GrShaderFlags fVisibility; |
150 | }; |
151 | |
152 | typedef GrTAllocator<VaryingInfo> VaryingList; |
153 | typedef GrTAllocator<GrShaderVar> VarArray; |
154 | typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle; |
155 | |
156 | VaryingList fVaryings; |
157 | VarArray fVertexInputs; |
158 | VarArray fVertexOutputs; |
159 | VarArray fGeomInputs; |
160 | VarArray fGeomOutputs; |
161 | VarArray fFragInputs; |
162 | VarArray fFragOutputs; |
163 | |
164 | // This is not owned by the class |
165 | GrGLSLProgramBuilder* fProgramBuilder; |
166 | |
167 | private: |
168 | void addAttribute(const GrShaderVar& var); |
169 | |
170 | virtual void onFinalize() = 0; |
171 | |
172 | // helper function for get*Decls |
173 | void appendDecls(const VarArray& vars, SkString* out) const; |
174 | |
175 | const char* fDefaultInterpolationModifier; |
176 | |
177 | friend class GrGLSLProgramBuilder; |
178 | }; |
179 | |
180 | #endif |
181 | |