Home | History | Annotate | Download | only in glsl
      1 /*
      2  * Copyright 2014 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 GrGLSLShaderBuilder_DEFINED
      9 #define GrGLSLShaderBuilder_DEFINED
     10 
     11 #include "GrAllocator.h"
     12 #include "glsl/GrGLSLShaderVar.h"
     13 #include "SkTDArray.h"
     14 
     15 #include <stdarg.h>
     16 
     17 class GrGLSLProgramBuilder;
     18 class GrGLSLTextureSampler;
     19 
     20 /**
     21   base class for all shaders builders
     22 */
     23 class GrGLSLShaderBuilder {
     24 public:
     25     GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
     26     virtual ~GrGLSLShaderBuilder() {}
     27 
     28     /*
     29      * We put texture lookups in the base class because it is TECHNICALLY possible to do texture
     30      * lookups in any kind of shader.  However, for the time being using these calls on non-fragment
     31      * shaders will result in a shader compilation error as texture sampler uniforms are only
     32      * visible to the fragment shader.  It would not be hard to change this behavior, if someone
     33      * actually wants to do texture lookups in a non-fragment shader
     34      *
     35      * TODO if append texture lookup is used on a non-fragment shader, sampler uniforms should be
     36      * made visible to that shaders
     37      */
     38     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
     39         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
     40         order of the result depends on the GrTextureAccess associated with the GrGLSLTextureSampler.
     41         */
     42     void appendTextureLookup(SkString* out,
     43                              const GrGLSLTextureSampler&,
     44                              const char* coordName,
     45                              GrSLType coordType = kVec2f_GrSLType) const;
     46 
     47     /** Version of above that appends the result to the fragment shader code instead.*/
     48     void appendTextureLookup(const GrGLSLTextureSampler&,
     49                              const char* coordName,
     50                              GrSLType coordType = kVec2f_GrSLType);
     51 
     52 
     53     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
     54         always a vec4. modulation and the swizzle specified by GrGLSLTextureSampler must both be
     55         vec4 or float. If modulation is "" or nullptr it this function acts as though
     56         appendTextureLookup were called. */
     57     void appendTextureLookupAndModulate(const char* modulation,
     58                                         const GrGLSLTextureSampler&,
     59                                         const char* coordName,
     60                                         GrSLType coordType = kVec2f_GrSLType);
     61 
     62     /**
     63     * Adds a #define directive to the top of the shader.
     64     */
     65     void define(const char* macro, const char* replacement) {
     66         this->definitions().appendf("#define %s %s\n", macro, replacement);
     67     }
     68 
     69     void define(const char* macro, int replacement) {
     70         this->definitions().appendf("#define %s %i\n", macro, replacement);
     71     }
     72 
     73     void definef(const char* macro, const char* replacement, ...) {
     74        this->definitions().appendf("#define %s ", macro);
     75        va_list args;
     76        va_start(args, replacement);
     77        this->definitions().appendVAList(replacement, args);
     78        va_end(args);
     79        this->definitions().append("\n");
     80     }
     81 
     82     /**
     83     * Called by GrGLSLProcessors to add code to one of the shaders.
     84     */
     85     void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
     86        va_list args;
     87        va_start(args, format);
     88        this->code().appendVAList(format, args);
     89        va_end(args);
     90     }
     91 
     92     void codeAppend(const char* str) { this->code().append(str); }
     93 
     94     void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
     95        va_list args;
     96        va_start(args, format);
     97        this->code().prependVAList(format, args);
     98        va_end(args);
     99     }
    100 
    101     /**
    102      * Appends a variable declaration to one of the shaders
    103      */
    104     void declAppend(const GrGLSLShaderVar& var);
    105 
    106     /** Emits a helper function outside of main() in the fragment shader. */
    107     void emitFunction(GrSLType returnType,
    108                       const char* name,
    109                       int argCnt,
    110                       const GrGLSLShaderVar* args,
    111                       const char* body,
    112                       SkString* outName);
    113 
    114     /*
    115      * Combines the various parts of the shader to create a single finalized shader string.
    116      */
    117     void finalize(uint32_t visibility);
    118 
    119     /*
    120      * Get parent builder for adding uniforms
    121      */
    122     GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
    123 
    124     /**
    125      * Helper for begining and ending a block in the shader code.
    126      */
    127     class ShaderBlock {
    128     public:
    129         ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
    130             SkASSERT(builder);
    131             fBuilder->codeAppend("{");
    132         }
    133 
    134         ~ShaderBlock() {
    135             fBuilder->codeAppend("}");
    136         }
    137     private:
    138         GrGLSLShaderBuilder* fBuilder;
    139     };
    140 
    141 protected:
    142     typedef GrTAllocator<GrGLSLShaderVar> VarArray;
    143     void appendDecls(const VarArray& vars, SkString* out) const;
    144 
    145     /**
    146      * Features that should only be enabled internally by the builders.
    147      */
    148     enum GLSLPrivateFeature {
    149         kFragCoordConventions_GLSLPrivateFeature,
    150         kBlendEquationAdvanced_GLSLPrivateFeature,
    151         kBlendFuncExtended_GLSLPrivateFeature,
    152         kExternalTexture_GLSLPrivateFeature,
    153         kFramebufferFetch_GLSLPrivateFeature,
    154         kNoPerspectiveInterpolation_GLSLPrivateFeature,
    155         kSampleVariables_GLSLPrivateFeature,
    156         kSampleMaskOverrideCoverage_GLSLPrivateFeature,
    157         kLastGLSLPrivateFeature = kSampleMaskOverrideCoverage_GLSLPrivateFeature
    158     };
    159 
    160     /*
    161      * A general function which enables an extension in a shader if the feature bit is not present
    162      *
    163      * @return true if the feature bit was not yet present, false otherwise.
    164      */
    165     bool addFeature(uint32_t featureBit, const char* extensionName);
    166 
    167     enum InterfaceQualifier {
    168         kOut_InterfaceQualifier,
    169         kLastInterfaceQualifier = kOut_InterfaceQualifier
    170     };
    171 
    172     /*
    173      * A low level function to build default layout qualifiers.
    174      *
    175      *   e.g. layout(param1, param2, ...) out;
    176      *
    177      * GLSL allows default layout qualifiers for in, out, and uniform.
    178      */
    179     void addLayoutQualifier(const char* param, InterfaceQualifier);
    180 
    181     void compileAndAppendLayoutQualifiers();
    182 
    183     void nextStage() {
    184         fShaderStrings.push_back();
    185         fCompilerStrings.push_back(this->code().c_str());
    186         fCompilerStringLengths.push_back((int)this->code().size());
    187         fCodeIndex++;
    188     }
    189 
    190     SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
    191     SkString& extensions() { return fShaderStrings[kExtensions]; }
    192     SkString& definitions() { return fShaderStrings[kDefinitions]; }
    193     SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
    194     SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
    195     SkString& uniforms() { return fShaderStrings[kUniforms]; }
    196     SkString& inputs() { return fShaderStrings[kInputs]; }
    197     SkString& outputs() { return fShaderStrings[kOutputs]; }
    198     SkString& functions() { return fShaderStrings[kFunctions]; }
    199     SkString& main() { return fShaderStrings[kMain]; }
    200     SkString& code() { return fShaderStrings[fCodeIndex]; }
    201 
    202     virtual void onFinalize() = 0;
    203 
    204     enum {
    205         kVersionDecl,
    206         kExtensions,
    207         kDefinitions,
    208         kPrecisionQualifier,
    209         kLayoutQualifiers,
    210         kUniforms,
    211         kInputs,
    212         kOutputs,
    213         kFunctions,
    214         kMain,
    215         kCode,
    216     };
    217 
    218     GrGLSLProgramBuilder* fProgramBuilder;
    219     SkSTArray<kCode, const char*, true> fCompilerStrings;
    220     SkSTArray<kCode, int, true> fCompilerStringLengths;
    221     SkSTArray<kCode, SkString> fShaderStrings;
    222     SkString fCode;
    223     SkString fFunctions;
    224     SkString fExtensions;
    225 
    226     VarArray fInputs;
    227     VarArray fOutputs;
    228     uint32_t fFeaturesAddedMask;
    229     SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
    230     int fCodeIndex;
    231     bool fFinalized;
    232 
    233     friend class GrGLSLProgramBuilder;
    234     friend class GrGLProgramBuilder;
    235     friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
    236     friend class GrGLPathProgramBuilder; // to access fInputs.
    237     friend class GrVkProgramBuilder;
    238 };
    239 #endif
    240