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 SK_PRINTF_LIKE(4, 5) { 87 this->definitions().appendf("const %s %s = ", type, name); 88 va_list args; 89 va_start(args, fmt); 90 this->definitions().appendVAList(fmt, args); 91 va_end(args); 92 this->definitions().append(";\n"); 93 } 94 definitionAppend(const char * str)95 void definitionAppend(const char* str) { this->definitions().append(str); } 96 97 void declareGlobal(const GrShaderVar&); 98 99 // Generates a unique variable name for holding the result of a temporary expression when it's 100 // not reasonable to just add a new block for scoping. Does not declare anything. newTmpVarName(const char * suffix)101 SkString newTmpVarName(const char* suffix) { 102 int tmpIdx = fTmpVariableCounter++; 103 return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix); 104 } 105 106 /** 107 * Called by GrGLSLProcessors to add code to one of the shaders. 108 */ codeAppendf(const char format[],...)109 void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 110 va_list args; 111 va_start(args, format); 112 this->code().appendVAList(format, args); 113 va_end(args); 114 } 115 codeAppend(const char * str)116 void codeAppend(const char* str) { this->code().append(str); } 117 codeAppend(const char * str,size_t length)118 void codeAppend(const char* str, size_t length) { this->code().append(str, length); } 119 120 void codeAppend(std::unique_ptr<SkSL::Statement> stmt); 121 codePrependf(const char format[],...)122 void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 123 va_list args; 124 va_start(args, format); 125 this->code().prependVAList(format, args); 126 va_end(args); 127 } 128 129 /** 130 * Appends a variable declaration to one of the shaders 131 */ 132 void declAppend(const GrShaderVar& var); 133 134 /** 135 * Generates a mangled name for a helper function in the fragment shader. Will give consistent 136 * results if called more than once. 137 */ 138 SkString getMangledFunctionName(const char* baseName); 139 140 /** Emits a prototype for a helper function outside of main() in the fragment shader. */ 141 void emitFunctionPrototype(SkSLType returnType, 142 const char* mangledName, 143 SkSpan<const GrShaderVar> args); 144 145 void emitFunctionPrototype(const char* declaration); 146 147 /** Emits a helper function outside of main() in the fragment shader. */ 148 void emitFunction(SkSLType returnType, 149 const char* mangledName, 150 SkSpan<const GrShaderVar> args, 151 const char* body); 152 153 void emitFunction(const char* declaration, const char* body); 154 155 /** 156 * Combines the various parts of the shader to create a single finalized shader string. 157 */ 158 void finalize(uint32_t visibility); 159 160 /** 161 * Get parent builder for adding uniforms. 162 */ getProgramBuilder()163 GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; } 164 165 /** 166 * Helper for begining and ending a block in the shader code. 167 */ 168 class ShaderBlock { 169 public: ShaderBlock(GrGLSLShaderBuilder * builder)170 ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) { 171 SkASSERT(builder); 172 fBuilder->codeAppend("{"); 173 } 174 ~ShaderBlock()175 ~ShaderBlock() { 176 fBuilder->codeAppend("}"); 177 } 178 private: 179 GrGLSLShaderBuilder* fBuilder; 180 }; 181 182 protected: 183 typedef SkTBlockList<GrShaderVar> VarArray; 184 void appendDecls(const VarArray& vars, SkString* out) const; 185 186 void appendFunctionDecl(SkSLType returnType, 187 const char* mangledName, 188 SkSpan<const GrShaderVar> args); 189 190 /** 191 * Features that should only be enabled internally by the builders. 192 */ 193 enum GLSLPrivateFeature { 194 kFragCoordConventions_GLSLPrivateFeature, 195 kBlendEquationAdvanced_GLSLPrivateFeature, 196 kBlendFuncExtended_GLSLPrivateFeature, 197 kFramebufferFetch_GLSLPrivateFeature, 198 kNoPerspectiveInterpolation_GLSLPrivateFeature, 199 kSampleVariables_GLSLPrivateFeature, 200 kLastGLSLPrivateFeature = kSampleVariables_GLSLPrivateFeature 201 }; 202 203 /* 204 * A general function which enables an extension in a shader if the feature bit is not present 205 * 206 * @return true if the feature bit was not yet present, false otherwise. 207 */ 208 bool addFeature(uint32_t featureBit, const char* extensionName); 209 210 enum InterfaceQualifier { 211 kIn_InterfaceQualifier, 212 kOut_InterfaceQualifier, 213 kLastInterfaceQualifier = kOut_InterfaceQualifier 214 }; 215 216 /* 217 * A low level function to build default layout qualifiers. 218 * 219 * e.g. layout(param1, param2, ...) out; 220 * 221 * GLSL allows default layout qualifiers for in, out, and uniform. 222 */ 223 void addLayoutQualifier(const char* param, InterfaceQualifier); 224 225 void compileAndAppendLayoutQualifiers(); 226 nextStage()227 void nextStage() { 228 fShaderStrings.push_back(); 229 fCodeIndex++; 230 } 231 deleteStage()232 void deleteStage() { 233 fShaderStrings.pop_back(); 234 fCodeIndex--; 235 } 236 extensions()237 SkString& extensions() { return fShaderStrings[kExtensions]; } definitions()238 SkString& definitions() { return fShaderStrings[kDefinitions]; } precisionQualifier()239 SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; } layoutQualifiers()240 SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; } uniforms()241 SkString& uniforms() { return fShaderStrings[kUniforms]; } inputs()242 SkString& inputs() { return fShaderStrings[kInputs]; } outputs()243 SkString& outputs() { return fShaderStrings[kOutputs]; } functions()244 SkString& functions() { return fShaderStrings[kFunctions]; } main()245 SkString& main() { return fShaderStrings[kMain]; } code()246 SkString& code() { return fShaderStrings[fCodeIndex]; } 247 248 virtual void onFinalize() = 0; 249 250 enum { 251 kExtensions, 252 kDefinitions, 253 kPrecisionQualifier, 254 kLayoutQualifiers, 255 kUniforms, 256 kInputs, 257 kOutputs, 258 kFunctions, 259 kMain, 260 kCode, 261 262 kPrealloc = kCode + 6, // 6 == Reasonable upper bound on number of processor stages 263 }; 264 265 GrGLSLProgramBuilder* fProgramBuilder; 266 std::string fCompilerString; 267 SkSTArray<kPrealloc, SkString> fShaderStrings; 268 SkString fCode; 269 SkString fFunctions; 270 SkString fExtensions; 271 // Hangs onto Declarations so we don't destroy them prior to the variables that refer to them. 272 SkSL::StatementArray fDeclarations; 273 274 VarArray fInputs; 275 VarArray fOutputs; 276 uint32_t fFeaturesAddedMask; 277 SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1]; 278 int fCodeIndex; 279 bool fFinalized; 280 281 // Counter for generating unique scratch variable names in a shader. 282 int fTmpVariableCounter; 283 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::ThreadContext; 293 }; 294 #endif 295