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 "GrShaderVar.h"
     13 #include "glsl/GrGLSLUniformHandler.h"
     14 #include "SkTDArray.h"
     15 
     16 #include <stdarg.h>
     17 
     18 class GrGLSLColorSpaceXformHelper;
     19 
     20 /**
     21   base class for all shaders builders
     22 */
     23 class GrGLSLShaderBuilder {
     24 public:
     25     GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
     26     virtual ~GrGLSLShaderBuilder() {}
     27 
     28     using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
     29     using TexelBufferHandle  = GrGLSLUniformHandler::TexelBufferHandle;
     30     using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
     31 
     32     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
     33         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
     34         order of the result depends on the GrProcessor::TextureSampler associated with the
     35         SamplerHandle.
     36         */
     37     void appendTextureLookup(SkString* out,
     38                              SamplerHandle,
     39                              const char* coordName,
     40                              GrSLType coordType = kVec2f_GrSLType) const;
     41 
     42     /** Version of above that appends the result to the shader code instead.*/
     43     void appendTextureLookup(SamplerHandle,
     44                              const char* coordName,
     45                              GrSLType coordType = kVec2f_GrSLType,
     46                              GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
     47 
     48 
     49     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
     50         always a vec4. modulation and the swizzle specified by SamplerHandle must both be
     51         vec4 or float. If modulation is "" or nullptr it this function acts as though
     52         appendTextureLookup were called. */
     53     void appendTextureLookupAndModulate(const char* modulation,
     54                                         SamplerHandle,
     55                                         const char* coordName,
     56                                         GrSLType coordType = kVec2f_GrSLType,
     57                                         GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
     58 
     59     /** Adds a helper function to facilitate color gamut transformation, and produces code that
     60         returns the srcColor transformed into a new gamut (via multiplication by the xform from
     61         colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
     62         determines if the source is premultipled or not). */
     63     void appendColorGamutXform(SkString* out, const char* srcColor,
     64                                GrGLSLColorSpaceXformHelper* colorXformHelper);
     65 
     66     /** Version of above that appends the result to the shader code instead. */
     67     void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
     68 
     69     /** Fetches an unfiltered texel from a sampler at integer coordinates. coordExpr must match the
     70         dimensionality of the sampler and must be within the sampler's range. coordExpr is emitted
     71         exactly once, so expressions like "idx++" are acceptable. */
     72     void appendTexelFetch(SkString* out, TexelBufferHandle, const char* coordExpr) const;
     73 
     74     /** Version of above that appends the result to the shader code instead.*/
     75     void appendTexelFetch(TexelBufferHandle, const char* coordExpr);
     76 
     77     /** Creates a string of shader code that performs an image load. */
     78     void appendImageStorageLoad(SkString* out, ImageStorageHandle, const char* coordExpr);
     79     /** Version of above that appends the result to the shader code instead. */
     80     void appendImageStorageLoad(ImageStorageHandle, const char* coordExpr);
     81 
     82     /**
     83     * Adds a constant declaration to the top of the shader.
     84     */
     85     void defineConstant(const char* type, const char* name, const char* value) {
     86         this->definitions().appendf("const %s %s = %s;\n", type, name, value);
     87     }
     88 
     89     void defineConstant(const char* name, int value) {
     90         this->definitions().appendf("const int %s = %i;\n", name, value);
     91     }
     92 
     93     void defineConstant(const char* name, float value) {
     94         this->definitions().appendf("const float %s = %f;\n", name, value);
     95     }
     96 
     97     void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
     98        this->definitions().appendf("const %s %s = ", type, name);
     99        va_list args;
    100        va_start(args, fmt);
    101        this->definitions().appendVAList(fmt, args);
    102        va_end(args);
    103        this->definitions().append(";\n");
    104     }
    105 
    106     void declareGlobal(const GrShaderVar&);
    107 
    108     /**
    109     * Called by GrGLSLProcessors to add code to one of the shaders.
    110     */
    111     void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
    112        va_list args;
    113        va_start(args, format);
    114        this->code().appendVAList(format, args);
    115        va_end(args);
    116     }
    117 
    118     void codeAppend(const char* str) { this->code().append(str); }
    119 
    120     void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
    121        va_list args;
    122        va_start(args, format);
    123        this->code().prependVAList(format, args);
    124        va_end(args);
    125     }
    126 
    127     /**
    128      * Appends a variable declaration to one of the shaders
    129      */
    130     void declAppend(const GrShaderVar& var);
    131 
    132     /** Emits a helper function outside of main() in the fragment shader. */
    133     void emitFunction(GrSLType returnType,
    134                       const char* name,
    135                       int argCnt,
    136                       const GrShaderVar* args,
    137                       const char* body,
    138                       SkString* outName);
    139 
    140     /*
    141      * Combines the various parts of the shader to create a single finalized shader string.
    142      */
    143     void finalize(uint32_t visibility);
    144 
    145     /*
    146      * Get parent builder for adding uniforms
    147      */
    148     GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
    149 
    150     /**
    151      * Helper for begining and ending a block in the shader code.
    152      */
    153     class ShaderBlock {
    154     public:
    155         ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
    156             SkASSERT(builder);
    157             fBuilder->codeAppend("{");
    158         }
    159 
    160         ~ShaderBlock() {
    161             fBuilder->codeAppend("}");
    162         }
    163     private:
    164         GrGLSLShaderBuilder* fBuilder;
    165     };
    166 
    167 protected:
    168     typedef GrTAllocator<GrShaderVar> VarArray;
    169     void appendDecls(const VarArray& vars, SkString* out) const;
    170 
    171     /**
    172      * Features that should only be enabled internally by the builders.
    173      */
    174     enum GLSLPrivateFeature {
    175         kFragCoordConventions_GLSLPrivateFeature,
    176         kBlendEquationAdvanced_GLSLPrivateFeature,
    177         kBlendFuncExtended_GLSLPrivateFeature,
    178         kExternalTexture_GLSLPrivateFeature,
    179         kTexelBuffer_GLSLPrivateFeature,
    180         kFramebufferFetch_GLSLPrivateFeature,
    181         kNoPerspectiveInterpolation_GLSLPrivateFeature,
    182         kSampleVariables_GLSLPrivateFeature,
    183         kSampleMaskOverrideCoverage_GLSLPrivateFeature,
    184         kLastGLSLPrivateFeature = kSampleMaskOverrideCoverage_GLSLPrivateFeature
    185     };
    186 
    187     /*
    188      * A general function which enables an extension in a shader if the feature bit is not present
    189      *
    190      * @return true if the feature bit was not yet present, false otherwise.
    191      */
    192     bool addFeature(uint32_t featureBit, const char* extensionName);
    193 
    194     enum InterfaceQualifier {
    195         kIn_InterfaceQualifier,
    196         kOut_InterfaceQualifier,
    197         kLastInterfaceQualifier = kOut_InterfaceQualifier
    198     };
    199 
    200     /*
    201      * A low level function to build default layout qualifiers.
    202      *
    203      *   e.g. layout(param1, param2, ...) out;
    204      *
    205      * GLSL allows default layout qualifiers for in, out, and uniform.
    206      */
    207     void addLayoutQualifier(const char* param, InterfaceQualifier);
    208 
    209     void compileAndAppendLayoutQualifiers();
    210 
    211     void nextStage() {
    212         fShaderStrings.push_back();
    213         fCompilerStrings.push_back(this->code().c_str());
    214         fCompilerStringLengths.push_back((int)this->code().size());
    215         fCodeIndex++;
    216     }
    217 
    218     SkString& versionDecl() { return fShaderStrings[kVersionDecl]; }
    219     SkString& extensions() { return fShaderStrings[kExtensions]; }
    220     SkString& definitions() { return fShaderStrings[kDefinitions]; }
    221     SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
    222     SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
    223     SkString& uniforms() { return fShaderStrings[kUniforms]; }
    224     SkString& inputs() { return fShaderStrings[kInputs]; }
    225     SkString& outputs() { return fShaderStrings[kOutputs]; }
    226     SkString& functions() { return fShaderStrings[kFunctions]; }
    227     SkString& main() { return fShaderStrings[kMain]; }
    228     SkString& code() { return fShaderStrings[fCodeIndex]; }
    229 
    230     virtual void onFinalize() = 0;
    231 
    232     enum {
    233         kVersionDecl,
    234         kExtensions,
    235         kDefinitions,
    236         kPrecisionQualifier,
    237         kLayoutQualifiers,
    238         kUniforms,
    239         kInputs,
    240         kOutputs,
    241         kFunctions,
    242         kMain,
    243         kCode,
    244     };
    245 
    246     GrGLSLProgramBuilder* fProgramBuilder;
    247     SkSTArray<kCode, const char*, true> fCompilerStrings;
    248     SkSTArray<kCode, int, true> fCompilerStringLengths;
    249     SkSTArray<kCode, SkString> fShaderStrings;
    250     SkString fCode;
    251     SkString fFunctions;
    252     SkString fExtensions;
    253 
    254     VarArray fInputs;
    255     VarArray fOutputs;
    256     uint32_t fFeaturesAddedMask;
    257     SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
    258     int fCodeIndex;
    259     bool fFinalized;
    260 
    261     friend class GrGLSLProgramBuilder;
    262     friend class GrGLProgramBuilder;
    263     friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
    264     friend class GrGLPathProgramBuilder; // to access fInputs.
    265     friend class GrVkPipelineStateBuilder;
    266 };
    267 #endif
    268