Home | History | Annotate | Download | only in gl
      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 
     22 class GrGLContextInfo;
     23 class GrEffectStage;
     24 class 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 */
     30 class GrGLShaderBuilder {
     31 public:
     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 
    243 protected:
    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 
    276 private:
    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 
    418 class GrGLFullShaderBuilder : public GrGLShaderBuilder {
    419 public:
    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 
    464 private:
    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 
    503 class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder {
    504 public:
    505     GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
    506 
    507     int addTexCoordSets(int count);
    508 
    509 private:
    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