GrGLShaderBuilder.h revision 26e18b593ab65e4d92dfbce92579d8bc180d4c2c
1/*
2 * Copyright 2012 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 "GrAllocator.h"
12#include "GrBackendEffectFactory.h"
13#include "GrColor.h"
14#include "GrEffect.h"
15#include "gl/GrGLSL.h"
16#include "gl/GrGLUniformManager.h"
17
18#include <stdarg.h>
19
20class GrGLContextInfo;
21class GrEffectStage;
22class GrGLProgramDesc;
23
24/**
25  Contains all the incremental state of a shader as it is being built,as well as helpers to
26  manipulate that state.
27*/
28class GrGLShaderBuilder {
29public:
30    /**
31     * Passed to GrGLEffects to add texture reads to their shader code.
32     */
33    class TextureSampler {
34    public:
35        TextureSampler()
36            : fConfigComponentMask(0)
37            , fSamplerUniform(GrGLUniformManager::kInvalidUniformHandle) {
38            // we will memcpy the first 4 bytes from passed in swizzle. This ensures the string is
39            // terminated.
40            fSwizzle[4] = '\0';
41        }
42
43        TextureSampler(const TextureSampler& other) { *this = other; }
44
45        TextureSampler& operator= (const TextureSampler& other) {
46            GrAssert(0 == fConfigComponentMask);
47            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
48
49            fConfigComponentMask = other.fConfigComponentMask;
50            fSamplerUniform = other.fSamplerUniform;
51            return *this;
52        }
53
54        // bitfield of GrColorComponentFlags present in the texture's config.
55        uint32_t configComponentMask() const { return fConfigComponentMask; }
56
57        const char* swizzle() const { return fSwizzle; }
58
59        bool isInitialized() const { return 0 != fConfigComponentMask; }
60
61    private:
62        // The idx param is used to ensure multiple samplers within a single effect have unique
63        // uniform names. swizzle is a four char max string made up of chars 'r', 'g', 'b', and 'a'.
64        void init(GrGLShaderBuilder* builder,
65                  uint32_t configComponentMask,
66                  const char* swizzle,
67                  int idx) {
68            GrAssert(!this->isInitialized());
69            GrAssert(0 != configComponentMask);
70            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
71
72            GrAssert(NULL != builder);
73            SkString name;
74            name.printf("Sampler%d_", idx);
75            fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
76                                                  kSampler2D_GrSLType,
77                                                  name.c_str());
78            GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform);
79
80            fConfigComponentMask = configComponentMask;
81            memcpy(fSwizzle, swizzle, 4);
82        }
83
84        void init(GrGLShaderBuilder* builder, const GrTextureAccess* access, int idx) {
85            GrAssert(NULL != access);
86            this->init(builder,
87                       GrPixelConfigComponentMask(access->getTexture()->config()),
88                       access->getSwizzle(),
89                       idx);
90        }
91
92        uint32_t                          fConfigComponentMask;
93        char                              fSwizzle[5];
94        GrGLUniformManager::UniformHandle fSamplerUniform;
95
96        friend class GrGLShaderBuilder; // to call init().
97    };
98
99    typedef SkTArray<TextureSampler> TextureSamplerArray;
100
101    enum ShaderType {
102        kVertex_ShaderType   = 0x1,
103        kGeometry_ShaderType = 0x2,
104        kFragment_ShaderType = 0x4,
105    };
106
107    GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&, const GrGLProgramDesc&);
108
109    /**
110     * Called by GrGLEffects to add code to one of the shaders.
111     */
112    void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
113        va_list args;
114        va_start(args, format);
115        this->codeAppendf(kVertex_ShaderType, format, args);
116        va_end(args);
117    }
118
119    void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
120        va_list args;
121        va_start(args, format);
122        this->codeAppendf(kGeometry_ShaderType, format, args);
123        va_end(args);
124    }
125
126    void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
127        va_list args;
128        va_start(args, format);
129        this->codeAppendf(kFragment_ShaderType, format, args);
130        va_end(args);
131    }
132
133    void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); }
134    void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); }
135    void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); }
136
137    /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
138        Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
139        order of the result depends on the GrTextureAccess associated with the TextureSampler. */
140    void appendTextureLookup(SkString* out,
141                             const TextureSampler&,
142                             const char* coordName,
143                             GrSLType coordType = kVec2f_GrSLType) const;
144
145    /** Version of above that appends the result to the shader code rather than an SkString.
146        Currently the shader type must be kFragment */
147    void appendTextureLookup(ShaderType,
148                             const TextureSampler&,
149                             const char* coordName,
150                             GrSLType coordType = kVec2f_GrSLType);
151
152
153    /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
154        always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
155        float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
156        called. */
157    void appendTextureLookupAndModulate(ShaderType,
158                                        const char* modulation,
159                                        const TextureSampler&,
160                                        const char* coordName,
161                                        GrSLType coordType = kVec2f_GrSLType);
162
163    /** Emits a helper function outside of main(). Currently ShaderType must be
164        kFragment_ShaderType. */
165    void emitFunction(ShaderType shader,
166                      GrSLType returnType,
167                      const char* name,
168                      int argCnt,
169                      const GrGLShaderVar* args,
170                      const char* body,
171                      SkString* outName);
172
173    /** Generates a EffectKey for the shader code based on the texture access parameters and the
174        capabilities of the GL context.  This is useful for keying the shader programs that may
175        have multiple representations, based on the type/format of textures used. */
176    static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&,
177                                                                 const GrGLCaps&);
178
179    typedef uint8_t DstReadKey;
180
181    /**  Returns a key for adding code to read the copy-of-dst color in service of effects that
182         require reading the dst. It must not return 0 because 0 indicates that there is no dst
183         copy read at all. */
184    static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&);
185
186    /** If texture swizzling is available using tex parameters then it is preferred over mangling
187        the generated shader code. This potentially allows greater reuse of cached shaders. */
188    static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
189
190    /** Add a uniform variable to the current program, that has visibility in one or more shaders.
191        visibility is a bitfield of ShaderType values indicating from which shaders the uniform
192        should be accessible. At least one bit must be set. Geometry shader uniforms are not
193        supported at this time. The actual uniform name will be mangled. If outName is not NULL then
194        it will refer to the final uniform name after return. Use the addUniformArray variant to add
195        an array of uniforms.
196    */
197    GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
198                                                 GrSLType type,
199                                                 const char* name,
200                                                 const char** outName = NULL) {
201        return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
202    }
203    GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
204                                                      GrSLType type,
205                                                      const char* name,
206                                                      int arrayCount,
207                                                      const char** outName = NULL);
208
209    const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
210
211    /**
212     * Shortcut for getUniformVariable(u).c_str()
213     */
214    const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
215        return this->getUniformVariable(u).c_str();
216    }
217
218   /** Add a vertex attribute to the current program that is passed in from the vertex data.
219       Returns false if the attribute was already there, true otherwise. */
220    bool addAttribute(GrSLType type, const char* name);
221
222   /** Add a varying variable to the current program to pass values between vertex and fragment
223        shaders. If the last two parameters are non-NULL, they are filled in with the name
224        generated. */
225    void addVarying(GrSLType type,
226                    const char* name,
227                    const char** vsOutName = NULL,
228                    const char** fsInName = NULL);
229
230    /** Returns a variable name that represents the position of the fragment in the FS. The position
231        is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
232    const char* fragmentPosition();
233
234    /** Returns a vertex attribute that represents the vertex position in the VS. This is the
235        pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
236      */
237    const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
238
239    /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
240        as positionAttribute() or it may not be. It depends upon whether the rendering code
241        specified explicit local coords or not in the GrDrawState. */
242    const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
243
244    /** Returns the color of the destination pixel. This may be NULL if no effect advertised
245        that it will read the destination. */
246    const char* dstColor() const;
247
248    /**
249     * Are explicit local coordinates provided as input to the vertex shader.
250     */
251    bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
252
253    /**
254     * Interfaces used by GrGLProgram.
255     * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
256     * Also, GrGLProgram's shader string construction should be moved to this class.
257     */
258
259    /** Called after building is complete to get the final shader string. */
260    void getShader(ShaderType, SkString*) const;
261
262    void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
263    void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
264    // TODO: move remainder of shader code generation to this class and call this privately
265    // Handles of sampler uniforms generated for the effect are appended to samplerHandles.
266    GrGLEffect* createAndEmitGLEffect(
267                                const GrEffectStage& stage,
268                                GrBackendEffectFactory::EffectKey key,
269                                const char* fsInColor, // NULL means no incoming color
270                                const char* fsOutColor,
271                                SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
272
273    GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
274    GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const {
275        return fDstCopyTopLeftUniform;
276    }
277    GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const {
278        return fDstCopyScaleUniform;
279    }
280    GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const {
281        return fDstCopySampler.fSamplerUniform;
282    }
283
284    struct AttributePair {
285        void set(int index, const SkString& name) {
286            fIndex = index; fName = name;
287        }
288        int      fIndex;
289        SkString fName;
290    };
291    const SkTArray<AttributePair, true>& getEffectAttributes() const {
292        return fEffectAttributes;
293    }
294    const SkString* getEffectAttributeName(int attributeIndex) const;
295
296    // TODO: Make this do all the compiling, linking, etc.
297    void finished(GrGLuint programID);
298
299    const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
300
301private:
302    void codeAppendf(ShaderType type, const char format[], va_list args);
303    void codeAppend(ShaderType type, const char* str);
304
305    typedef GrTAllocator<GrGLShaderVar> VarArray;
306
307    void appendDecls(const VarArray&, SkString*) const;
308    void appendUniformDecls(ShaderType, SkString*) const;
309
310    typedef GrGLUniformManager::BuilderUniform BuilderUniform;
311    GrGLUniformManager::BuilderUniformArray fUniforms;
312
313    // TODO: Everything below here private.
314public:
315
316    SkString    fHeader; // VS+FS, GLSL version, etc
317    VarArray    fVSAttrs;
318    VarArray    fVSOutputs;
319    VarArray    fGSInputs;
320    VarArray    fGSOutputs;
321    VarArray    fFSInputs;
322    SkString    fGSHeader; // layout qualifiers specific to GS
323    VarArray    fFSOutputs;
324
325private:
326    enum {
327        kNonStageIdx = -1,
328    };
329
330    // Interpretation of DstReadKey when generating code
331    enum {
332        kNoDstRead_DstReadKey         = 0,
333        kYesDstRead_DstReadKeyBit     = 0x1, // Set if we do a dst-copy-read.
334        kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only.
335        kTopLeftOrigin_DstReadKeyBit  = 0x4, // Set if dst-copy origin is top-left.
336    };
337
338    const GrGLContextInfo&              fCtxInfo;
339    GrGLUniformManager&                 fUniformManager;
340    int                                 fCurrentStageIdx;
341    SkString                            fFSFunctions;
342    SkString                            fFSHeader;
343
344    bool                                fUsesGS;
345
346    SkString                            fFSCode;
347    SkString                            fVSCode;
348    SkString                            fGSCode;
349
350    bool                                fSetupFragPosition;
351    TextureSampler                      fDstCopySampler;
352
353    GrGLUniformManager::UniformHandle   fRTHeightUniform;
354    GrGLUniformManager::UniformHandle   fDstCopyTopLeftUniform;
355    GrGLUniformManager::UniformHandle   fDstCopyScaleUniform;
356
357    SkSTArray<10, AttributePair, true>  fEffectAttributes;
358
359    GrGLShaderVar*                      fPositionVar;
360    GrGLShaderVar*                      fLocalCoordsVar;
361
362};
363
364#endif
365