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