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 "GrAllocator.h"
12 #include "glsl/GrGLSLShaderVar.h"
13 #include "SkTDArray.h"
14 
15 #include <stdarg.h>
16 
17 class GrGLSLProgramBuilder;
18 class GrGLSLTextureSampler;
19 
20 /**
21   base class for all shaders builders
22 */
23 class GrGLSLShaderBuilder {
24 public:
25     GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
~GrGLSLShaderBuilder()26     virtual ~GrGLSLShaderBuilder() {}
27 
28     /*
29      * We put texture lookups in the base class because it is TECHNICALLY possible to do texture
30      * lookups in any kind of shader.  However, for the time being using these calls on non-fragment
31      * shaders will result in a shader compilation error as texture sampler uniforms are only
32      * visible to the fragment shader.  It would not be hard to change this behavior, if someone
33      * actually wants to do texture lookups in a non-fragment shader
34      *
35      * TODO if append texture lookup is used on a non-fragment shader, sampler uniforms should be
36      * made visible to that shaders
37      */
38     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
39         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
40         order of the result depends on the GrTextureAccess associated with the GrGLSLTextureSampler.
41         */
42     void appendTextureLookup(SkString* out,
43                              const GrGLSLTextureSampler&,
44                              const char* coordName,
45                              GrSLType coordType = kVec2f_GrSLType) const;
46 
47     /** Version of above that appends the result to the fragment shader code instead.*/
48     void appendTextureLookup(const GrGLSLTextureSampler&,
49                              const char* coordName,
50                              GrSLType coordType = kVec2f_GrSLType);
51 
52 
53     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
54         always a vec4. modulation and the swizzle specified by GrGLSLTextureSampler must both be
55         vec4 or float. If modulation is "" or nullptr it this function acts as though
56         appendTextureLookup were called. */
57     void appendTextureLookupAndModulate(const char* modulation,
58                                         const GrGLSLTextureSampler&,
59                                         const char* coordName,
60                                         GrSLType coordType = kVec2f_GrSLType);
61 
62     /**
63     * Adds a #define directive to the top of the shader.
64     */
define(const char * macro,const char * replacement)65     void define(const char* macro, const char* replacement) {
66         this->definitions().appendf("#define %s %s\n", macro, replacement);
67     }
68 
define(const char * macro,int replacement)69     void define(const char* macro, int replacement) {
70         this->definitions().appendf("#define %s %i\n", macro, replacement);
71     }
72 
definef(const char * macro,const char * replacement,...)73     void definef(const char* macro, const char* replacement, ...) {
74        this->definitions().appendf("#define %s ", macro);
75        va_list args;
76        va_start(args, replacement);
77        this->definitions().appendVAList(replacement, args);
78        va_end(args);
79        this->definitions().append("\n");
80     }
81 
82     /**
83     * Called by GrGLSLProcessors to add code to one of the shaders.
84     */
codeAppendf(const char format[],...)85     void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
86        va_list args;
87        va_start(args, format);
88        this->code().appendVAList(format, args);
89        va_end(args);
90     }
91 
codeAppend(const char * str)92     void codeAppend(const char* str) { this->code().append(str); }
93 
codePrependf(const char format[],...)94     void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
95        va_list args;
96        va_start(args, format);
97        this->code().prependVAList(format, args);
98        va_end(args);
99     }
100 
101     /**
102      * Appends a variable declaration to one of the shaders
103      */
104     void declAppend(const GrGLSLShaderVar& var);
105 
106     /** Emits a helper function outside of main() in the fragment shader. */
107     void emitFunction(GrSLType returnType,
108                       const char* name,
109                       int argCnt,
110                       const GrGLSLShaderVar* args,
111                       const char* body,
112                       SkString* outName);
113 
114     /*
115      * Combines the various parts of the shader to create a single finalized shader string.
116      */
117     void finalize(uint32_t visibility);
118 
119     /*
120      * Get parent builder for adding uniforms
121      */
getProgramBuilder()122     GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
123 
124     /**
125      * Helper for begining and ending a block in the shader code.
126      */
127     class ShaderBlock {
128     public:
ShaderBlock(GrGLSLShaderBuilder * builder)129         ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
130             SkASSERT(builder);
131             fBuilder->codeAppend("{");
132         }
133 
~ShaderBlock()134         ~ShaderBlock() {
135             fBuilder->codeAppend("}");
136         }
137     private:
138         GrGLSLShaderBuilder* fBuilder;
139     };
140 
141 protected:
142     typedef GrTAllocator<GrGLSLShaderVar> VarArray;
143     void appendDecls(const VarArray& vars, SkString* out) const;
144 
145     /**
146      * Features that should only be enabled internally by the builders.
147      */
148     enum GLSLPrivateFeature {
149         kFragCoordConventions_GLSLPrivateFeature,
150         kBlendEquationAdvanced_GLSLPrivateFeature,
151         kBlendFuncExtended_GLSLPrivateFeature,
152         kExternalTexture_GLSLPrivateFeature,
153         kFramebufferFetch_GLSLPrivateFeature,
154         kNoPerspectiveInterpolation_GLSLPrivateFeature,
155         kSampleVariables_GLSLPrivateFeature,
156         kSampleMaskOverrideCoverage_GLSLPrivateFeature,
157         kLastGLSLPrivateFeature = kSampleMaskOverrideCoverage_GLSLPrivateFeature
158     };
159 
160     /*
161      * A general function which enables an extension in a shader if the feature bit is not present
162      *
163      * @return true if the feature bit was not yet present, false otherwise.
164      */
165     bool addFeature(uint32_t featureBit, const char* extensionName);
166 
167     enum InterfaceQualifier {
168         kOut_InterfaceQualifier,
169         kLastInterfaceQualifier = kOut_InterfaceQualifier
170     };
171 
172     /*
173      * A low level function to build default layout qualifiers.
174      *
175      *   e.g. layout(param1, param2, ...) out;
176      *
177      * GLSL allows default layout qualifiers for in, out, and uniform.
178      */
179     void addLayoutQualifier(const char* param, InterfaceQualifier);
180 
181     void compileAndAppendLayoutQualifiers();
182 
nextStage()183     void nextStage() {
184         fShaderStrings.push_back();
185         fCompilerStrings.push_back(this->code().c_str());
186         fCompilerStringLengths.push_back((int)this->code().size());
187         fCodeIndex++;
188     }
189 
versionDecl()190     SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
extensions()191     SkString& extensions() { return fShaderStrings[kExtensions]; }
definitions()192     SkString& definitions() { return fShaderStrings[kDefinitions]; }
precisionQualifier()193     SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
layoutQualifiers()194     SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
uniforms()195     SkString& uniforms() { return fShaderStrings[kUniforms]; }
inputs()196     SkString& inputs() { return fShaderStrings[kInputs]; }
outputs()197     SkString& outputs() { return fShaderStrings[kOutputs]; }
functions()198     SkString& functions() { return fShaderStrings[kFunctions]; }
main()199     SkString& main() { return fShaderStrings[kMain]; }
code()200     SkString& code() { return fShaderStrings[fCodeIndex]; }
201 
202     virtual void onFinalize() = 0;
203 
204     enum {
205         kVersionDecl,
206         kExtensions,
207         kDefinitions,
208         kPrecisionQualifier,
209         kLayoutQualifiers,
210         kUniforms,
211         kInputs,
212         kOutputs,
213         kFunctions,
214         kMain,
215         kCode,
216     };
217 
218     GrGLSLProgramBuilder* fProgramBuilder;
219     SkSTArray<kCode, const char*, true> fCompilerStrings;
220     SkSTArray<kCode, int, true> fCompilerStringLengths;
221     SkSTArray<kCode, SkString> fShaderStrings;
222     SkString fCode;
223     SkString fFunctions;
224     SkString fExtensions;
225 
226     VarArray fInputs;
227     VarArray fOutputs;
228     uint32_t fFeaturesAddedMask;
229     SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
230     int fCodeIndex;
231     bool fFinalized;
232 
233     friend class GrGLSLProgramBuilder;
234     friend class GrGLProgramBuilder;
235     friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
236     friend class GrGLPathProgramBuilder; // to access fInputs.
237     friend class GrVkProgramBuilder;
238 };
239 #endif
240