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