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