GrGLShaderBuilder.h revision a05fa0669bac20e521ac3c1905fe8391fd659e60
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 "SkTypes.h"
16#include "gl/GrGLProgramEffects.h"
17#include "gl/GrGLSL.h"
18#include "gl/GrGLUniformManager.h"
19
20#include <stdarg.h>
21
22class GrGLContextInfo;
23class GrEffectStage;
24class GrGLProgramDesc;
25
26/**
27  Contains all the incremental state of a shader as it is being built,as well as helpers to
28  manipulate that state.
29*/
30class GrGLShaderBuilder {
31public:
32    typedef GrTAllocator<GrGLShaderVar> VarArray;
33    typedef GrBackendEffectFactory::EffectKey EffectKey;
34    typedef GrGLProgramEffects::TextureSampler TextureSampler;
35    typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray;
36    typedef GrGLUniformManager::BuilderUniform BuilderUniform;
37
38    enum ShaderVisibility {
39        kVertex_Visibility   = 0x1,
40        kGeometry_Visibility = 0x2,
41        kFragment_Visibility = 0x4,
42    };
43
44    typedef GrGLUniformManager::UniformHandle UniformHandle;
45
46    // Handles for program uniforms (other than per-effect uniforms)
47    struct UniformHandles {
48        UniformHandle       fViewMatrixUni;
49        UniformHandle       fRTAdjustmentUni;
50        UniformHandle       fColorUni;
51        UniformHandle       fCoverageUni;
52
53        // We use the render target height to provide a y-down frag coord when specifying
54        // origin_upper_left is not supported.
55        UniformHandle       fRTHeightUni;
56
57        // Uniforms for computing texture coords to do the dst-copy lookup
58        UniformHandle       fDstCopyTopLeftUni;
59        UniformHandle       fDstCopyScaleUni;
60        UniformHandle       fDstCopySamplerUni;
61    };
62
63    struct GenProgramOutput {
64        GenProgramOutput()
65            : fColorEffects(NULL)
66            , fCoverageEffects(NULL)
67            , fHasVertexShader(false)
68            , fTexCoordSetCnt(0)
69            , fProgramID(0) {}
70
71        GenProgramOutput(const GenProgramOutput& other) {
72            *this = other;
73        }
74
75        GenProgramOutput& operator=(const GenProgramOutput& other) {
76            fColorEffects.reset(SkRef(other.fColorEffects.get()));
77            fCoverageEffects.reset(SkRef(other.fCoverageEffects.get()));
78            fUniformHandles = other.fUniformHandles;
79            fHasVertexShader = other.fHasVertexShader;
80            fTexCoordSetCnt = other.fTexCoordSetCnt;
81            fProgramID = other.fProgramID;
82            return *this;
83        }
84
85        SkAutoTUnref<GrGLProgramEffects> fColorEffects;
86        SkAutoTUnref<GrGLProgramEffects> fCoverageEffects;
87        UniformHandles                   fUniformHandles;
88        bool                             fHasVertexShader;
89        int                              fTexCoordSetCnt;
90        GrGLuint                         fProgramID;
91    };
92
93    static bool GenProgram(GrGpuGL* gpu,
94                           GrGLUniformManager* uman,
95                           const GrGLProgramDesc& desc,
96                           const GrEffectStage* inColorStages[],
97                           const GrEffectStage* inCoverageStages[],
98                           GenProgramOutput* output);
99
100    virtual ~GrGLShaderBuilder() {}
101
102    /**
103     * Use of these features may require a GLSL extension to be enabled. Shaders may not compile
104     * if code is added that uses one of these features without calling enableFeature()
105     */
106    enum GLSLFeature {
107        kStandardDerivatives_GLSLFeature = 0,
108
109        kLastGLSLFeature = kStandardDerivatives_GLSLFeature
110    };
111
112    /**
113     * If the feature is supported then true is returned and any necessary #extension declarations
114     * are added to the shaders. If the feature is not supported then false will be returned.
115     */
116    bool enableFeature(GLSLFeature);
117
118    /**
119     * Called by GrGLEffects to add code the fragment shader.
120     */
121    void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
122        va_list args;
123        va_start(args, format);
124        fFSCode.appendVAList(format, args);
125        va_end(args);
126    }
127
128    void fsCodeAppend(const char* str) { fFSCode.append(str); }
129
130    /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
131        Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
132        order of the result depends on the GrTextureAccess associated with the TextureSampler. */
133    void appendTextureLookup(SkString* out,
134                             const TextureSampler&,
135                             const char* coordName,
136                             GrSLType coordType = kVec2f_GrSLType) const;
137
138    /** Version of above that appends the result to the fragment shader code instead.*/
139    void fsAppendTextureLookup(const TextureSampler&,
140                               const char* coordName,
141                               GrSLType coordType = kVec2f_GrSLType);
142
143
144    /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
145        always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
146        float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
147        called. */
148    void fsAppendTextureLookupAndModulate(const char* modulation,
149                                          const TextureSampler&,
150                                          const char* coordName,
151                                          GrSLType coordType = kVec2f_GrSLType);
152
153    /** Emits a helper function outside of main() in the fragment shader. */
154    void fsEmitFunction(GrSLType returnType,
155                        const char* name,
156                        int argCnt,
157                        const GrGLShaderVar* args,
158                        const char* body,
159                        SkString* outName);
160
161    typedef uint8_t DstReadKey;
162    typedef uint8_t FragPosKey;
163
164    /**  Returns a key for adding code to read the copy-of-dst color in service of effects that
165         require reading the dst. It must not return 0 because 0 indicates that there is no dst
166         copy read at all (in which case this function should not be called). */
167    static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&);
168
169    /** Returns a key for reading the fragment location. This should only be called if there is an
170        effect that will requires the fragment position. If the fragment position is not required,
171        the key is 0. */
172    static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&);
173
174    /** If texture swizzling is available using tex parameters then it is preferred over mangling
175        the generated shader code. This potentially allows greater reuse of cached shaders. */
176    static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
177
178    /** Add a uniform variable to the current program, that has visibility in one or more shaders.
179        visibility is a bitfield of ShaderVisibility values indicating from which shaders the
180        uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not
181        supported at this time. The actual uniform name will be mangled. If outName is not NULL then
182        it will refer to the final uniform name after return. Use the addUniformArray variant to add
183        an array of uniforms. */
184    GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
185                                                 GrSLType type,
186                                                 const char* name,
187                                                 const char** outName = NULL) {
188        return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
189    }
190    GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
191                                                      GrSLType type,
192                                                      const char* name,
193                                                      int arrayCount,
194                                                      const char** outName = NULL);
195
196    const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle u) const {
197        return fUniformManager->getBuilderUniform(fUniforms, u).fVariable;
198    }
199
200    /**
201     * Shortcut for getUniformVariable(u).c_str()
202     */
203    const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
204        return this->getUniformVariable(u).c_str();
205    }
206
207    /**
208     * This returns a variable name to access the 2D, perspective correct version of the coords in
209     * the fragment shader. If the coordinates at index are 3-dimensional, it immediately emits a
210     * perspective divide into the fragment shader (xy / z) to convert them to 2D.
211     */
212    SkString ensureFSCoords2D(const TransformedCoordsArray&, int index);
213
214    /** Returns a variable name that represents the position of the fragment in the FS. The position
215        is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
216    const char* fragmentPosition();
217
218    /** Returns the variable name that holds the color of the destination pixel. This may be NULL if
219        no effect advertised that it will read the destination. */
220    const char* dstColor();
221
222    const GrGLContextInfo& ctxInfo() const;
223
224    /**
225     * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder
226     * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that
227     * our shaders print pretty without effect writers tracking indentation.
228     */
229    class FSBlock {
230    public:
231        FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) {
232            SkASSERT(NULL != builder);
233            fBuilder->fsCodeAppend("\t{\n");
234        }
235
236        ~FSBlock() {
237            fBuilder->fsCodeAppend("\t}\n");
238        }
239    private:
240        GrGLShaderBuilder* fBuilder;
241    };
242
243protected:
244    GrGLShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
245
246    GrGpuGL* gpu() const { return fGpu; }
247
248    const GrGLProgramDesc& desc() const { return fDesc; }
249
250    /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */
251    GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); }
252
253    // Helper for emitEffects().
254    void createAndEmitEffects(GrGLProgramEffectsBuilder*,
255                              const GrEffectStage* effectStages[],
256                              const EffectKey effectKeys[],
257                              int effectCnt,
258                              GrGLSLExpr4* inOutFSColor);
259
260    // Generates a name for a variable. The generated string will be name prefixed by the prefix
261    // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
262    // generating stage code.
263    void nameVariable(SkString* out, char prefix, const char* name);
264
265    virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
266
267    virtual void bindProgramLocations(GrGLuint programId) const;
268
269    void appendDecls(const VarArray&, SkString*) const;
270    void appendUniformDecls(ShaderVisibility, SkString*) const;
271
272    const GenProgramOutput& getOutput() const { return fOutput; }
273
274    GenProgramOutput fOutput;
275
276private:
277    class CodeStage : SkNoncopyable {
278    public:
279        CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
280
281        bool inStageCode() const {
282            this->validate();
283            return NULL != fEffectStage;
284        }
285
286        const GrEffectStage* effectStage() const {
287            this->validate();
288            return fEffectStage;
289        }
290
291        int stageIndex() const {
292            this->validate();
293            return fCurrentIndex;
294        }
295
296        class AutoStageRestore : SkNoncopyable {
297        public:
298            AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
299                SkASSERT(NULL != codeStage);
300                fSavedIndex = codeStage->fCurrentIndex;
301                fSavedEffectStage = codeStage->fEffectStage;
302
303                if (NULL == newStage) {
304                    codeStage->fCurrentIndex = -1;
305                } else {
306                    codeStage->fCurrentIndex = codeStage->fNextIndex++;
307                }
308                codeStage->fEffectStage = newStage;
309
310                fCodeStage = codeStage;
311            }
312            ~AutoStageRestore() {
313                fCodeStage->fCurrentIndex = fSavedIndex;
314                fCodeStage->fEffectStage = fSavedEffectStage;
315            }
316        private:
317            CodeStage*              fCodeStage;
318            int                     fSavedIndex;
319            const GrEffectStage*    fSavedEffectStage;
320        };
321    private:
322        void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
323        int                     fNextIndex;
324        int                     fCurrentIndex;
325        const GrEffectStage*    fEffectStage;
326    } fCodeStage;
327
328    bool genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]);
329
330    /**
331     * The base class will emit the fragment code that precedes the per-effect code and then call
332     * this function. The subclass can use it to insert additional fragment code that should
333     * execute before the effects' code and/or emit other shaders (e.g. geometry, vertex).
334     *
335     * The subclass can modify the initial color or coverage
336     */
337    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) = 0;
338
339    /**
340    * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
341    * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key
342    * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and
343    * is updated to be the output color of the last stage.
344    * The handles to texture samplers for effectStage[i] are added to
345    * effectSamplerHandles[i].
346    */
347    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
348                                                     const EffectKey effectKeys[],
349                                                     int effectCnt,
350                                                     GrGLSLExpr4* inOutFSColor) = 0;
351
352    /**
353     * Similar to emitCodeBeforeEffects() but called after per-effect code is emitted.
354     */
355    virtual void emitCodeAfterEffects() = 0;
356
357    /** Enables using the secondary color output and returns the name of the var in which it is
358        to be stored */
359    const char* enableSecondaryOutput();
360    /** Gets the name of the primary color output. */
361    const char* getColorOutputName() const;
362
363    /**
364     * Compiles all the shaders, links them into a program, and writes the program id to the output
365     * struct.
366     **/
367    bool finish();
368
369    /**
370     * Features that should only be enabled by GrGLShaderBuilder itself.
371     */
372    enum GLSLPrivateFeature {
373        kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
374        kEXTShaderFramebufferFetch_GLSLPrivateFeature,
375        kNVShaderFramebufferFetch_GLSLPrivateFeature,
376    };
377    bool enablePrivateFeature(GLSLPrivateFeature);
378
379    // If we ever have VS/GS features we can expand this to take a bitmask of ShaderVisibility and
380    // track the enables separately for each shader.
381    void addFSFeature(uint32_t featureBit, const char* extensionName);
382
383    // Interpretation of DstReadKey when generating code
384    enum {
385        kNoDstRead_DstReadKey           = 0,
386        kYesDstRead_DstReadKeyBit       = 0x1, // Set if we do a dst-copy-read.
387        kUseAlphaConfig_DstReadKeyBit   = 0x2, // Set if dst-copy config is alpha only.
388        kTopLeftOrigin_DstReadKeyBit    = 0x4, // Set if dst-copy origin is top-left.
389    };
390
391    enum {
392        kNoFragPosRead_FragPosKey           = 0,  // The fragment positition will not be needed.
393        kTopLeftFragPosRead_FragPosKey      = 0x1,// Read frag pos relative to top-left.
394        kBottomLeftFragPosRead_FragPosKey   = 0x2,// Read frag pos relative to bottom-left.
395    };
396
397    const GrGLProgramDesc&                  fDesc;
398    GrGpuGL*                                fGpu;
399    SkAutoTUnref<GrGLUniformManager>        fUniformManager;
400    uint32_t                                fFSFeaturesAddedMask;
401    SkString                                fFSFunctions;
402    SkString                                fFSExtensions;
403    VarArray                                fFSInputs;
404    VarArray                                fFSOutputs;
405    GrGLUniformManager::BuilderUniformArray fUniforms;
406
407    SkString                                fFSCode;
408
409    bool                                    fSetupFragPosition;
410    bool                                    fTopLeftFragPosRead;
411
412    bool                                    fHasCustomColorOutput;
413    bool                                    fHasSecondaryOutput;
414};
415
416////////////////////////////////////////////////////////////////////////////////
417
418class GrGLFullShaderBuilder : public GrGLShaderBuilder {
419public:
420    GrGLFullShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
421
422    /**
423     * Called by GrGLEffects to add code to one of the shaders.
424     */
425    void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
426        va_list args;
427        va_start(args, format);
428        fVSCode.appendVAList(format, args);
429        va_end(args);
430    }
431
432    void vsCodeAppend(const char* str) { fVSCode.append(str); }
433
434   /** Add a vertex attribute to the current program that is passed in from the vertex data.
435       Returns false if the attribute was already there, true otherwise. */
436    bool addAttribute(GrSLType type, const char* name);
437
438   /** Add a varying variable to the current program to pass values between vertex and fragment
439        shaders. If the last two parameters are non-NULL, they are filled in with the name
440        generated. */
441    void addVarying(GrSLType type,
442                    const char* name,
443                    const char** vsOutName = NULL,
444                    const char** fsInName = NULL);
445
446    /** Returns a vertex attribute that represents the vertex position in the VS. This is the
447        pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
448      */
449    const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
450
451    /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
452        as positionAttribute() or it may not be. It depends upon whether the rendering code
453        specified explicit local coords or not in the GrDrawState. */
454    const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
455
456    /**
457     * Are explicit local coordinates provided as input to the vertex shader.
458     */
459    bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
460
461    bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
462    const SkString* getEffectAttributeName(int attributeIndex) const;
463
464private:
465    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE;
466
467    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
468                                                     const EffectKey effectKeys[],
469                                                     int effectCnt,
470                                                     GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
471
472    virtual void emitCodeAfterEffects() SK_OVERRIDE;
473
474    virtual bool compileAndAttachShaders(GrGLuint programId,
475                                         SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE;
476
477    virtual void bindProgramLocations(GrGLuint programId) const SK_OVERRIDE;
478
479    VarArray                            fVSAttrs;
480    VarArray                            fVSOutputs;
481    VarArray                            fGSInputs;
482    VarArray                            fGSOutputs;
483
484    SkString                            fVSCode;
485
486    struct AttributePair {
487        void set(int index, const SkString& name) {
488            fIndex = index; fName = name;
489        }
490        int      fIndex;
491        SkString fName;
492    };
493    SkSTArray<10, AttributePair, true>  fEffectAttributes;
494
495    GrGLShaderVar*                      fPositionVar;
496    GrGLShaderVar*                      fLocalCoordsVar;
497
498    typedef GrGLShaderBuilder INHERITED;
499};
500
501////////////////////////////////////////////////////////////////////////////////
502
503class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder {
504public:
505    GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
506
507    int addTexCoordSets(int count);
508
509private:
510    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {}
511
512    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
513                                                     const EffectKey effectKeys[],
514                                                     int effectCnt,
515                                                     GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
516
517    virtual void emitCodeAfterEffects() SK_OVERRIDE {}
518
519    typedef GrGLShaderBuilder INHERITED;
520};
521
522#endif
523