/src/skia/src/gpu/glsl/GrGLSLShaderBuilder.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2014 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 GrGLSLShaderBuilder_DEFINED |
9 | | #define GrGLSLShaderBuilder_DEFINED |
10 | | |
11 | | #include "include/core/SkSpan.h" |
12 | | #include "include/private/SkSLStatement.h" |
13 | | #include "include/private/SkSLString.h" |
14 | | #include "include/private/SkTDArray.h" |
15 | | #include "src/gpu/GrShaderVar.h" |
16 | | #include "src/gpu/GrTBlockList.h" |
17 | | #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
18 | | |
19 | | #include <stdarg.h> |
20 | | |
21 | | class GrGLSLColorSpaceXformHelper; |
22 | | |
23 | | namespace SkSL { |
24 | | namespace dsl { |
25 | | class DSLWriter; |
26 | | } |
27 | | } |
28 | | |
29 | | /** |
30 | | base class for all shaders builders |
31 | | */ |
32 | | class GrGLSLShaderBuilder { |
33 | | public: |
34 | | GrGLSLShaderBuilder(GrGLSLProgramBuilder* program); |
35 | 0 | virtual ~GrGLSLShaderBuilder() {} |
36 | | |
37 | | using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; |
38 | | |
39 | | /** Appends a 2D texture sample with projection if necessary. The vec length and swizzle |
40 | | order of the result depends on the GrProcessor::TextureSampler associated with the |
41 | | SamplerHandle. |
42 | | */ |
43 | | void appendTextureLookup(SkString* out, SamplerHandle, const char* coordName) const; |
44 | | |
45 | | /** Version of above that appends the result to the shader code instead.*/ |
46 | | void appendTextureLookup(SamplerHandle, |
47 | | const char* coordName, |
48 | | GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); |
49 | | |
50 | | /** Does the work of appendTextureLookup and blends the result by dst, treating the texture |
51 | | lookup as the src input to the blend. The dst is assumed to be half4 and the result is |
52 | | always a half4. If dst is nullptr we use half4(1) as the blend dst. */ |
53 | | void appendTextureLookupAndBlend(const char* dst, |
54 | | SkBlendMode, |
55 | | SamplerHandle, |
56 | | const char* coordName, |
57 | | GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); |
58 | | |
59 | | /** Appends a load of an input attachment into the shader code. */ |
60 | | void appendInputLoad(SamplerHandle); |
61 | | |
62 | | /** Adds a helper function to facilitate color gamut transformation, and produces code that |
63 | | returns the srcColor transformed into a new gamut (via multiplication by the xform from |
64 | | colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper |
65 | | determines if the source is premultipled or not). */ |
66 | | void appendColorGamutXform(SkString* out, const char* srcColor, |
67 | | GrGLSLColorSpaceXformHelper* colorXformHelper); |
68 | | |
69 | | /** Version of above that appends the result to the shader code instead. */ |
70 | | void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper); |
71 | | |
72 | | /** |
73 | | * Adds a constant declaration to the top of the shader. |
74 | | */ |
75 | 0 | void defineConstant(const char* type, const char* name, const char* value) { |
76 | 0 | this->definitions().appendf("const %s %s = %s;\n", type, name, value); |
77 | 0 | } |
78 | | |
79 | 0 | void defineConstant(const char* name, int value) { |
80 | 0 | this->definitions().appendf("const int %s = %i;\n", name, value); |
81 | 0 | } |
82 | | |
83 | 0 | void defineConstant(const char* name, float value) { |
84 | 0 | this->definitions().appendf("const float %s = %f;\n", name, value); |
85 | 0 | } |
86 | | |
87 | 0 | void defineConstantf(const char* type, const char* name, const char* fmt, ...) { |
88 | 0 | this->definitions().appendf("const %s %s = ", type, name); |
89 | 0 | va_list args; |
90 | 0 | va_start(args, fmt); |
91 | 0 | this->definitions().appendVAList(fmt, args); |
92 | 0 | va_end(args); |
93 | 0 | this->definitions().append(";\n"); |
94 | 0 | } |
95 | | |
96 | 0 | void definitionAppend(const char* str) { this->definitions().append(str); } |
97 | | |
98 | | void declareGlobal(const GrShaderVar&); |
99 | | |
100 | | // Generates a unique variable name for holding the result of a temporary expression when it's |
101 | | // not reasonable to just add a new block for scoping. Does not declare anything. |
102 | 0 | SkString newTmpVarName(const char* suffix) { |
103 | 0 | int tmpIdx = fTmpVariableCounter++; |
104 | 0 | return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix); |
105 | 0 | } |
106 | | |
107 | | /** |
108 | | * Called by GrGLSLProcessors to add code to one of the shaders. |
109 | | */ |
110 | 0 | void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { |
111 | 0 | va_list args; |
112 | 0 | va_start(args, format); |
113 | 0 | this->code().appendVAList(format, args); |
114 | 0 | va_end(args); |
115 | 0 | } |
116 | | |
117 | 0 | void codeAppend(const char* str) { this->code().append(str); } |
118 | | |
119 | 0 | void codeAppend(const char* str, size_t length) { this->code().append(str, length); } |
120 | | |
121 | | void codeAppend(std::unique_ptr<SkSL::Statement> stmt); |
122 | | |
123 | 0 | void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { |
124 | 0 | va_list args; |
125 | 0 | va_start(args, format); |
126 | 0 | this->code().prependVAList(format, args); |
127 | 0 | va_end(args); |
128 | 0 | } |
129 | | |
130 | | /** |
131 | | * Appends a variable declaration to one of the shaders |
132 | | */ |
133 | | void declAppend(const GrShaderVar& var); |
134 | | |
135 | | /** |
136 | | * Generates a mangled name for a helper function in the fragment shader. Will give consistent |
137 | | * results if called more than once. |
138 | | */ |
139 | | SkString getMangledFunctionName(const char* baseName); |
140 | | |
141 | | /** Emits a prototype for a helper function outside of main() in the fragment shader. */ |
142 | | void emitFunctionPrototype(GrSLType returnType, |
143 | | const char* mangledName, |
144 | | SkSpan<const GrShaderVar> args); |
145 | | |
146 | | /** Emits a helper function outside of main() in the fragment shader. */ |
147 | | void emitFunction(GrSLType returnType, |
148 | | const char* mangledName, |
149 | | SkSpan<const GrShaderVar> args, |
150 | | const char* body); |
151 | | |
152 | | void emitFunction(const char* declaration, const char* body); |
153 | | |
154 | | /** |
155 | | * Combines the various parts of the shader to create a single finalized shader string. |
156 | | */ |
157 | | void finalize(uint32_t visibility); |
158 | | |
159 | | /** |
160 | | * Get parent builder for adding uniforms. |
161 | | */ |
162 | 0 | GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; } |
163 | | |
164 | | /** |
165 | | * Helper for begining and ending a block in the shader code. |
166 | | */ |
167 | | class ShaderBlock { |
168 | | public: |
169 | 0 | ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) { |
170 | 0 | SkASSERT(builder); |
171 | 0 | fBuilder->codeAppend("{"); |
172 | 0 | } Unexecuted instantiation: GrGLSLShaderBuilder::ShaderBlock::ShaderBlock(GrGLSLShaderBuilder*) Unexecuted instantiation: GrGLSLShaderBuilder::ShaderBlock::ShaderBlock(GrGLSLShaderBuilder*) |
173 | | |
174 | 0 | ~ShaderBlock() { |
175 | 0 | fBuilder->codeAppend("}"); |
176 | 0 | } |
177 | | private: |
178 | | GrGLSLShaderBuilder* fBuilder; |
179 | | }; |
180 | | |
181 | | protected: |
182 | | typedef GrTBlockList<GrShaderVar> VarArray; |
183 | | void appendDecls(const VarArray& vars, SkString* out) const; |
184 | | |
185 | | void appendFunctionDecl(GrSLType returnType, |
186 | | const char* mangledName, |
187 | | SkSpan<const GrShaderVar> args); |
188 | | |
189 | | /** |
190 | | * Features that should only be enabled internally by the builders. |
191 | | */ |
192 | | enum GLSLPrivateFeature { |
193 | | kFragCoordConventions_GLSLPrivateFeature, |
194 | | kBlendEquationAdvanced_GLSLPrivateFeature, |
195 | | kBlendFuncExtended_GLSLPrivateFeature, |
196 | | kFramebufferFetch_GLSLPrivateFeature, |
197 | | kNoPerspectiveInterpolation_GLSLPrivateFeature, |
198 | | kSampleVariables_GLSLPrivateFeature, |
199 | | kLastGLSLPrivateFeature = kSampleVariables_GLSLPrivateFeature |
200 | | }; |
201 | | |
202 | | /* |
203 | | * A general function which enables an extension in a shader if the feature bit is not present |
204 | | * |
205 | | * @return true if the feature bit was not yet present, false otherwise. |
206 | | */ |
207 | | bool addFeature(uint32_t featureBit, const char* extensionName); |
208 | | |
209 | | enum InterfaceQualifier { |
210 | | kIn_InterfaceQualifier, |
211 | | kOut_InterfaceQualifier, |
212 | | kLastInterfaceQualifier = kOut_InterfaceQualifier |
213 | | }; |
214 | | |
215 | | /* |
216 | | * A low level function to build default layout qualifiers. |
217 | | * |
218 | | * e.g. layout(param1, param2, ...) out; |
219 | | * |
220 | | * GLSL allows default layout qualifiers for in, out, and uniform. |
221 | | */ |
222 | | void addLayoutQualifier(const char* param, InterfaceQualifier); |
223 | | |
224 | | void compileAndAppendLayoutQualifiers(); |
225 | | |
226 | 0 | void nextStage() { |
227 | 0 | fShaderStrings.push_back(); |
228 | 0 | fCodeIndex++; |
229 | 0 | } |
230 | | |
231 | 0 | void deleteStage() { |
232 | 0 | fShaderStrings.pop_back(); |
233 | 0 | fCodeIndex--; |
234 | 0 | } |
235 | | |
236 | 0 | SkString& extensions() { return fShaderStrings[kExtensions]; } |
237 | 0 | SkString& definitions() { return fShaderStrings[kDefinitions]; } |
238 | 0 | SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; } |
239 | 0 | SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; } |
240 | 0 | SkString& uniforms() { return fShaderStrings[kUniforms]; } |
241 | 0 | SkString& inputs() { return fShaderStrings[kInputs]; } |
242 | 0 | SkString& outputs() { return fShaderStrings[kOutputs]; } |
243 | 0 | SkString& functions() { return fShaderStrings[kFunctions]; } |
244 | 0 | SkString& main() { return fShaderStrings[kMain]; } |
245 | 0 | SkString& code() { return fShaderStrings[fCodeIndex]; } |
246 | | |
247 | | virtual void onFinalize() = 0; |
248 | | |
249 | | enum { |
250 | | kExtensions, |
251 | | kDefinitions, |
252 | | kPrecisionQualifier, |
253 | | kLayoutQualifiers, |
254 | | kUniforms, |
255 | | kInputs, |
256 | | kOutputs, |
257 | | kFunctions, |
258 | | kMain, |
259 | | kCode, |
260 | | |
261 | | kPrealloc = kCode + 6, // 6 == Reasonable upper bound on number of processor stages |
262 | | }; |
263 | | |
264 | | GrGLSLProgramBuilder* fProgramBuilder; |
265 | | SkSL::String fCompilerString; |
266 | | SkSTArray<kPrealloc, SkString> fShaderStrings; |
267 | | SkString fCode; |
268 | | SkString fFunctions; |
269 | | SkString fExtensions; |
270 | | // Hangs onto Declarations so we don't destroy them prior to the variables that refer to them. |
271 | | SkSL::StatementArray fDeclarations; |
272 | | |
273 | | VarArray fInputs; |
274 | | VarArray fOutputs; |
275 | | uint32_t fFeaturesAddedMask; |
276 | | SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1]; |
277 | | int fCodeIndex; |
278 | | bool fFinalized; |
279 | | |
280 | | // Counter for generating unique scratch variable names in a shader. |
281 | | int fTmpVariableCounter; |
282 | | |
283 | | friend class GrGLSLProgramBuilder; |
284 | | friend class GrGLProgramBuilder; |
285 | | friend class GrD3DPipelineStateBuilder; |
286 | | friend class GrDawnProgramBuilder; |
287 | | friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature. |
288 | | friend class GrGLPathProgramBuilder; // to access fInputs. |
289 | | friend class GrVkPipelineStateBuilder; |
290 | | friend class GrMtlPipelineStateBuilder; |
291 | | friend class SkSL::dsl::DSLWriter; |
292 | | }; |
293 | | #endif |