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
17class GrGLSLProgramBuilder;
18class GrGLSLTextureSampler;
19
20/**
21  base class for all shaders builders
22*/
23class GrGLSLShaderBuilder {
24public:
25    GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
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    */
65    void define(const char* macro, const char* replacement) {
66        this->definitions().appendf("#define %s %s\n", macro, replacement);
67    }
68
69    void define(const char* macro, int replacement) {
70        this->definitions().appendf("#define %s %i\n", macro, replacement);
71    }
72
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    */
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
92    void codeAppend(const char* str) { this->code().append(str); }
93
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     */
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:
129        ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
130            SkASSERT(builder);
131            fBuilder->codeAppend("{");
132        }
133
134        ~ShaderBlock() {
135            fBuilder->codeAppend("}");
136        }
137    private:
138        GrGLSLShaderBuilder* fBuilder;
139    };
140
141protected:
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
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
190    SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
191    SkString& extensions() { return fShaderStrings[kExtensions]; }
192    SkString& definitions() { return fShaderStrings[kDefinitions]; }
193    SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
194    SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
195    SkString& uniforms() { return fShaderStrings[kUniforms]; }
196    SkString& inputs() { return fShaderStrings[kInputs]; }
197    SkString& outputs() { return fShaderStrings[kOutputs]; }
198    SkString& functions() { return fShaderStrings[kFunctions]; }
199    SkString& main() { return fShaderStrings[kMain]; }
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