• 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        this->definitions().appendf("const %s %s = ", type, name);
87        va_list args;
88        va_start(args, fmt);
89        this->definitions().appendVAList(fmt, args);
90        va_end(args);
91        this->definitions().append(";\n");
92     }
93 
definitionAppend(const char * str)94     void definitionAppend(const char* str) { this->definitions().append(str); }
95 
96     void declareGlobal(const GrShaderVar&);
97 
98     // Generates a unique variable name for holding the result of a temporary expression when it's
99     // not reasonable to just add a new block for scoping. Does not declare anything.
newTmpVarName(const char * suffix)100     SkString newTmpVarName(const char* suffix) {
101         int tmpIdx = fTmpVariableCounter++;
102         return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix);
103     }
104 
105     /**
106      * Called by GrGLSLProcessors to add code to one of the shaders.
107      */
codeAppendf(const char format[],...)108     void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
109        va_list args;
110        va_start(args, format);
111        this->code().appendVAList(format, args);
112        va_end(args);
113     }
114 
codeAppend(const char * str)115     void codeAppend(const char* str) { this->code().append(str); }
116 
codeAppend(const char * str,size_t length)117     void codeAppend(const char* str, size_t length) { this->code().append(str, length); }
118 
119     void codeAppend(std::unique_ptr<SkSL::Statement> stmt);
120 
codePrependf(const char format[],...)121     void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
122        va_list args;
123        va_start(args, format);
124        this->code().prependVAList(format, args);
125        va_end(args);
126     }
127 
128     /**
129      * Appends a variable declaration to one of the shaders
130      */
131     void declAppend(const GrShaderVar& var);
132 
133     /**
134      * Generates a mangled name for a helper function in the fragment shader. Will give consistent
135      * results if called more than once.
136      */
137     SkString getMangledFunctionName(const char* baseName);
138 
139     /** Emits a prototype for a helper function outside of main() in the fragment shader. */
140     void emitFunctionPrototype(GrSLType returnType,
141                                const char* mangledName,
142                                SkSpan<const GrShaderVar> args);
143 
144     void emitFunctionPrototype(const char* declaration);
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      */
getProgramBuilder()162     GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
163 
164     /**
165      * Helper for begining and ending a block in the shader code.
166      */
167     class ShaderBlock {
168     public:
ShaderBlock(GrGLSLShaderBuilder * builder)169         ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
170             SkASSERT(builder);
171             fBuilder->codeAppend("{");
172         }
173 
~ShaderBlock()174         ~ShaderBlock() {
175             fBuilder->codeAppend("}");
176         }
177     private:
178         GrGLSLShaderBuilder* fBuilder;
179     };
180 
181 protected:
182     typedef SkTBlockList<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 
nextStage()226     void nextStage() {
227         fShaderStrings.push_back();
228         fCodeIndex++;
229     }
230 
deleteStage()231     void deleteStage() {
232         fShaderStrings.pop_back();
233         fCodeIndex--;
234     }
235 
extensions()236     SkString& extensions() { return fShaderStrings[kExtensions]; }
definitions()237     SkString& definitions() { return fShaderStrings[kDefinitions]; }
precisionQualifier()238     SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
layoutQualifiers()239     SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
uniforms()240     SkString& uniforms() { return fShaderStrings[kUniforms]; }
inputs()241     SkString& inputs() { return fShaderStrings[kInputs]; }
outputs()242     SkString& outputs() { return fShaderStrings[kOutputs]; }
functions()243     SkString& functions() { return fShaderStrings[kFunctions]; }
main()244     SkString& main() { return fShaderStrings[kMain]; }
code()245     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::ThreadContext;
292 };
293 #endif
294