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