1 /* 2 * Copyright 2012 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 GrGLShaderBuilder_DEFINED 9 #define GrGLShaderBuilder_DEFINED 10 11 #include "GrAllocator.h" 12 #include "GrBackendEffectFactory.h" 13 #include "GrColor.h" 14 #include "GrEffect.h" 15 #include "gl/GrGLSL.h" 16 #include "gl/GrGLUniformManager.h" 17 18 #include <stdarg.h> 19 20 class GrGLContextInfo; 21 class GrEffectStage; 22 class GrGLProgramDesc; 23 24 /** 25 Contains all the incremental state of a shader as it is being built,as well as helpers to 26 manipulate that state. 27 */ 28 class GrGLShaderBuilder { 29 public: 30 /** 31 * Passed to GrGLEffects to add texture reads to their shader code. 32 */ 33 class TextureSampler { 34 public: 35 TextureSampler() 36 : fConfigComponentMask(0) 37 , fSamplerUniform(GrGLUniformManager::kInvalidUniformHandle) { 38 // we will memcpy the first 4 bytes from passed in swizzle. This ensures the string is 39 // terminated. 40 fSwizzle[4] = '\0'; 41 } 42 43 TextureSampler(const TextureSampler& other) { *this = other; } 44 45 TextureSampler& operator= (const TextureSampler& other) { 46 GrAssert(0 == fConfigComponentMask); 47 GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform); 48 49 fConfigComponentMask = other.fConfigComponentMask; 50 fSamplerUniform = other.fSamplerUniform; 51 return *this; 52 } 53 54 // bitfield of GrColorComponentFlags present in the texture's config. 55 uint32_t configComponentMask() const { return fConfigComponentMask; } 56 57 const char* swizzle() const { return fSwizzle; } 58 59 bool isInitialized() const { return 0 != fConfigComponentMask; } 60 61 private: 62 // The idx param is used to ensure multiple samplers within a single effect have unique 63 // uniform names. swizzle is a four char max string made up of chars 'r', 'g', 'b', and 'a'. 64 void init(GrGLShaderBuilder* builder, 65 uint32_t configComponentMask, 66 const char* swizzle, 67 int idx) { 68 GrAssert(!this->isInitialized()); 69 GrAssert(0 != configComponentMask); 70 GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform); 71 72 GrAssert(NULL != builder); 73 SkString name; 74 name.printf("Sampler%d", idx); 75 fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 76 kSampler2D_GrSLType, 77 name.c_str()); 78 GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform); 79 80 fConfigComponentMask = configComponentMask; 81 memcpy(fSwizzle, swizzle, 4); 82 } 83 84 void init(GrGLShaderBuilder* builder, const GrTextureAccess* access, int idx) { 85 GrAssert(NULL != access); 86 this->init(builder, 87 GrPixelConfigComponentMask(access->getTexture()->config()), 88 access->getSwizzle(), 89 idx); 90 } 91 92 uint32_t fConfigComponentMask; 93 char fSwizzle[5]; 94 GrGLUniformManager::UniformHandle fSamplerUniform; 95 96 friend class GrGLShaderBuilder; // to call init(). 97 }; 98 99 typedef SkTArray<TextureSampler> TextureSamplerArray; 100 101 enum ShaderType { 102 kVertex_ShaderType = 0x1, 103 kGeometry_ShaderType = 0x2, 104 kFragment_ShaderType = 0x4, 105 }; 106 107 GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&, const GrGLProgramDesc&); 108 109 /** 110 * Use of these features may require a GLSL extension to be enabled. Shaders may not compile 111 * if code is added that uses one of these features without calling enableFeature() 112 */ 113 enum GLSLFeature { 114 kStandardDerivatives_GLSLFeature = 0, 115 116 kLastGLSLFeature = kStandardDerivatives_GLSLFeature 117 }; 118 119 /** 120 * If the feature is supported then true is returned and any necessary #extension declarations 121 * are added to the shaders. If the feature is not supported then false will be returned. 122 */ 123 bool enableFeature(GLSLFeature); 124 125 /** 126 * Called by GrGLEffects to add code to one of the shaders. 127 */ 128 void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 129 va_list args; 130 va_start(args, format); 131 this->codeAppendf(kVertex_ShaderType, format, args); 132 va_end(args); 133 } 134 135 void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 136 va_list args; 137 va_start(args, format); 138 this->codeAppendf(kGeometry_ShaderType, format, args); 139 va_end(args); 140 } 141 142 void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 143 va_list args; 144 va_start(args, format); 145 this->codeAppendf(kFragment_ShaderType, format, args); 146 va_end(args); 147 } 148 149 void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); } 150 void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); } 151 void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); } 152 153 /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or 154 Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle 155 order of the result depends on the GrTextureAccess associated with the TextureSampler. */ 156 void appendTextureLookup(SkString* out, 157 const TextureSampler&, 158 const char* coordName, 159 GrSLType coordType = kVec2f_GrSLType) const; 160 161 /** Version of above that appends the result to the shader code rather than an SkString. 162 Currently the shader type must be kFragment */ 163 void appendTextureLookup(ShaderType, 164 const TextureSampler&, 165 const char* coordName, 166 GrSLType coordType = kVec2f_GrSLType); 167 168 169 /** Does the work of appendTextureLookup and modulates the result by modulation. The result is 170 always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or 171 float. If modulation is "" or NULL it this function acts as though appendTextureLookup were 172 called. */ 173 void appendTextureLookupAndModulate(ShaderType, 174 const char* modulation, 175 const TextureSampler&, 176 const char* coordName, 177 GrSLType coordType = kVec2f_GrSLType); 178 179 /** Emits a helper function outside of main(). Currently ShaderType must be 180 kFragment_ShaderType. */ 181 void emitFunction(ShaderType shader, 182 GrSLType returnType, 183 const char* name, 184 int argCnt, 185 const GrGLShaderVar* args, 186 const char* body, 187 SkString* outName); 188 189 /** Generates a EffectKey for the shader code based on the texture access parameters and the 190 capabilities of the GL context. This is useful for keying the shader programs that may 191 have multiple representations, based on the type/format of textures used. */ 192 static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&, 193 const GrGLCaps&); 194 195 typedef uint8_t DstReadKey; 196 typedef uint8_t FragPosKey; 197 198 /** Returns a key for adding code to read the copy-of-dst color in service of effects that 199 require reading the dst. It must not return 0 because 0 indicates that there is no dst 200 copy read at all (in which case this function should not be called). */ 201 static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&); 202 203 /** Returns a key for reading the fragment location. This should only be called if there is an 204 effect that will requires the fragment position. If the fragment position is not required, 205 the key is 0. */ 206 static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&); 207 208 /** If texture swizzling is available using tex parameters then it is preferred over mangling 209 the generated shader code. This potentially allows greater reuse of cached shaders. */ 210 static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps); 211 212 /** Add a uniform variable to the current program, that has visibility in one or more shaders. 213 visibility is a bitfield of ShaderType values indicating from which shaders the uniform 214 should be accessible. At least one bit must be set. Geometry shader uniforms are not 215 supported at this time. The actual uniform name will be mangled. If outName is not NULL then 216 it will refer to the final uniform name after return. Use the addUniformArray variant to add 217 an array of uniforms. 218 */ 219 GrGLUniformManager::UniformHandle addUniform(uint32_t visibility, 220 GrSLType type, 221 const char* name, 222 const char** outName = NULL) { 223 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName); 224 } 225 GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility, 226 GrSLType type, 227 const char* name, 228 int arrayCount, 229 const char** outName = NULL); 230 231 const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const; 232 233 /** 234 * Shortcut for getUniformVariable(u).c_str() 235 */ 236 const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const { 237 return this->getUniformVariable(u).c_str(); 238 } 239 240 /** Add a vertex attribute to the current program that is passed in from the vertex data. 241 Returns false if the attribute was already there, true otherwise. */ 242 bool addAttribute(GrSLType type, const char* name); 243 244 /** Add a varying variable to the current program to pass values between vertex and fragment 245 shaders. If the last two parameters are non-NULL, they are filled in with the name 246 generated. */ 247 void addVarying(GrSLType type, 248 const char* name, 249 const char** vsOutName = NULL, 250 const char** fsInName = NULL); 251 252 /** Returns a variable name that represents the position of the fragment in the FS. The position 253 is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */ 254 const char* fragmentPosition(); 255 256 /** Returns a vertex attribute that represents the vertex position in the VS. This is the 257 pre-matrix position and is commonly used by effects to compute texture coords via a matrix. 258 */ 259 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; } 260 261 /** Returns a vertex attribute that represents the local coords in the VS. This may be the same 262 as positionAttribute() or it may not be. It depends upon whether the rendering code 263 specified explicit local coords or not in the GrDrawState. */ 264 const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; } 265 266 /** Returns the color of the destination pixel. This may be NULL if no effect advertised 267 that it will read the destination. */ 268 const char* dstColor(); 269 270 /** 271 * Are explicit local coordinates provided as input to the vertex shader. 272 */ 273 bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } 274 275 /** 276 * Interfaces used by GrGLProgram. 277 * TODO: Hide these from the GrEffects using friend or splitting this into two related classes. 278 * Also, GrGLProgram's shader string construction should be moved to this class. 279 */ 280 281 /** Called after building is complete to get the final shader string. */ 282 void getShader(ShaderType, SkString*) const; 283 284 /** 285 * Adds code for effects. effectStages contains the effects to add. effectKeys[i] is the key 286 * generated from effectStages[i]. An entry in effectStages can be NULL, in which case it is 287 * skipped. Moreover, if the corresponding key is GrGLEffect::NoEffectKey then it is skipped. 288 * inOutFSColor specifies the input color to the first stage and is updated to be the 289 * output color of the last stage. fsInOutColorKnownValue specifies whether the input color 290 * has a known constant value and is updated to refer to the status of the output color. 291 * The handles to texture samplers for effectStage[i] are added to effectSamplerHandles[i]. The 292 * glEffects array is updated to contain the GrGLEffect generated for each entry in 293 * effectStages. 294 */ 295 void emitEffects(const GrEffectStage* effectStages[], 296 const GrBackendEffectFactory::EffectKey effectKeys[], 297 int effectCnt, 298 SkString* inOutFSColor, 299 GrSLConstantVec* fsInOutColorKnownValue, 300 SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[], 301 GrGLEffect* glEffects[]); 302 303 GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; } 304 GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const { 305 return fDstCopyTopLeftUniform; 306 } 307 GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const { 308 return fDstCopyScaleUniform; 309 } 310 GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const { 311 return fDstCopySampler.fSamplerUniform; 312 } 313 314 struct AttributePair { 315 void set(int index, const SkString& name) { 316 fIndex = index; fName = name; 317 } 318 int fIndex; 319 SkString fName; 320 }; 321 const SkTArray<AttributePair, true>& getEffectAttributes() const { 322 return fEffectAttributes; 323 } 324 const SkString* getEffectAttributeName(int attributeIndex) const; 325 326 // TODO: Make this do all the compiling, linking, etc. 327 void finished(GrGLuint programID); 328 329 const GrGLContextInfo& ctxInfo() const { return fCtxInfo; } 330 331 private: 332 void codeAppendf(ShaderType type, const char format[], va_list args); 333 void codeAppend(ShaderType type, const char* str); 334 335 typedef GrTAllocator<GrGLShaderVar> VarArray; 336 337 void appendDecls(const VarArray&, SkString*) const; 338 void appendUniformDecls(ShaderType, SkString*) const; 339 340 typedef GrGLUniformManager::BuilderUniform BuilderUniform; 341 GrGLUniformManager::BuilderUniformArray fUniforms; 342 343 // TODO: Everything below here private. 344 public: 345 346 VarArray fVSAttrs; 347 VarArray fVSOutputs; 348 VarArray fGSInputs; 349 VarArray fGSOutputs; 350 VarArray fFSInputs; 351 SkString fGSHeader; // layout qualifiers specific to GS 352 VarArray fFSOutputs; 353 354 private: 355 class CodeStage : GrNoncopyable { 356 public: 357 CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} 358 359 bool inStageCode() const { 360 this->validate(); 361 return NULL != fEffectStage; 362 } 363 364 const GrEffectStage* effectStage() const { 365 this->validate(); 366 return fEffectStage; 367 } 368 369 int stageIndex() const { 370 this->validate(); 371 return fCurrentIndex; 372 } 373 374 class AutoStageRestore : GrNoncopyable { 375 public: 376 AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) { 377 GrAssert(NULL != codeStage); 378 fSavedIndex = codeStage->fCurrentIndex; 379 fSavedEffectStage = codeStage->fEffectStage; 380 381 if (NULL == newStage) { 382 codeStage->fCurrentIndex = -1; 383 } else { 384 codeStage->fCurrentIndex = codeStage->fNextIndex++; 385 } 386 codeStage->fEffectStage = newStage; 387 388 fCodeStage = codeStage; 389 } 390 ~AutoStageRestore() { 391 fCodeStage->fCurrentIndex = fSavedIndex; 392 fCodeStage->fEffectStage = fSavedEffectStage; 393 } 394 private: 395 CodeStage* fCodeStage; 396 int fSavedIndex; 397 const GrEffectStage* fSavedEffectStage; 398 }; 399 private: 400 void validate() const { GrAssert((NULL == fEffectStage) == (-1 == fCurrentIndex)); } 401 int fNextIndex; 402 int fCurrentIndex; 403 const GrEffectStage* fEffectStage; 404 } fCodeStage; 405 406 /** 407 * Features that should only be enabled by GrGLShaderBuilder itself. 408 */ 409 enum GLSLPrivateFeature { 410 kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1, 411 kEXTShaderFramebufferFetch_GLSLPrivateFeature, 412 kNVShaderFramebufferFetch_GLSLPrivateFeature, 413 }; 414 bool enablePrivateFeature(GLSLPrivateFeature); 415 416 // If we ever have VS/GS features we can expand this to take a bitmask of ShaderType and track 417 // the enables separately for each shader. 418 void addFSFeature(uint32_t featureBit, const char* extensionName); 419 420 // Generates a name for a variable. The generated string will be name prefixed by the prefix 421 // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're 422 // generating stage code. 423 void nameVariable(SkString* out, char prefix, const char* name); 424 425 // Interpretation of DstReadKey when generating code 426 enum { 427 kNoDstRead_DstReadKey = 0, 428 kYesDstRead_DstReadKeyBit = 0x1, // Set if we do a dst-copy-read. 429 kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only. 430 kTopLeftOrigin_DstReadKeyBit = 0x4, // Set if dst-copy origin is top-left. 431 }; 432 433 enum { 434 kNoFragPosRead_FragPosKey = 0, // The fragment positition will not be needed. 435 kTopLeftFragPosRead_FragPosKey = 0x1,// Read frag pos relative to top-left. 436 kBottomLeftFragPosRead_FragPosKey = 0x2,// Read frag pos relative to bottom-left. 437 }; 438 439 const GrGLContextInfo& fCtxInfo; 440 GrGLUniformManager& fUniformManager; 441 uint32_t fFSFeaturesAddedMask; 442 SkString fFSFunctions; 443 SkString fFSExtensions; 444 445 bool fUsesGS; 446 447 SkString fFSCode; 448 SkString fVSCode; 449 SkString fGSCode; 450 451 bool fSetupFragPosition; 452 TextureSampler fDstCopySampler; 453 454 GrGLUniformManager::UniformHandle fRTHeightUniform; 455 GrGLUniformManager::UniformHandle fDstCopyTopLeftUniform; 456 GrGLUniformManager::UniformHandle fDstCopyScaleUniform; 457 458 bool fTopLeftFragPosRead; 459 460 SkSTArray<10, AttributePair, true> fEffectAttributes; 461 462 GrGLShaderVar* fPositionVar; 463 GrGLShaderVar* fLocalCoordsVar; 464 465 }; 466 467 #endif 468