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