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
18class GrGLContextInfo;
19class GrGLProgramBuilder;
20
21/**
22  base class for all shaders builders
23*/
24class GrGLShaderBuilder {
25public:
26    typedef GrGLProcessor::TransformedCoordsArray TransformedCoordsArray;
27    typedef GrGLProcessor::TextureSampler TextureSampler;
28
29    GrGLShaderBuilder(GrGLProgramBuilder* program);
30
31    void addInput(GrGLShaderVar i) { fInputs.push_back(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    */
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
81    void codeAppend(const char* str) { this->code().append(str); }
82
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     */
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:
113        ShaderBlock(GrGLShaderBuilder* builder) : fBuilder(builder) {
114            SkASSERT(builder);
115            fBuilder->codeAppend("{");
116        }
117
118        ~ShaderBlock() {
119            fBuilder->codeAppend("}");
120        }
121    private:
122        GrGLShaderBuilder* fBuilder;
123    };
124
125protected:
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
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
165    SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
166    SkString& extensions() { return fShaderStrings[kExtensions]; }
167    SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
168    SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
169    SkString& uniforms() { return fShaderStrings[kUniforms]; }
170    SkString& inputs() { return fShaderStrings[kInputs]; }
171    SkString& outputs() { return fShaderStrings[kOutputs]; }
172    SkString& functions() { return fShaderStrings[kFunctions]; }
173    SkString& main() { return fShaderStrings[kMain]; }
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