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