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 GrGLShaderBuilder_DEFINED
9 #define GrGLShaderBuilder_DEFINED
10 
11 #include "SkTArray.h"
12 #include "gl/GrGLProcessor.h"
13 #include "gl/GrGLProgramDesc.h"
14 #include "gl/GrGLProgramDataManager.h"
15 
16 #include <stdarg.h>
17 
18 class GrGLContextInfo;
19 class GrGLProgramBuilder;
20 
21 /**
22   base class for all shaders builders
23 */
24 class GrGLShaderBuilder {
25 public:
26     typedef GrGLProcessor::TransformedCoordsArray TransformedCoordsArray;
27     typedef GrGLProcessor::TextureSampler TextureSampler;
28 
29     GrGLShaderBuilder(GrGLProgramBuilder* program);
30 
addInput(GrGLShaderVar i)31     void addInput(GrGLShaderVar i) { fInputs.push_back(i); }
addOutput(GrGLShaderVar i)32     void addOutput(GrGLShaderVar i) { fOutputs.push_back(i); }
33 
34     /*
35      * We put texture lookups in the base class because it is TECHNICALLY possible to do texture
36      * lookups in any kind of shader.  However, for the time being using these calls on non-fragment
37      * shaders will result in a shader compilation error as texture sampler uniforms are only
38      * visible to the fragment shader.  It would not be hard to change this behavior, if someone
39      * actually wants to do texture lookups in a non-fragment shader
40      *
41      * TODO if append texture lookup is used on a non-fragment shader, sampler uniforms should be
42      * made visible to that shaders
43      */
44     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
45         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
46         order of the result depends on the GrTextureAccess associated with the TextureSampler. */
47     void appendTextureLookup(SkString* out,
48                              const TextureSampler&,
49                              const char* coordName,
50                              GrSLType coordType = kVec2f_GrSLType) const;
51 
52     /** Version of above that appends the result to the fragment shader code instead.*/
53     void appendTextureLookup(const TextureSampler&,
54                              const char* coordName,
55                              GrSLType coordType = kVec2f_GrSLType);
56 
57 
58     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
59         always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
60         float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
61         called. */
62     void appendTextureLookupAndModulate(const char* modulation,
63                                         const TextureSampler&,
64                                         const char* coordName,
65                                         GrSLType coordType = kVec2f_GrSLType);
66 
67     /** If texture swizzling is available using tex parameters then it is preferred over mangling
68         the generated shader code. This potentially allows greater reuse of cached shaders. */
69     static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
70 
71     /**
72     * Called by GrGLProcessors to add code to one of the shaders.
73     */
codeAppendf(const char format[],...)74     void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
75        va_list args;
76        va_start(args, format);
77        this->code().appendVAList(format, args);
78        va_end(args);
79     }
80 
codeAppend(const char * str)81     void codeAppend(const char* str) { this->code().append(str); }
82 
codePrependf(const char format[],...)83     void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
84        va_list args;
85        va_start(args, format);
86        this->code().prependVAList(format, args);
87        va_end(args);
88     }
89 
90     /**
91      * Appends a variable declaration to one of the shaders
92      */
93     void declAppend(const GrGLShaderVar& var);
94 
95     /** Emits a helper function outside of main() in the fragment shader. */
96     void emitFunction(GrSLType returnType,
97                       const char* name,
98                       int argCnt,
99                       const GrGLShaderVar* args,
100                       const char* body,
101                       SkString* outName);
102 
103     /*
104      * Get parent builder for adding uniforms
105      */
getProgramBuilder()106     GrGLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
107 
108     /**
109      * Helper for begining and ending a block in the shader code.
110      */
111     class ShaderBlock {
112     public:
ShaderBlock(GrGLShaderBuilder * builder)113         ShaderBlock(GrGLShaderBuilder* builder) : fBuilder(builder) {
114             SkASSERT(builder);
115             fBuilder->codeAppend("{");
116         }
117 
~ShaderBlock()118         ~ShaderBlock() {
119             fBuilder->codeAppend("}");
120         }
121     private:
122         GrGLShaderBuilder* fBuilder;
123     };
124 
125 protected:
126     typedef GrTAllocator<GrGLShaderVar> VarArray;
127     void appendDecls(const VarArray& vars, SkString* out) const;
128 
129     /*
130      * this super low level function is just for use internally to builders
131      */
132     void appendTextureLookup(const char* samplerName,
133                              const char* coordName,
134                              uint32_t configComponentMask,
135                              const char* swizzle);
136 
137     /*
138      * A general function which enables an extension in a shader if the feature bit is not present
139      */
140     void addFeature(uint32_t featureBit, const char* extensionName);
141 
142     enum InterfaceQualifier {
143         kOut_InterfaceQualifier,
144         kLastInterfaceQualifier = kOut_InterfaceQualifier
145     };
146 
147     /*
148      * A low level function to build default layout qualifiers.
149      *
150      *   e.g. layout(param1, param2, ...) out;
151      *
152      * GLSL allows default layout qualifiers for in, out, and uniform.
153      */
154     void addLayoutQualifier(const char* param, InterfaceQualifier);
155 
156     void compileAndAppendLayoutQualifiers();
157 
nextStage()158     void nextStage() {
159         fShaderStrings.push_back();
160         fCompilerStrings.push_back(this->code().c_str());
161         fCompilerStringLengths.push_back((int)this->code().size());
162         fCodeIndex++;
163     }
164 
versionDecl()165     SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
extensions()166     SkString& extensions() { return fShaderStrings[kExtensions]; }
precisionQualifier()167     SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
layoutQualifiers()168     SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
uniforms()169     SkString& uniforms() { return fShaderStrings[kUniforms]; }
inputs()170     SkString& inputs() { return fShaderStrings[kInputs]; }
outputs()171     SkString& outputs() { return fShaderStrings[kOutputs]; }
functions()172     SkString& functions() { return fShaderStrings[kFunctions]; }
main()173     SkString& main() { return fShaderStrings[kMain]; }
code()174     SkString& code() { return fShaderStrings[fCodeIndex]; }
175     bool finalize(GrGLuint programId, GrGLenum type, SkTDArray<GrGLuint>* shaderIds);
176 
177     enum {
178         kVersionDecl,
179         kExtensions,
180         kPrecisionQualifier,
181         kLayoutQualifiers,
182         kUniforms,
183         kInputs,
184         kOutputs,
185         kFunctions,
186         kMain,
187         kCode,
188     };
189 
190     GrGLProgramBuilder* fProgramBuilder;
191     SkSTArray<kCode, const char*, true> fCompilerStrings;
192     SkSTArray<kCode, int, true> fCompilerStringLengths;
193     SkSTArray<kCode, SkString> fShaderStrings;
194     SkString fCode;
195     SkString fFunctions;
196     SkString fExtensions;
197 
198     VarArray fInputs;
199     VarArray fOutputs;
200     uint32_t fFeaturesAddedMask;
201     SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
202     int fCodeIndex;
203     bool fFinalized;
204 
205     friend class GrGLProgramBuilder;
206 };
207 #endif
208