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