GrGLSLShaderBuilder.h revision 5af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64
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 "GrShaderVar.h"
13#include "glsl/GrGLSLUniformHandler.h"
14#include "SkTDArray.h"
15
16#include <stdarg.h>
17
18class GrGLSLColorSpaceXformHelper;
19
20/**
21  base class for all shaders builders
22*/
23class GrGLSLShaderBuilder {
24public:
25    GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
26    virtual ~GrGLSLShaderBuilder() {}
27
28    using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
29    using TexelBufferHandle  = GrGLSLUniformHandler::TexelBufferHandle;
30    using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
31
32    /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
33        Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
34        order of the result depends on the GrProcessor::TextureSampler associated with the
35        SamplerHandle.
36        */
37    void appendTextureLookup(SkString* out,
38                             SamplerHandle,
39                             const char* coordName,
40                             GrSLType coordType = kVec2f_GrSLType) const;
41
42    /** Version of above that appends the result to the shader code instead.*/
43    void appendTextureLookup(SamplerHandle,
44                             const char* coordName,
45                             GrSLType coordType = kVec2f_GrSLType,
46                             GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
47
48
49    /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
50        always a float4. modulation and the swizzle specified by SamplerHandle must both be
51        float4 or float. If modulation is "" or nullptr it this function acts as though
52        appendTextureLookup were called. */
53    void appendTextureLookupAndModulate(const char* modulation,
54                                        SamplerHandle,
55                                        const char* coordName,
56                                        GrSLType coordType = kVec2f_GrSLType,
57                                        GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
58
59    /** Adds a helper function to facilitate color gamut transformation, and produces code that
60        returns the srcColor transformed into a new gamut (via multiplication by the xform from
61        colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
62        determines if the source is premultipled or not). */
63    void appendColorGamutXform(SkString* out, const char* srcColor,
64                               GrGLSLColorSpaceXformHelper* colorXformHelper);
65
66    /** Version of above that appends the result to the shader code instead. */
67    void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
68
69    /** Fetches an unfiltered texel from a sampler at integer coordinates. coordExpr must match the
70        dimensionality of the sampler and must be within the sampler's range. coordExpr is emitted
71        exactly once, so expressions like "idx++" are acceptable. */
72    void appendTexelFetch(SkString* out, TexelBufferHandle, const char* coordExpr) const;
73
74    /** Version of above that appends the result to the shader code instead.*/
75    void appendTexelFetch(TexelBufferHandle, const char* coordExpr);
76
77    /** Creates a string of shader code that performs an image load. */
78    void appendImageStorageLoad(SkString* out, ImageStorageHandle, const char* coordExpr);
79    /** Version of above that appends the result to the shader code instead. */
80    void appendImageStorageLoad(ImageStorageHandle, const char* coordExpr);
81
82    /**
83    * Adds a constant declaration to the top of the shader.
84    */
85    void defineConstant(const char* type, const char* name, const char* value) {
86        this->definitions().appendf("const %s %s = %s;\n", type, name, value);
87    }
88
89    void defineConstant(const char* name, int value) {
90        this->definitions().appendf("const int %s = %i;\n", name, value);
91    }
92
93    void defineConstant(const char* name, float value) {
94        this->definitions().appendf("const float %s = %f;\n", name, value);
95    }
96
97    void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
98       this->definitions().appendf("const %s %s = ", type, name);
99       va_list args;
100       va_start(args, fmt);
101       this->definitions().appendVAList(fmt, args);
102       va_end(args);
103       this->definitions().append(";\n");
104    }
105
106    void declareGlobal(const GrShaderVar&);
107
108    /**
109    * Called by GrGLSLProcessors to add code to one of the shaders.
110    */
111    void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
112       va_list args;
113       va_start(args, format);
114       this->code().appendVAList(format, args);
115       va_end(args);
116    }
117
118    void codeAppend(const char* str) { this->code().append(str); }
119
120    void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
121       va_list args;
122       va_start(args, format);
123       this->code().prependVAList(format, args);
124       va_end(args);
125    }
126
127    /**
128     * Appends a variable declaration to one of the shaders
129     */
130    void declAppend(const GrShaderVar& var);
131
132    /** Emits a helper function outside of main() in the fragment shader. */
133    void emitFunction(GrSLType returnType,
134                      const char* name,
135                      int argCnt,
136                      const GrShaderVar* args,
137                      const char* body,
138                      SkString* outName);
139
140    /*
141     * Combines the various parts of the shader to create a single finalized shader string.
142     */
143    void finalize(uint32_t visibility);
144
145    /*
146     * Get parent builder for adding uniforms
147     */
148    GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
149
150    /**
151     * Helper for begining and ending a block in the shader code.
152     */
153    class ShaderBlock {
154    public:
155        ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
156            SkASSERT(builder);
157            fBuilder->codeAppend("{");
158        }
159
160        ~ShaderBlock() {
161            fBuilder->codeAppend("}");
162        }
163    private:
164        GrGLSLShaderBuilder* fBuilder;
165    };
166
167protected:
168    typedef GrTAllocator<GrShaderVar> VarArray;
169    void appendDecls(const VarArray& vars, SkString* out) const;
170
171    /**
172     * Features that should only be enabled internally by the builders.
173     */
174    enum GLSLPrivateFeature {
175        kFragCoordConventions_GLSLPrivateFeature,
176        kBlendEquationAdvanced_GLSLPrivateFeature,
177        kBlendFuncExtended_GLSLPrivateFeature,
178        kExternalTexture_GLSLPrivateFeature,
179        kTexelBuffer_GLSLPrivateFeature,
180        kFramebufferFetch_GLSLPrivateFeature,
181        kNoPerspectiveInterpolation_GLSLPrivateFeature,
182        kSampleVariables_GLSLPrivateFeature,
183        kSampleMaskOverrideCoverage_GLSLPrivateFeature,
184        kLastGLSLPrivateFeature = kSampleMaskOverrideCoverage_GLSLPrivateFeature
185    };
186
187    /*
188     * A general function which enables an extension in a shader if the feature bit is not present
189     *
190     * @return true if the feature bit was not yet present, false otherwise.
191     */
192    bool addFeature(uint32_t featureBit, const char* extensionName);
193
194    enum InterfaceQualifier {
195        kIn_InterfaceQualifier,
196        kOut_InterfaceQualifier,
197        kLastInterfaceQualifier = kOut_InterfaceQualifier
198    };
199
200    /*
201     * A low level function to build default layout qualifiers.
202     *
203     *   e.g. layout(param1, param2, ...) out;
204     *
205     * GLSL allows default layout qualifiers for in, out, and uniform.
206     */
207    void addLayoutQualifier(const char* param, InterfaceQualifier);
208
209    void compileAndAppendLayoutQualifiers();
210
211    void nextStage() {
212        fShaderStrings.push_back();
213        fCompilerStrings.push_back(this->code().c_str());
214        fCompilerStringLengths.push_back((int)this->code().size());
215        fCodeIndex++;
216    }
217
218    SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
219    SkString& extensions() { return fShaderStrings[kExtensions]; }
220    SkString& definitions() { return fShaderStrings[kDefinitions]; }
221    SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
222    SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
223    SkString& uniforms() { return fShaderStrings[kUniforms]; }
224    SkString& inputs() { return fShaderStrings[kInputs]; }
225    SkString& outputs() { return fShaderStrings[kOutputs]; }
226    SkString& functions() { return fShaderStrings[kFunctions]; }
227    SkString& main() { return fShaderStrings[kMain]; }
228    SkString& code() { return fShaderStrings[fCodeIndex]; }
229
230    virtual void onFinalize() = 0;
231
232    enum {
233        kVersionDecl,
234        kExtensions,
235        kDefinitions,
236        kPrecisionQualifier,
237        kLayoutQualifiers,
238        kUniforms,
239        kInputs,
240        kOutputs,
241        kFunctions,
242        kMain,
243        kCode,
244    };
245
246    GrGLSLProgramBuilder* fProgramBuilder;
247    SkSTArray<kCode, const char*, true> fCompilerStrings;
248    SkSTArray<kCode, int, true> fCompilerStringLengths;
249    SkSTArray<kCode, SkString> fShaderStrings;
250    SkString fCode;
251    SkString fFunctions;
252    SkString fExtensions;
253
254    VarArray fInputs;
255    VarArray fOutputs;
256    uint32_t fFeaturesAddedMask;
257    SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
258    int fCodeIndex;
259    bool fFinalized;
260
261    friend class GrGLSLProgramBuilder;
262    friend class GrGLProgramBuilder;
263    friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
264    friend class GrGLPathProgramBuilder; // to access fInputs.
265    friend class GrVkPipelineStateBuilder;
266};
267#endif
268