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 "GrEffect.h"
14#include "gl/GrGLSL.h"
15#include "gl/GrGLUniformManager.h"
16
17class GrGLContextInfo;
18
19/**
20  Contains all the incremental state of a shader as it is being built,as well as helpers to
21  manipulate that state.
22*/
23class GrGLShaderBuilder {
24public:
25    /**
26     * Passed to GrGLEffects to add texture reads to their shader code.
27     */
28    class TextureSampler {
29    public:
30        TextureSampler()
31            : fTextureAccess(NULL)
32            , fSamplerUniform(GrGLUniformManager::kInvalidUniformHandle) {}
33
34        TextureSampler(const TextureSampler& other) { *this = other; }
35
36        TextureSampler& operator= (const TextureSampler& other) {
37            GrAssert(NULL == fTextureAccess);
38            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
39
40            fTextureAccess = other.fTextureAccess;
41            fSamplerUniform = other.fSamplerUniform;
42            return *this;
43        }
44
45        const GrTextureAccess* textureAccess() const { return fTextureAccess; }
46
47    private:
48        // The idx param is used to ensure multiple samplers within a single effect have unique
49        // uniform names.
50        void init(GrGLShaderBuilder* builder, const GrTextureAccess* access, int idx) {
51            GrAssert(NULL == fTextureAccess);
52            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
53
54            GrAssert(NULL != builder);
55            GrAssert(NULL != access);
56            SkString name;
57            name.printf("Sampler%d_", idx);
58            fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
59                                                  kSampler2D_GrSLType,
60                                                  name.c_str());
61            GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform);
62
63            fTextureAccess = access;
64        }
65
66        const GrTextureAccess*            fTextureAccess;
67        GrGLUniformManager::UniformHandle fSamplerUniform;
68
69        friend class GrGLShaderBuilder; // to access fSamplerUniform
70        friend class GrGLProgram;       // to construct these and access fSamplerUniform.
71    };
72
73    typedef SkTArray<TextureSampler> TextureSamplerArray;
74
75    enum ShaderType {
76        kVertex_ShaderType   = 0x1,
77        kGeometry_ShaderType = 0x2,
78        kFragment_ShaderType = 0x4,
79    };
80
81    GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&);
82
83    /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
84        Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
85        order of the result depends on the GrTextureAccess associated with the TextureSampler. */
86    void appendTextureLookup(SkString* out,
87                             const TextureSampler&,
88                             const char* coordName,
89                             GrSLType coordType = kVec2f_GrSLType) const;
90
91    /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
92        always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
93        float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
94        called. */
95    void appendTextureLookupAndModulate(SkString* out,
96                                        const char* modulation,
97                                        const TextureSampler&,
98                                        const char* coordName,
99                                        GrSLType coordType = kVec2f_GrSLType) const;
100
101    /** Emits a helper function outside of main(). Currently ShaderType must be
102        kFragment_ShaderType. */
103    void emitFunction(ShaderType shader,
104                      GrSLType returnType,
105                      const char* name,
106                      int argCnt,
107                      const GrGLShaderVar* args,
108                      const char* body,
109                      SkString* outName);
110
111    /** Generates a EffectKey for the shader code based on the texture access parameters and the
112        capabilities of the GL context.  This is useful for keying the shader programs that may
113        have multiple representations, based on the type/format of textures used. */
114    static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&,
115                                                                 const GrGLCaps&);
116
117    /** If texture swizzling is available using tex parameters then it is preferred over mangling
118        the generated shader code. This potentially allows greater reuse of cached shaders. */
119    static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
120
121    /** Add a uniform variable to the current program, that has visibility in one or more shaders.
122        visibility is a bitfield of ShaderType values indicating from which shaders the uniform
123        should be accessible. At least one bit must be set. Geometry shader uniforms are not
124        supported at this time. The actual uniform name will be mangled. If outName is not NULL then
125        it will refer to the final uniform name after return. Use the addUniformArray variant to add
126        an array of uniforms.
127    */
128    GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
129                                                 GrSLType type,
130                                                 const char* name,
131                                                 const char** outName = NULL) {
132        return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
133    }
134    GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
135                                                      GrSLType type,
136                                                      const char* name,
137                                                      int arrayCount,
138                                                      const char** outName = NULL);
139
140    const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
141
142    /**
143     * Shortcut for getUniformVariable(u).c_str()
144     */
145    const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
146        return this->getUniformVariable(u).c_str();
147    }
148
149    /** Add a varying variable to the current program to pass values between vertex and fragment
150        shaders. If the last two parameters are non-NULL, they are filled in with the name
151        generated. */
152    void addVarying(GrSLType type,
153                    const char* name,
154                    const char** vsOutName = NULL,
155                    const char** fsInName = NULL);
156
157    /** Returns a variable name that represents the position of the fragment in the FS. The position
158        is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
159    const char* fragmentPosition();
160
161    /** Returns a vertex attribute that represents the vertex position in the VS. This is the
162        pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
163      */
164    const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
165
166    /**
167     * Interfaces used by GrGLProgram.
168     * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
169     * Also, GrGLProgram's shader string construction should be moved to this class.
170     */
171
172    /** Called after building is complete to get the final shader string. */
173    void getShader(ShaderType, SkString*) const;
174
175    void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
176    void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
177    // TODO: move remainder of shader code generation to this class and call this privately
178    // Handles of sampler uniforms generated for the effect are appended to samplerHandles.
179    GrGLEffect* createAndEmitGLEffect(
180                                const GrEffectStage& stage,
181                                GrBackendEffectFactory::EffectKey key,
182                                const char* fsInColor, // NULL means no incoming color
183                                const char* fsOutColor,
184                                const char* vsInCoord,
185                                SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
186    GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
187    // TODO: Make this do all the compiling, linking, etc.
188    void finished(GrGLuint programID);
189
190private:
191    typedef GrTAllocator<GrGLShaderVar> VarArray;
192
193    void appendDecls(const VarArray&, SkString*) const;
194    void appendUniformDecls(ShaderType, SkString*) const;
195
196    typedef GrGLUniformManager::BuilderUniform BuilderUniform;
197    GrGLUniformManager::BuilderUniformArray fUniforms;
198
199    // TODO: Everything below here private.
200public:
201
202    SkString    fHeader; // VS+FS, GLSL version, etc
203    VarArray    fVSAttrs;
204    VarArray    fVSOutputs;
205    VarArray    fGSInputs;
206    VarArray    fGSOutputs;
207    VarArray    fFSInputs;
208    SkString    fGSHeader; // layout qualifiers specific to GS
209    VarArray    fFSOutputs;
210    SkString    fVSCode;
211    SkString    fGSCode;
212    SkString    fFSCode;
213    bool        fUsesGS;
214
215private:
216    enum {
217        kNonStageIdx = -1,
218    };
219
220    const GrGLContextInfo&              fContext;
221    GrGLUniformManager&                 fUniformManager;
222    int                                 fCurrentStageIdx;
223    SkString                            fFSFunctions;
224    SkString                            fFSHeader;
225
226    bool                                fSetupFragPosition;
227    GrGLUniformManager::UniformHandle   fRTHeightUniform;
228
229    GrGLShaderVar*                      fPositionVar;
230};
231
232#endif
233