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 "include/core/SkSpan.h" 12 #include "include/private/SkSLStatement.h" 13 #include "include/private/SkSLString.h" 14 #include "include/private/SkTDArray.h" 15 #include "src/gpu/GrShaderVar.h" 16 #include "src/gpu/GrTBlockList.h" 17 #include "src/gpu/glsl/GrGLSLUniformHandler.h" 18 19 #include <stdarg.h> 20 21 class GrGLSLColorSpaceXformHelper; 22 23 namespace SkSL { 24 namespace dsl { 25 class DSLWriter; 26 } 27 } 28 29 /** 30 base class for all shaders builders 31 */ 32 class GrGLSLShaderBuilder { 33 public: 34 GrGLSLShaderBuilder(GrGLSLProgramBuilder* program); ~GrGLSLShaderBuilder()35 virtual ~GrGLSLShaderBuilder() {} 36 37 using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; 38 39 /** Appends a 2D texture sample with projection if necessary. The vec length and swizzle 40 order of the result depends on the GrProcessor::TextureSampler associated with the 41 SamplerHandle. 42 */ 43 void appendTextureLookup(SkString* out, SamplerHandle, const char* coordName) const; 44 45 /** Version of above that appends the result to the shader code instead.*/ 46 void appendTextureLookup(SamplerHandle, 47 const char* coordName, 48 GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); 49 50 /** Does the work of appendTextureLookup and blends the result by dst, treating the texture 51 lookup a the src input to the blend. The dst is assumed to be half4 and the result is always 52 a half4. If dst is nullptr we use half4(1) as the blend dst. */ 53 void appendTextureLookupAndBlend(const char* dst, 54 SkBlendMode, 55 SamplerHandle, 56 const char* coordName, 57 GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); 58 59 /** Appends a load of an input attachment into the shader code. */ 60 void appendInputLoad(SamplerHandle); 61 62 /** Adds a helper function to facilitate color gamut transformation, and produces code that 63 returns the srcColor transformed into a new gamut (via multiplication by the xform from 64 colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper 65 determines if the source is premultipled or not). */ 66 void appendColorGamutXform(SkString* out, const char* srcColor, 67 GrGLSLColorSpaceXformHelper* colorXformHelper); 68 69 /** Version of above that appends the result to the shader code instead. */ 70 void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper); 71 72 /** 73 * Adds a constant declaration to the top of the shader. 74 */ defineConstant(const char * type,const char * name,const char * value)75 void defineConstant(const char* type, const char* name, const char* value) { 76 this->definitions().appendf("const %s %s = %s;\n", type, name, value); 77 } 78 defineConstant(const char * name,int value)79 void defineConstant(const char* name, int value) { 80 this->definitions().appendf("const int %s = %i;\n", name, value); 81 } 82 defineConstant(const char * name,float value)83 void defineConstant(const char* name, float value) { 84 this->definitions().appendf("const float %s = %f;\n", name, value); 85 } 86 defineConstantf(const char * type,const char * name,const char * fmt,...)87 void defineConstantf(const char* type, const char* name, const char* fmt, ...) { 88 this->definitions().appendf("const %s %s = ", type, name); 89 va_list args; 90 va_start(args, fmt); 91 this->definitions().appendVAList(fmt, args); 92 va_end(args); 93 this->definitions().append(";\n"); 94 } 95 definitionAppend(const char * str)96 void definitionAppend(const char* str) { this->definitions().append(str); } 97 98 void declareGlobal(const GrShaderVar&); 99 100 // Generates a unique variable name for holding the result of a temporary expression when it's 101 // not reasonable to just add a new block for scoping. Does not declare anything. newTmpVarName(const char * suffix)102 SkString newTmpVarName(const char* suffix) { 103 int tmpIdx = fTmpVariableCounter++; 104 return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix); 105 } 106 107 /** 108 * Called by GrGLSLProcessors to add code to one of the shaders. 109 */ codeAppendf(const char format[],...)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 codeAppend(const char * str)117 void codeAppend(const char* str) { this->code().append(str); } 118 codeAppend(const char * str,size_t length)119 void codeAppend(const char* str, size_t length) { this->code().append(str, length); } 120 121 void codeAppend(std::unique_ptr<SkSL::Statement> stmt); 122 codePrependf(const char format[],...)123 void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 124 va_list args; 125 va_start(args, format); 126 this->code().prependVAList(format, args); 127 va_end(args); 128 } 129 130 /** 131 * Appends a variable declaration to one of the shaders 132 */ 133 void declAppend(const GrShaderVar& var); 134 135 /** 136 * Generates a mangled name for a helper function in the fragment shader. Will give consistent 137 * results if called more than once. 138 */ 139 SkString getMangledFunctionName(const char* baseName); 140 141 /** Emits a prototype for a helper function outside of main() in the fragment shader. */ 142 void emitFunctionPrototype(GrSLType returnType, 143 const char* mangledName, 144 SkSpan<const GrShaderVar> args); 145 146 /** Emits a helper function outside of main() in the fragment shader. */ 147 void emitFunction(GrSLType returnType, 148 const char* mangledName, 149 SkSpan<const GrShaderVar> args, 150 const char* body); 151 152 void emitFunction(const char* declaration, const char* body); 153 154 /** 155 * Combines the various parts of the shader to create a single finalized shader string. 156 */ 157 void finalize(uint32_t visibility); 158 159 /** 160 * Get parent builder for adding uniforms. 161 */ getProgramBuilder()162 GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; } 163 164 /** 165 * Helper for begining and ending a block in the shader code. 166 */ 167 class ShaderBlock { 168 public: ShaderBlock(GrGLSLShaderBuilder * builder)169 ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) { 170 SkASSERT(builder); 171 fBuilder->codeAppend("{"); 172 } 173 ~ShaderBlock()174 ~ShaderBlock() { 175 fBuilder->codeAppend("}"); 176 } 177 private: 178 GrGLSLShaderBuilder* fBuilder; 179 }; 180 181 protected: 182 typedef GrTBlockList<GrShaderVar> VarArray; 183 void appendDecls(const VarArray& vars, SkString* out) const; 184 185 void appendFunctionDecl(GrSLType returnType, 186 const char* mangledName, 187 SkSpan<const GrShaderVar> args); 188 189 /** 190 * Features that should only be enabled internally by the builders. 191 */ 192 enum GLSLPrivateFeature { 193 kFragCoordConventions_GLSLPrivateFeature, 194 kBlendEquationAdvanced_GLSLPrivateFeature, 195 kBlendFuncExtended_GLSLPrivateFeature, 196 kFramebufferFetch_GLSLPrivateFeature, 197 kNoPerspectiveInterpolation_GLSLPrivateFeature, 198 kSampleVariables_GLSLPrivateFeature, 199 kLastGLSLPrivateFeature = kSampleVariables_GLSLPrivateFeature 200 }; 201 202 /* 203 * A general function which enables an extension in a shader if the feature bit is not present 204 * 205 * @return true if the feature bit was not yet present, false otherwise. 206 */ 207 bool addFeature(uint32_t featureBit, const char* extensionName); 208 209 enum InterfaceQualifier { 210 kIn_InterfaceQualifier, 211 kOut_InterfaceQualifier, 212 kLastInterfaceQualifier = kOut_InterfaceQualifier 213 }; 214 215 /* 216 * A low level function to build default layout qualifiers. 217 * 218 * e.g. layout(param1, param2, ...) out; 219 * 220 * GLSL allows default layout qualifiers for in, out, and uniform. 221 */ 222 void addLayoutQualifier(const char* param, InterfaceQualifier); 223 224 void compileAndAppendLayoutQualifiers(); 225 nextStage()226 void nextStage() { 227 fShaderStrings.push_back(); 228 fCodeIndex++; 229 } 230 deleteStage()231 void deleteStage() { 232 fShaderStrings.pop_back(); 233 fCodeIndex--; 234 } 235 extensions()236 SkString& extensions() { return fShaderStrings[kExtensions]; } definitions()237 SkString& definitions() { return fShaderStrings[kDefinitions]; } precisionQualifier()238 SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; } layoutQualifiers()239 SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; } uniforms()240 SkString& uniforms() { return fShaderStrings[kUniforms]; } inputs()241 SkString& inputs() { return fShaderStrings[kInputs]; } outputs()242 SkString& outputs() { return fShaderStrings[kOutputs]; } functions()243 SkString& functions() { return fShaderStrings[kFunctions]; } main()244 SkString& main() { return fShaderStrings[kMain]; } code()245 SkString& code() { return fShaderStrings[fCodeIndex]; } 246 247 virtual void onFinalize() = 0; 248 249 enum { 250 kExtensions, 251 kDefinitions, 252 kPrecisionQualifier, 253 kLayoutQualifiers, 254 kUniforms, 255 kInputs, 256 kOutputs, 257 kFunctions, 258 kMain, 259 kCode, 260 261 kPrealloc = kCode + 6, // 6 == Reasonable upper bound on number of processor stages 262 }; 263 264 GrGLSLProgramBuilder* fProgramBuilder; 265 SkSL::String fCompilerString; 266 SkSTArray<kPrealloc, SkString> fShaderStrings; 267 SkString fCode; 268 SkString fFunctions; 269 SkString fExtensions; 270 // Hangs onto Declarations so we don't destroy them prior to the variables that refer to them. 271 SkSL::StatementArray fDeclarations; 272 273 VarArray fInputs; 274 VarArray fOutputs; 275 uint32_t fFeaturesAddedMask; 276 SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1]; 277 int fCodeIndex; 278 bool fFinalized; 279 280 // Counter for generating unique scratch variable names in a shader. 281 int fTmpVariableCounter; 282 283 friend class GrCCCoverageProcessor; // to access code(). 284 friend class GrGLSLProgramBuilder; 285 friend class GrGLProgramBuilder; 286 friend class GrD3DPipelineStateBuilder; 287 friend class GrDawnProgramBuilder; 288 friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature. 289 friend class GrGLPathProgramBuilder; // to access fInputs. 290 friend class GrVkPipelineStateBuilder; 291 friend class GrMtlPipelineStateBuilder; 292 friend class SkSL::dsl::DSLWriter; 293 }; 294 #endif 295