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 "gl/GrGLSL.h"
     16 #include "gl/GrGLUniformManager.h"
     17 
     18 #include <stdarg.h>
     19 
     20 class GrGLContextInfo;
     21 class GrEffectStage;
     22 class 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 */
     28 class GrGLShaderBuilder {
     29 public:
     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      * Use of these features may require a GLSL extension to be enabled. Shaders may not compile
    111      * if code is added that uses one of these features without calling enableFeature()
    112      */
    113     enum GLSLFeature {
    114         kStandardDerivatives_GLSLFeature = 0,
    115 
    116         kLastGLSLFeature = kStandardDerivatives_GLSLFeature
    117     };
    118 
    119     /**
    120      * If the feature is supported then true is returned and any necessary #extension declarations
    121      * are added to the shaders. If the feature is not supported then false will be returned.
    122      */
    123     bool enableFeature(GLSLFeature);
    124 
    125     /**
    126      * Called by GrGLEffects to add code to one of the shaders.
    127      */
    128     void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
    129         va_list args;
    130         va_start(args, format);
    131         this->codeAppendf(kVertex_ShaderType, format, args);
    132         va_end(args);
    133     }
    134 
    135     void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
    136         va_list args;
    137         va_start(args, format);
    138         this->codeAppendf(kGeometry_ShaderType, format, args);
    139         va_end(args);
    140     }
    141 
    142     void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
    143         va_list args;
    144         va_start(args, format);
    145         this->codeAppendf(kFragment_ShaderType, format, args);
    146         va_end(args);
    147     }
    148 
    149     void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); }
    150     void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); }
    151     void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); }
    152 
    153     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
    154         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
    155         order of the result depends on the GrTextureAccess associated with the TextureSampler. */
    156     void appendTextureLookup(SkString* out,
    157                              const TextureSampler&,
    158                              const char* coordName,
    159                              GrSLType coordType = kVec2f_GrSLType) const;
    160 
    161     /** Version of above that appends the result to the shader code rather than an SkString.
    162         Currently the shader type must be kFragment */
    163     void appendTextureLookup(ShaderType,
    164                              const TextureSampler&,
    165                              const char* coordName,
    166                              GrSLType coordType = kVec2f_GrSLType);
    167 
    168 
    169     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
    170         always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
    171         float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
    172         called. */
    173     void appendTextureLookupAndModulate(ShaderType,
    174                                         const char* modulation,
    175                                         const TextureSampler&,
    176                                         const char* coordName,
    177                                         GrSLType coordType = kVec2f_GrSLType);
    178 
    179     /** Emits a helper function outside of main(). Currently ShaderType must be
    180         kFragment_ShaderType. */
    181     void emitFunction(ShaderType shader,
    182                       GrSLType returnType,
    183                       const char* name,
    184                       int argCnt,
    185                       const GrGLShaderVar* args,
    186                       const char* body,
    187                       SkString* outName);
    188 
    189     /** Generates a EffectKey for the shader code based on the texture access parameters and the
    190         capabilities of the GL context.  This is useful for keying the shader programs that may
    191         have multiple representations, based on the type/format of textures used. */
    192     static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&,
    193                                                                  const GrGLCaps&);
    194 
    195     typedef uint8_t DstReadKey;
    196     typedef uint8_t FragPosKey;
    197 
    198     /**  Returns a key for adding code to read the copy-of-dst color in service of effects that
    199          require reading the dst. It must not return 0 because 0 indicates that there is no dst
    200          copy read at all (in which case this function should not be called). */
    201     static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&);
    202 
    203     /** Returns a key for reading the fragment location. This should only be called if there is an
    204         effect that will requires the fragment position. If the fragment position is not required,
    205         the key is 0. */
    206     static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&);
    207 
    208     /** If texture swizzling is available using tex parameters then it is preferred over mangling
    209         the generated shader code. This potentially allows greater reuse of cached shaders. */
    210     static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
    211 
    212     /** Add a uniform variable to the current program, that has visibility in one or more shaders.
    213         visibility is a bitfield of ShaderType values indicating from which shaders the uniform
    214         should be accessible. At least one bit must be set. Geometry shader uniforms are not
    215         supported at this time. The actual uniform name will be mangled. If outName is not NULL then
    216         it will refer to the final uniform name after return. Use the addUniformArray variant to add
    217         an array of uniforms.
    218     */
    219     GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
    220                                                  GrSLType type,
    221                                                  const char* name,
    222                                                  const char** outName = NULL) {
    223         return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
    224     }
    225     GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
    226                                                       GrSLType type,
    227                                                       const char* name,
    228                                                       int arrayCount,
    229                                                       const char** outName = NULL);
    230 
    231     const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
    232 
    233     /**
    234      * Shortcut for getUniformVariable(u).c_str()
    235      */
    236     const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
    237         return this->getUniformVariable(u).c_str();
    238     }
    239 
    240    /** Add a vertex attribute to the current program that is passed in from the vertex data.
    241        Returns false if the attribute was already there, true otherwise. */
    242     bool addAttribute(GrSLType type, const char* name);
    243 
    244    /** Add a varying variable to the current program to pass values between vertex and fragment
    245         shaders. If the last two parameters are non-NULL, they are filled in with the name
    246         generated. */
    247     void addVarying(GrSLType type,
    248                     const char* name,
    249                     const char** vsOutName = NULL,
    250                     const char** fsInName = NULL);
    251 
    252     /** Returns a variable name that represents the position of the fragment in the FS. The position
    253         is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
    254     const char* fragmentPosition();
    255 
    256     /** Returns a vertex attribute that represents the vertex position in the VS. This is the
    257         pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
    258       */
    259     const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
    260 
    261     /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
    262         as positionAttribute() or it may not be. It depends upon whether the rendering code
    263         specified explicit local coords or not in the GrDrawState. */
    264     const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
    265 
    266     /** Returns the color of the destination pixel. This may be NULL if no effect advertised
    267         that it will read the destination. */
    268     const char* dstColor();
    269 
    270     /**
    271      * Are explicit local coordinates provided as input to the vertex shader.
    272      */
    273     bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
    274 
    275     /**
    276      * Interfaces used by GrGLProgram.
    277      * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
    278      * Also, GrGLProgram's shader string construction should be moved to this class.
    279      */
    280 
    281     /** Called after building is complete to get the final shader string. */
    282     void getShader(ShaderType, SkString*) const;
    283 
    284     /**
    285      * Adds code for effects. effectStages contains the effects to add. effectKeys[i] is the key
    286      * generated from effectStages[i]. An entry in effectStages can be NULL, in which case it is
    287      * skipped. Moreover, if the corresponding key is GrGLEffect::NoEffectKey then it is skipped.
    288      * inOutFSColor specifies the input color to the first stage and is updated to be the
    289      * output color of the last stage. fsInOutColorKnownValue specifies whether the input color
    290      * has a known constant value and is updated to refer to the status of the output color.
    291      * The handles to texture samplers for effectStage[i] are added to effectSamplerHandles[i]. The
    292      * glEffects array is updated to contain the GrGLEffect generated for each entry in
    293      * effectStages.
    294      */
    295     void emitEffects(const GrEffectStage* effectStages[],
    296                      const GrBackendEffectFactory::EffectKey effectKeys[],
    297                      int effectCnt,
    298                      SkString*  inOutFSColor,
    299                      GrSLConstantVec* fsInOutColorKnownValue,
    300                      SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[],
    301                      GrGLEffect* glEffects[]);
    302 
    303     GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
    304     GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const {
    305         return fDstCopyTopLeftUniform;
    306     }
    307     GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const {
    308         return fDstCopyScaleUniform;
    309     }
    310     GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const {
    311         return fDstCopySampler.fSamplerUniform;
    312     }
    313 
    314     struct AttributePair {
    315         void set(int index, const SkString& name) {
    316             fIndex = index; fName = name;
    317         }
    318         int      fIndex;
    319         SkString fName;
    320     };
    321     const SkTArray<AttributePair, true>& getEffectAttributes() const {
    322         return fEffectAttributes;
    323     }
    324     const SkString* getEffectAttributeName(int attributeIndex) const;
    325 
    326     // TODO: Make this do all the compiling, linking, etc.
    327     void finished(GrGLuint programID);
    328 
    329     const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
    330 
    331 private:
    332     void codeAppendf(ShaderType type, const char format[], va_list args);
    333     void codeAppend(ShaderType type, const char* str);
    334 
    335     typedef GrTAllocator<GrGLShaderVar> VarArray;
    336 
    337     void appendDecls(const VarArray&, SkString*) const;
    338     void appendUniformDecls(ShaderType, SkString*) const;
    339 
    340     typedef GrGLUniformManager::BuilderUniform BuilderUniform;
    341     GrGLUniformManager::BuilderUniformArray fUniforms;
    342 
    343     // TODO: Everything below here private.
    344 public:
    345 
    346     VarArray    fVSAttrs;
    347     VarArray    fVSOutputs;
    348     VarArray    fGSInputs;
    349     VarArray    fGSOutputs;
    350     VarArray    fFSInputs;
    351     SkString    fGSHeader; // layout qualifiers specific to GS
    352     VarArray    fFSOutputs;
    353 
    354 private:
    355     class CodeStage : GrNoncopyable {
    356     public:
    357         CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
    358 
    359         bool inStageCode() const {
    360             this->validate();
    361             return NULL != fEffectStage;
    362         }
    363 
    364         const GrEffectStage* effectStage() const {
    365             this->validate();
    366             return fEffectStage;
    367         }
    368 
    369         int stageIndex() const {
    370             this->validate();
    371             return fCurrentIndex;
    372         }
    373 
    374         class AutoStageRestore : GrNoncopyable {
    375         public:
    376             AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
    377                 GrAssert(NULL != codeStage);
    378                 fSavedIndex = codeStage->fCurrentIndex;
    379                 fSavedEffectStage = codeStage->fEffectStage;
    380 
    381                 if (NULL == newStage) {
    382                     codeStage->fCurrentIndex = -1;
    383                 } else {
    384                     codeStage->fCurrentIndex = codeStage->fNextIndex++;
    385                 }
    386                 codeStage->fEffectStage = newStage;
    387 
    388                 fCodeStage = codeStage;
    389             }
    390             ~AutoStageRestore() {
    391                 fCodeStage->fCurrentIndex = fSavedIndex;
    392                 fCodeStage->fEffectStage = fSavedEffectStage;
    393             }
    394         private:
    395             CodeStage*              fCodeStage;
    396             int                     fSavedIndex;
    397             const GrEffectStage*    fSavedEffectStage;
    398         };
    399     private:
    400         void validate() const { GrAssert((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
    401         int                     fNextIndex;
    402         int                     fCurrentIndex;
    403         const GrEffectStage*    fEffectStage;
    404     } fCodeStage;
    405 
    406     /**
    407      * Features that should only be enabled by GrGLShaderBuilder itself.
    408      */
    409     enum GLSLPrivateFeature {
    410         kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
    411         kEXTShaderFramebufferFetch_GLSLPrivateFeature,
    412         kNVShaderFramebufferFetch_GLSLPrivateFeature,
    413     };
    414     bool enablePrivateFeature(GLSLPrivateFeature);
    415 
    416     // If we ever have VS/GS features we can expand this to take a bitmask of ShaderType and track
    417     // the enables separately for each shader.
    418     void addFSFeature(uint32_t featureBit, const char* extensionName);
    419 
    420     // Generates a name for a variable. The generated string will be name prefixed by the prefix
    421     // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
    422     // generating stage code.
    423     void nameVariable(SkString* out, char prefix, const char* name);
    424 
    425     // Interpretation of DstReadKey when generating code
    426     enum {
    427         kNoDstRead_DstReadKey         = 0,
    428         kYesDstRead_DstReadKeyBit     = 0x1, // Set if we do a dst-copy-read.
    429         kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only.
    430         kTopLeftOrigin_DstReadKeyBit  = 0x4, // Set if dst-copy origin is top-left.
    431     };
    432 
    433     enum {
    434         kNoFragPosRead_FragPosKey           = 0,  // The fragment positition will not be needed.
    435         kTopLeftFragPosRead_FragPosKey      = 0x1,// Read frag pos relative to top-left.
    436         kBottomLeftFragPosRead_FragPosKey   = 0x2,// Read frag pos relative to bottom-left.
    437     };
    438 
    439     const GrGLContextInfo&              fCtxInfo;
    440     GrGLUniformManager&                 fUniformManager;
    441     uint32_t                            fFSFeaturesAddedMask;
    442     SkString                            fFSFunctions;
    443     SkString                            fFSExtensions;
    444 
    445     bool                                fUsesGS;
    446 
    447     SkString                            fFSCode;
    448     SkString                            fVSCode;
    449     SkString                            fGSCode;
    450 
    451     bool                                fSetupFragPosition;
    452     TextureSampler                      fDstCopySampler;
    453 
    454     GrGLUniformManager::UniformHandle   fRTHeightUniform;
    455     GrGLUniformManager::UniformHandle   fDstCopyTopLeftUniform;
    456     GrGLUniformManager::UniformHandle   fDstCopyScaleUniform;
    457 
    458     bool                                fTopLeftFragPosRead;
    459 
    460     SkSTArray<10, AttributePair, true>  fEffectAttributes;
    461 
    462     GrGLShaderVar*                      fPositionVar;
    463     GrGLShaderVar*                      fLocalCoordsVar;
    464 
    465 };
    466 
    467 #endif
    468