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