GrGLShaderBuilder.h revision ff6ea2663f76aa85ec55ddd0f00ca7906f1bc4e3
14a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project/*
24a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project * Copyright 2012 Google Inc.
34a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project *
44a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project * Use of this source code is governed by a BSD-style license that can be
54a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project * found in the LICENSE file.
64a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project */
74a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
84a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#ifndef GrGLShaderBuilder_DEFINED
94a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#define GrGLShaderBuilder_DEFINED
104a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
114a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "GrAllocator.h"
124a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "GrBackendEffectFactory.h"
134a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "GrEffect.h"
144a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "gl/GrGLSL.h"
154a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "gl/GrGLUniformManager.h"
164a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
174a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include <stdarg.h>
184a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
194a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectclass GrGLContextInfo;
204a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
214a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project/**
224a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  Contains all the incremental state of a shader as it is being built,as well as helpers to
234a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  manipulate that state.
244a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project*/
254a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectclass GrGLShaderBuilder {
264a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectpublic:
274a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    /**
284a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project     * Passed to GrGLEffects to add texture reads to their shader code.
294a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project     */
304a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    class TextureSampler {
314a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    public:
324a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project        TextureSampler()
334a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project            : fTextureAccess(NULL)
344a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project            , fSamplerUniform(GrGLUniformManager::kInvalidUniformHandle) {}
354a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
364a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project        TextureSampler(const TextureSampler& other) { *this = other; }
37
38        TextureSampler& operator= (const TextureSampler& other) {
39            GrAssert(NULL == fTextureAccess);
40            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
41
42            fTextureAccess = other.fTextureAccess;
43            fSamplerUniform = other.fSamplerUniform;
44            return *this;
45        }
46
47        const GrTextureAccess* textureAccess() const { return fTextureAccess; }
48
49    private:
50        // The idx param is used to ensure multiple samplers within a single effect have unique
51        // uniform names.
52        void init(GrGLShaderBuilder* builder, const GrTextureAccess* access, int idx) {
53            GrAssert(NULL == fTextureAccess);
54            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
55
56            GrAssert(NULL != builder);
57            GrAssert(NULL != access);
58            SkString name;
59            name.printf("Sampler%d_", idx);
60            fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
61                                                  kSampler2D_GrSLType,
62                                                  name.c_str());
63            GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform);
64
65            fTextureAccess = access;
66        }
67
68        const GrTextureAccess*            fTextureAccess;
69        GrGLUniformManager::UniformHandle fSamplerUniform;
70
71        friend class GrGLShaderBuilder; // to access fSamplerUniform
72        friend class GrGLProgram;       // to construct these and access fSamplerUniform.
73    };
74
75    typedef SkTArray<TextureSampler> TextureSamplerArray;
76
77    enum ShaderType {
78        kVertex_ShaderType   = 0x1,
79        kGeometry_ShaderType = 0x2,
80        kFragment_ShaderType = 0x4,
81    };
82
83    GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&);
84
85    /**
86     * Called by GrGLEffects to add code to one of the shaders.
87     */
88    void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
89        va_list args;
90        va_start(args, format);
91        this->codeAppendf(kVertex_ShaderType, format, args);
92        va_end(args);
93    }
94
95    void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
96        va_list args;
97        va_start(args, format);
98        this->codeAppendf(kGeometry_ShaderType, format, args);
99        va_end(args);
100    }
101
102    void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
103        va_list args;
104        va_start(args, format);
105        this->codeAppendf(kFragment_ShaderType, format, args);
106        va_end(args);
107    }
108
109    void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); }
110    void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); }
111    void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); }
112
113    /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
114        Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
115        order of the result depends on the GrTextureAccess associated with the TextureSampler. */
116    void appendTextureLookup(SkString* out,
117                             const TextureSampler&,
118                             const char* coordName,
119                             GrSLType coordType = kVec2f_GrSLType) const;
120
121    /** Version of above that appends the result to the shader code rather than an SkString.
122        Currently the shader type must be kFragment */
123    void appendTextureLookup(ShaderType,
124                             const TextureSampler&,
125                             const char* coordName,
126                             GrSLType coordType = kVec2f_GrSLType);
127
128
129    /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
130        always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
131        float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
132        called. */
133    void appendTextureLookupAndModulate(ShaderType,
134                                        const char* modulation,
135                                        const TextureSampler&,
136                                        const char* coordName,
137                                        GrSLType coordType = kVec2f_GrSLType);
138
139    /** Emits a helper function outside of main(). Currently ShaderType must be
140        kFragment_ShaderType. */
141    void emitFunction(ShaderType shader,
142                      GrSLType returnType,
143                      const char* name,
144                      int argCnt,
145                      const GrGLShaderVar* args,
146                      const char* body,
147                      SkString* outName);
148
149    /** Generates a EffectKey for the shader code based on the texture access parameters and the
150        capabilities of the GL context.  This is useful for keying the shader programs that may
151        have multiple representations, based on the type/format of textures used. */
152    static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&,
153                                                                 const GrGLCaps&);
154
155    /** If texture swizzling is available using tex parameters then it is preferred over mangling
156        the generated shader code. This potentially allows greater reuse of cached shaders. */
157    static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
158
159    /** Add a uniform variable to the current program, that has visibility in one or more shaders.
160        visibility is a bitfield of ShaderType values indicating from which shaders the uniform
161        should be accessible. At least one bit must be set. Geometry shader uniforms are not
162        supported at this time. The actual uniform name will be mangled. If outName is not NULL then
163        it will refer to the final uniform name after return. Use the addUniformArray variant to add
164        an array of uniforms.
165    */
166    GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
167                                                 GrSLType type,
168                                                 const char* name,
169                                                 const char** outName = NULL) {
170        return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
171    }
172    GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
173                                                      GrSLType type,
174                                                      const char* name,
175                                                      int arrayCount,
176                                                      const char** outName = NULL);
177
178    const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
179
180    /**
181     * Shortcut for getUniformVariable(u).c_str()
182     */
183    const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
184        return this->getUniformVariable(u).c_str();
185    }
186
187   /** Add a vertex attribute to the current program that is passed in from the vertex data.
188       Returns false if the attribute was already there, true otherwise. */
189    bool addAttribute(GrSLType type, const char* name);
190
191   /** Add a varying variable to the current program to pass values between vertex and fragment
192        shaders. If the last two parameters are non-NULL, they are filled in with the name
193        generated. */
194    void addVarying(GrSLType type,
195                    const char* name,
196                    const char** vsOutName = NULL,
197                    const char** fsInName = NULL);
198
199    /** Returns a variable name that represents the position of the fragment in the FS. The position
200        is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
201    const char* fragmentPosition();
202
203    /** Returns a vertex attribute that represents the vertex position in the VS. This is the
204        pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
205      */
206    const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
207
208    /**
209     * Interfaces used by GrGLProgram.
210     * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
211     * Also, GrGLProgram's shader string construction should be moved to this class.
212     */
213
214    /** Called after building is complete to get the final shader string. */
215    void getShader(ShaderType, SkString*) const;
216
217    void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
218    void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
219    // TODO: move remainder of shader code generation to this class and call this privately
220    // Handles of sampler uniforms generated for the effect are appended to samplerHandles.
221    GrGLEffect* createAndEmitGLEffect(
222                                const GrEffectStage& stage,
223                                GrBackendEffectFactory::EffectKey key,
224                                const char* fsInColor, // NULL means no incoming color
225                                const char* fsOutColor,
226                                const char* vsInCoord,
227                                SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
228    GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
229
230    struct AttributePair {
231        void set(int index, const SkString& name) {
232            fIndex = index; fName = name;
233        }
234        int      fIndex;
235        SkString fName;
236    };
237    const SkSTArray<10, AttributePair, true>& getEffectAttributes() const {
238        return fEffectAttributes;
239    }
240    const SkString* getEffectAttributeName(int attributeIndex) const;
241
242    // TODO: Make this do all the compiling, linking, etc.
243    void finished(GrGLuint programID);
244
245    const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
246
247private:
248    void codeAppendf(ShaderType type, const char format[], va_list args);
249    void codeAppend(ShaderType type, const char* str);
250
251    typedef GrTAllocator<GrGLShaderVar> VarArray;
252
253    void appendDecls(const VarArray&, SkString*) const;
254    void appendUniformDecls(ShaderType, SkString*) const;
255
256    typedef GrGLUniformManager::BuilderUniform BuilderUniform;
257    GrGLUniformManager::BuilderUniformArray fUniforms;
258
259    // TODO: Everything below here private.
260public:
261
262    SkString    fHeader; // VS+FS, GLSL version, etc
263    VarArray    fVSAttrs;
264    VarArray    fVSOutputs;
265    VarArray    fGSInputs;
266    VarArray    fGSOutputs;
267    VarArray    fFSInputs;
268    SkString    fGSHeader; // layout qualifiers specific to GS
269    VarArray    fFSOutputs;
270    bool        fUsesGS;
271
272private:
273    enum {
274        kNonStageIdx = -1,
275    };
276
277    const GrGLContextInfo&              fCtxInfo;
278    GrGLUniformManager&                 fUniformManager;
279    int                                 fCurrentStageIdx;
280    SkString                            fFSFunctions;
281    SkString                            fFSHeader;
282
283    SkString                            fFSCode;
284    SkString                            fVSCode;
285    SkString                            fGSCode;
286
287    bool                                fSetupFragPosition;
288    GrGLUniformManager::UniformHandle   fRTHeightUniform;
289
290    SkSTArray<10, AttributePair, true>  fEffectAttributes;
291
292    GrGLShaderVar*                      fPositionVar;
293};
294
295#endif
296