GrGLShaderBuilder.h revision 0365261597f73c049f2d8c117c8c87ef2fb2c9ab
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 "SkTypes.h" 16#include "gl/GrGLProgramEffects.h" 17#include "gl/GrGLSL.h" 18#include "gl/GrGLUniformManager.h" 19 20#include <stdarg.h> 21 22class GrGLContextInfo; 23class GrEffectStage; 24class GrGLProgramDesc; 25 26/** 27 Contains all the incremental state of a shader as it is being built,as well as helpers to 28 manipulate that state. 29*/ 30class GrGLShaderBuilder { 31public: 32 typedef GrTAllocator<GrGLShaderVar> VarArray; 33 typedef GrBackendEffectFactory::EffectKey EffectKey; 34 typedef GrGLProgramEffects::TextureSampler TextureSampler; 35 typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray; 36 typedef GrGLUniformManager::BuilderUniform BuilderUniform; 37 38 enum ShaderVisibility { 39 kVertex_Visibility = 0x1, 40 kGeometry_Visibility = 0x2, 41 kFragment_Visibility = 0x4, 42 }; 43 44 typedef GrGLUniformManager::UniformHandle UniformHandle; 45 46 // Handles for program uniforms (other than per-effect uniforms) 47 struct UniformHandles { 48 UniformHandle fViewMatrixUni; 49 UniformHandle fRTAdjustmentUni; 50 UniformHandle fColorUni; 51 UniformHandle fCoverageUni; 52 53 // We use the render target height to provide a y-down frag coord when specifying 54 // origin_upper_left is not supported. 55 UniformHandle fRTHeightUni; 56 57 // Uniforms for computing texture coords to do the dst-copy lookup 58 UniformHandle fDstCopyTopLeftUni; 59 UniformHandle fDstCopyScaleUni; 60 UniformHandle fDstCopySamplerUni; 61 }; 62 63 struct GenProgramOutput { 64 GrGLProgramEffects* fColorEffects; 65 GrGLProgramEffects* fCoverageEffects; 66 UniformHandles fUniformHandles; 67 bool fHasVS; 68 int fNumTexCoordSets; 69 GrGLuint fProgramID; 70 }; 71 72 static bool GenProgram(GrGpuGL* gpu, 73 GrGLUniformManager& uman, 74 const GrGLProgramDesc& desc, 75 const GrEffectStage* inColorStages[], 76 const GrEffectStage* inCoverageStages[], 77 GenProgramOutput* output); 78 79 virtual ~GrGLShaderBuilder() {} 80 81 /** 82 * Use of these features may require a GLSL extension to be enabled. Shaders may not compile 83 * if code is added that uses one of these features without calling enableFeature() 84 */ 85 enum GLSLFeature { 86 kStandardDerivatives_GLSLFeature = 0, 87 88 kLastGLSLFeature = kStandardDerivatives_GLSLFeature 89 }; 90 91 /** 92 * If the feature is supported then true is returned and any necessary #extension declarations 93 * are added to the shaders. If the feature is not supported then false will be returned. 94 */ 95 bool enableFeature(GLSLFeature); 96 97 /** 98 * Called by GrGLEffects to add code the fragment shader. 99 */ 100 void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 101 va_list args; 102 va_start(args, format); 103 fFSCode.appendVAList(format, args); 104 va_end(args); 105 } 106 107 void fsCodeAppend(const char* str) { fFSCode.append(str); } 108 109 /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or 110 Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle 111 order of the result depends on the GrTextureAccess associated with the TextureSampler. */ 112 void appendTextureLookup(SkString* out, 113 const TextureSampler&, 114 const char* coordName, 115 GrSLType coordType = kVec2f_GrSLType) const; 116 117 /** Version of above that appends the result to the fragment shader code instead.*/ 118 void fsAppendTextureLookup(const TextureSampler&, 119 const char* coordName, 120 GrSLType coordType = kVec2f_GrSLType); 121 122 123 /** Does the work of appendTextureLookup and modulates the result by modulation. The result is 124 always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or 125 float. If modulation is "" or NULL it this function acts as though appendTextureLookup were 126 called. */ 127 void fsAppendTextureLookupAndModulate(const char* modulation, 128 const TextureSampler&, 129 const char* coordName, 130 GrSLType coordType = kVec2f_GrSLType); 131 132 /** Emits a helper function outside of main() in the fragment shader. */ 133 void fsEmitFunction(GrSLType returnType, 134 const char* name, 135 int argCnt, 136 const GrGLShaderVar* args, 137 const char* body, 138 SkString* outName); 139 140 typedef uint8_t DstReadKey; 141 typedef uint8_t FragPosKey; 142 143 /** Returns a key for adding code to read the copy-of-dst color in service of effects that 144 require reading the dst. It must not return 0 because 0 indicates that there is no dst 145 copy read at all (in which case this function should not be called). */ 146 static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&); 147 148 /** Returns a key for reading the fragment location. This should only be called if there is an 149 effect that will requires the fragment position. If the fragment position is not required, 150 the key is 0. */ 151 static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&); 152 153 /** If texture swizzling is available using tex parameters then it is preferred over mangling 154 the generated shader code. This potentially allows greater reuse of cached shaders. */ 155 static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps); 156 157 /** Add a uniform variable to the current program, that has visibility in one or more shaders. 158 visibility is a bitfield of ShaderVisibility values indicating from which shaders the 159 uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not 160 supported at this time. The actual uniform name will be mangled. If outName is not NULL then 161 it will refer to the final uniform name after return. Use the addUniformArray variant to add 162 an array of uniforms. 163 */ 164 GrGLUniformManager::UniformHandle addUniform(uint32_t visibility, 165 GrSLType type, 166 const char* name, 167 const char** outName = NULL) { 168 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName); 169 } 170 GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility, 171 GrSLType type, 172 const char* name, 173 int arrayCount, 174 const char** outName = NULL); 175 176 const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle u) const { 177 return fUniformManager.getBuilderUniform(fUniforms, u).fVariable; 178 } 179 180 /** 181 * Shortcut for getUniformVariable(u).c_str() 182 */ 183 const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const { 184 return this->getUniformVariable(u).c_str(); 185 } 186 187 /** 188 * This returns a variable name to access the 2D, perspective correct version of the coords in 189 * the fragment shader. If the coordinates at index are 3-dimensional, it immediately emits a 190 * perspective divide into the fragment shader (xy / z) to convert them to 2D. 191 */ 192 SkString ensureFSCoords2D(const TransformedCoordsArray&, int index); 193 194 /** Returns a variable name that represents the position of the fragment in the FS. The position 195 is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */ 196 const char* fragmentPosition(); 197 198 /** Returns the color of the destination pixel. This may be NULL if no effect advertised 199 that it will read the destination. */ 200 const char* dstColor(); 201 202 /** 203 * Interfaces used by GrGLProgram. 204 */ 205 const GrGLSLExpr4& getInputColor() const { 206 return fInputColor; 207 } 208 const GrGLSLExpr4& getInputCoverage() const { 209 return fInputCoverage; 210 } 211 212 /** 213 * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for 214 * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key 215 * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and 216 * is updated to be the output color of the last stage. 217 * The handles to texture samplers for effectStage[i] are added to 218 * effectSamplerHandles[i]. 219 */ 220 virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], 221 const EffectKey effectKeys[], 222 int effectCnt, 223 GrGLSLExpr4* inOutFSColor) = 0; 224 225 const char* getColorOutputName() const; 226 const char* enableSecondaryOutput(); 227 228 GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; } 229 GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const { 230 return fDstCopyTopLeftUniform; 231 } 232 GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const { 233 return fDstCopyScaleUniform; 234 } 235 GrGLUniformManager::UniformHandle getColorUniform() const { return fColorUniform; } 236 GrGLUniformManager::UniformHandle getCoverageUniform() const { return fCoverageUniform; } 237 GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const { 238 return fDstCopySamplerUniform; 239 } 240 241 bool finish(GrGLuint* outProgramId); 242 243 const GrGLContextInfo& ctxInfo() const; 244 245 /** 246 * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder 247 * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that 248 * our shaders print pretty without effect writers tracking indentation. 249 */ 250 class FSBlock { 251 public: 252 FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) { 253 SkASSERT(NULL != builder); 254 fBuilder->fsCodeAppend("\t{\n"); 255 } 256 257 ~FSBlock() { 258 fBuilder->fsCodeAppend("\t}\n"); 259 } 260 private: 261 GrGLShaderBuilder* fBuilder; 262 }; 263 264protected: 265 GrGLShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); 266 267 GrGpuGL* gpu() const { return fGpu; } 268 269 const GrGLProgramDesc& desc() const { return fDesc; } 270 271 void setInputColor(const GrGLSLExpr4& inputColor) { fInputColor = inputColor; } 272 void setInputCoverage(const GrGLSLExpr4& inputCoverage) { fInputCoverage = inputCoverage; } 273 274 /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */ 275 GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); } 276 277 // Generates a name for a variable. The generated string will be name prefixed by the prefix 278 // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're 279 // generating stage code. 280 void nameVariable(SkString* out, char prefix, const char* name); 281 282 // Helper for emitEffects(). 283 void createAndEmitEffects(GrGLProgramEffectsBuilder*, 284 const GrEffectStage* effectStages[], 285 const EffectKey effectKeys[], 286 int effectCnt, 287 GrGLSLExpr4* inOutFSColor); 288 289 virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const; 290 virtual void bindProgramLocations(GrGLuint programId) const; 291 292 void appendDecls(const VarArray&, SkString*) const; 293 void appendUniformDecls(ShaderVisibility, SkString*) const; 294 295private: 296 class CodeStage : SkNoncopyable { 297 public: 298 CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} 299 300 bool inStageCode() const { 301 this->validate(); 302 return NULL != fEffectStage; 303 } 304 305 const GrEffectStage* effectStage() const { 306 this->validate(); 307 return fEffectStage; 308 } 309 310 int stageIndex() const { 311 this->validate(); 312 return fCurrentIndex; 313 } 314 315 class AutoStageRestore : SkNoncopyable { 316 public: 317 AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) { 318 SkASSERT(NULL != codeStage); 319 fSavedIndex = codeStage->fCurrentIndex; 320 fSavedEffectStage = codeStage->fEffectStage; 321 322 if (NULL == newStage) { 323 codeStage->fCurrentIndex = -1; 324 } else { 325 codeStage->fCurrentIndex = codeStage->fNextIndex++; 326 } 327 codeStage->fEffectStage = newStage; 328 329 fCodeStage = codeStage; 330 } 331 ~AutoStageRestore() { 332 fCodeStage->fCurrentIndex = fSavedIndex; 333 fCodeStage->fEffectStage = fSavedEffectStage; 334 } 335 private: 336 CodeStage* fCodeStage; 337 int fSavedIndex; 338 const GrEffectStage* fSavedEffectStage; 339 }; 340 private: 341 void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); } 342 int fNextIndex; 343 int fCurrentIndex; 344 const GrEffectStage* fEffectStage; 345 } fCodeStage; 346 347 bool genProgram(const GrEffectStage* colorStages[], 348 const GrEffectStage* coverageStages[], 349 GenProgramOutput* output); 350 351 /** 352 * Features that should only be enabled by GrGLShaderBuilder itself. 353 */ 354 enum GLSLPrivateFeature { 355 kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1, 356 kEXTShaderFramebufferFetch_GLSLPrivateFeature, 357 kNVShaderFramebufferFetch_GLSLPrivateFeature, 358 }; 359 bool enablePrivateFeature(GLSLPrivateFeature); 360 361 // If we ever have VS/GS features we can expand this to take a bitmask of ShaderVisibility and 362 // track the enables separately for each shader. 363 void addFSFeature(uint32_t featureBit, const char* extensionName); 364 365 // Interpretation of DstReadKey when generating code 366 enum { 367 kNoDstRead_DstReadKey = 0, 368 kYesDstRead_DstReadKeyBit = 0x1, // Set if we do a dst-copy-read. 369 kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only. 370 kTopLeftOrigin_DstReadKeyBit = 0x4, // Set if dst-copy origin is top-left. 371 }; 372 373 enum { 374 kNoFragPosRead_FragPosKey = 0, // The fragment positition will not be needed. 375 kTopLeftFragPosRead_FragPosKey = 0x1,// Read frag pos relative to top-left. 376 kBottomLeftFragPosRead_FragPosKey = 0x2,// Read frag pos relative to bottom-left. 377 }; 378 379 const GrGLProgramDesc& fDesc; 380 GrGpuGL* fGpu; 381 GrGLUniformManager& fUniformManager; 382 uint32_t fFSFeaturesAddedMask; 383 SkString fFSFunctions; 384 SkString fFSExtensions; 385 VarArray fFSInputs; 386 VarArray fFSOutputs; 387 GrGLUniformManager::BuilderUniformArray fUniforms; 388 389 SkString fFSCode; 390 391 bool fSetupFragPosition; 392 GrGLUniformManager::UniformHandle fDstCopySamplerUniform; 393 394 GrGLSLExpr4 fInputColor; 395 GrGLSLExpr4 fInputCoverage; 396 397 bool fHasCustomColorOutput; 398 bool fHasSecondaryOutput; 399 400 GrGLUniformManager::UniformHandle fRTHeightUniform; 401 GrGLUniformManager::UniformHandle fDstCopyTopLeftUniform; 402 GrGLUniformManager::UniformHandle fDstCopyScaleUniform; 403 GrGLUniformManager::UniformHandle fColorUniform; 404 GrGLUniformManager::UniformHandle fCoverageUniform; 405 406 bool fTopLeftFragPosRead; 407}; 408 409//////////////////////////////////////////////////////////////////////////////// 410 411class GrGLFullShaderBuilder : public GrGLShaderBuilder { 412public: 413 GrGLFullShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); 414 415 /** 416 * Called by GrGLEffects to add code to one of the shaders. 417 */ 418 void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 419 va_list args; 420 va_start(args, format); 421 fVSCode.appendVAList(format, args); 422 va_end(args); 423 } 424 425 void vsCodeAppend(const char* str) { fVSCode.append(str); } 426 427 /** Add a vertex attribute to the current program that is passed in from the vertex data. 428 Returns false if the attribute was already there, true otherwise. */ 429 bool addAttribute(GrSLType type, const char* name); 430 431 /** Add a varying variable to the current program to pass values between vertex and fragment 432 shaders. If the last two parameters are non-NULL, they are filled in with the name 433 generated. */ 434 void addVarying(GrSLType type, 435 const char* name, 436 const char** vsOutName = NULL, 437 const char** fsInName = NULL); 438 439 /** Returns a vertex attribute that represents the vertex position in the VS. This is the 440 pre-matrix position and is commonly used by effects to compute texture coords via a matrix. 441 */ 442 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; } 443 444 /** Returns a vertex attribute that represents the local coords in the VS. This may be the same 445 as positionAttribute() or it may not be. It depends upon whether the rendering code 446 specified explicit local coords or not in the GrDrawState. */ 447 const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; } 448 449 /** 450 * Are explicit local coordinates provided as input to the vertex shader. 451 */ 452 bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } 453 454 bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name); 455 const SkString* getEffectAttributeName(int attributeIndex) const; 456 457 virtual GrGLProgramEffects* createAndEmitEffects( 458 const GrEffectStage* effectStages[], 459 const EffectKey effectKeys[], 460 int effectCnt, 461 GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; 462 463 /** 464 * The view matrix uniform is only valid in the VS. It is always mat33. 465 */ 466 GrGLUniformManager::UniformHandle getViewMatrixUniform() const { 467 return fViewMatrixUniform; 468 } 469 470 GrGLUniformManager::UniformHandle getRTAdjustmentVecUniform() const { 471 return fRTAdustmentVecUniform; 472 } 473 474protected: 475 virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE; 476 virtual void bindProgramLocations(GrGLuint programId) const SK_OVERRIDE; 477 478private: 479 VarArray fVSAttrs; 480 VarArray fVSOutputs; 481 VarArray fGSInputs; 482 VarArray fGSOutputs; 483 484 SkString fVSCode; 485 486 struct AttributePair { 487 void set(int index, const SkString& name) { 488 fIndex = index; fName = name; 489 } 490 int fIndex; 491 SkString fName; 492 }; 493 SkSTArray<10, AttributePair, true> fEffectAttributes; 494 495 GrGLUniformManager::UniformHandle fViewMatrixUniform; 496 GrGLUniformManager::UniformHandle fRTAdustmentVecUniform; 497 GrGLShaderVar* fPositionVar; 498 GrGLShaderVar* fLocalCoordsVar; 499 500 typedef GrGLShaderBuilder INHERITED; 501}; 502 503//////////////////////////////////////////////////////////////////////////////// 504 505class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder { 506public: 507 GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); 508 509 int getNumTexCoordSets() const { return fNumTexCoordSets; } 510 int addTexCoordSets(int count); 511 512 virtual GrGLProgramEffects* createAndEmitEffects( 513 const GrEffectStage* effectStages[], 514 const EffectKey effectKeys[], 515 int effectCnt, 516 GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; 517 518private: 519 int fNumTexCoordSets; 520 521 typedef GrGLShaderBuilder INHERITED; 522}; 523 524#endif 525