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