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/core/SkTBlockList.h" 16 #include "src/gpu/GrShaderVar.h" 17 #include "src/gpu/glsl/GrGLSLUniformHandler.h" 18 19 #include <stdarg.h> 20 21 class GrGLSLColorSpaceXformHelper; 22 23 namespace SkSL { 24 class ThreadContext; 25 } 26 27 /** 28 base class for all shaders builders 29 */ 30 class GrGLSLShaderBuilder { 31 public: 32 GrGLSLShaderBuilder(GrGLSLProgramBuilder* program); ~GrGLSLShaderBuilder()33 virtual ~GrGLSLShaderBuilder() {} 34 35 using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; 36 37 /** Appends a 2D texture sample with projection if necessary. The vec length and swizzle 38 order of the result depends on the GrProcessor::TextureSampler associated with the 39 SamplerHandle. 40 */ 41 void appendTextureLookup(SkString* out, SamplerHandle, const char* coordName) const; 42 43 /** Version of above that appends the result to the shader code instead.*/ 44 void appendTextureLookup(SamplerHandle, 45 const char* coordName, 46 GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); 47 48 /** Does the work of appendTextureLookup and blends the result by dst, treating the texture 49 lookup as the src input to the blend. The dst is assumed to be half4 and the result is 50 always a half4. If dst is nullptr we use half4(1) as the blend dst. */ 51 void appendTextureLookupAndBlend(const char* dst, 52 SkBlendMode, 53 SamplerHandle, 54 const char* coordName, 55 GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); 56 57 /** Appends a load of an input attachment into the shader code. */ 58 void appendInputLoad(SamplerHandle); 59 60 /** Adds a helper function to facilitate color gamut transformation, and produces code that 61 returns the srcColor transformed into a new gamut (via multiplication by the xform from 62 colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper 63 determines if the source is premultipled or not). */ 64 void appendColorGamutXform(SkString* out, const char* srcColor, 65 GrGLSLColorSpaceXformHelper* colorXformHelper); 66 67 /** Version of above that appends the result to the shader code instead. */ 68 void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper); 69 70 /** 71 * Adds a constant declaration to the top of the shader. 72 */ defineConstant(const char * type,const char * name,const char * value)73 void defineConstant(const char* type, const char* name, const char* value) { 74 this->definitions().appendf("const %s %s = %s;\n", type, name, value); 75 } 76 defineConstant(const char * name,int value)77 void defineConstant(const char* name, int value) { 78 this->definitions().appendf("const int %s = %i;\n", name, value); 79 } 80 defineConstant(const char * name,float value)81 void defineConstant(const char* name, float value) { 82 this->definitions().appendf("const float %s = %f;\n", name, value); 83 } 84 defineConstantf(const char * type,const char * name,const char * fmt,...)85 void defineConstantf(const char* type, const char* name, const char* fmt, ...) { 86 this->definitions().appendf("const %s %s = ", type, name); 87 va_list args; 88 va_start(args, fmt); 89 this->definitions().appendVAList(fmt, args); 90 va_end(args); 91 this->definitions().append(";\n"); 92 } 93 definitionAppend(const char * str)94 void definitionAppend(const char* str) { this->definitions().append(str); } 95 96 void declareGlobal(const GrShaderVar&); 97 98 // Generates a unique variable name for holding the result of a temporary expression when it's 99 // not reasonable to just add a new block for scoping. Does not declare anything. newTmpVarName(const char * suffix)100 SkString newTmpVarName(const char* suffix) { 101 int tmpIdx = fTmpVariableCounter++; 102 return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix); 103 } 104 105 /** 106 * Called by GrGLSLProcessors to add code to one of the shaders. 107 */ codeAppendf(const char format[],...)108 void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 109 va_list args; 110 va_start(args, format); 111 this->code().appendVAList(format, args); 112 va_end(args); 113 } 114 codeAppend(const char * str)115 void codeAppend(const char* str) { this->code().append(str); } 116 codeAppend(const char * str,size_t length)117 void codeAppend(const char* str, size_t length) { this->code().append(str, length); } 118 119 void codeAppend(std::unique_ptr<SkSL::Statement> stmt); 120 codePrependf(const char format[],...)121 void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 122 va_list args; 123 va_start(args, format); 124 this->code().prependVAList(format, args); 125 va_end(args); 126 } 127 128 /** 129 * Appends a variable declaration to one of the shaders 130 */ 131 void declAppend(const GrShaderVar& var); 132 133 /** 134 * Generates a mangled name for a helper function in the fragment shader. Will give consistent 135 * results if called more than once. 136 */ 137 SkString getMangledFunctionName(const char* baseName); 138 139 /** Emits a prototype for a helper function outside of main() in the fragment shader. */ 140 void emitFunctionPrototype(GrSLType returnType, 141 const char* mangledName, 142 SkSpan<const GrShaderVar> args); 143 144 void emitFunctionPrototype(const char* declaration); 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 SkTBlockList<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 GrGLSLProgramBuilder; 284 friend class GrGLProgramBuilder; 285 friend class GrD3DPipelineStateBuilder; 286 friend class GrDawnProgramBuilder; 287 friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature. 288 friend class GrGLPathProgramBuilder; // to access fInputs. 289 friend class GrVkPipelineStateBuilder; 290 friend class GrMtlPipelineStateBuilder; 291 friend class SkSL::ThreadContext; 292 }; 293 #endif 294