1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/gl/GrGLShaderBuilder.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,475 @@ 1.4 +/* 1.5 + * Copyright 2012 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#ifndef GrGLShaderBuilder_DEFINED 1.12 +#define GrGLShaderBuilder_DEFINED 1.13 + 1.14 +#include "GrAllocator.h" 1.15 +#include "GrBackendEffectFactory.h" 1.16 +#include "GrColor.h" 1.17 +#include "GrEffect.h" 1.18 +#include "SkTypes.h" 1.19 +#include "gl/GrGLProgramEffects.h" 1.20 +#include "gl/GrGLSL.h" 1.21 +#include "gl/GrGLUniformManager.h" 1.22 + 1.23 +#include <stdarg.h> 1.24 + 1.25 +class GrGLContextInfo; 1.26 +class GrEffectStage; 1.27 +class GrGLProgramDesc; 1.28 + 1.29 +/** 1.30 + Contains all the incremental state of a shader as it is being built,as well as helpers to 1.31 + manipulate that state. 1.32 +*/ 1.33 +class GrGLShaderBuilder { 1.34 +public: 1.35 + typedef GrTAllocator<GrGLShaderVar> VarArray; 1.36 + typedef GrBackendEffectFactory::EffectKey EffectKey; 1.37 + typedef GrGLProgramEffects::TextureSampler TextureSampler; 1.38 + typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray; 1.39 + typedef GrGLUniformManager::BuilderUniform BuilderUniform; 1.40 + 1.41 + enum ShaderVisibility { 1.42 + kVertex_Visibility = 0x1, 1.43 + kGeometry_Visibility = 0x2, 1.44 + kFragment_Visibility = 0x4, 1.45 + }; 1.46 + 1.47 + GrGLShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); 1.48 + virtual ~GrGLShaderBuilder() {} 1.49 + 1.50 + /** 1.51 + * Use of these features may require a GLSL extension to be enabled. Shaders may not compile 1.52 + * if code is added that uses one of these features without calling enableFeature() 1.53 + */ 1.54 + enum GLSLFeature { 1.55 + kStandardDerivatives_GLSLFeature = 0, 1.56 + 1.57 + kLastGLSLFeature = kStandardDerivatives_GLSLFeature 1.58 + }; 1.59 + 1.60 + /** 1.61 + * If the feature is supported then true is returned and any necessary #extension declarations 1.62 + * are added to the shaders. If the feature is not supported then false will be returned. 1.63 + */ 1.64 + bool enableFeature(GLSLFeature); 1.65 + 1.66 + /** 1.67 + * Called by GrGLEffects to add code the fragment shader. 1.68 + */ 1.69 + void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 1.70 + va_list args; 1.71 + va_start(args, format); 1.72 + fFSCode.appendVAList(format, args); 1.73 + va_end(args); 1.74 + } 1.75 + 1.76 + void fsCodeAppend(const char* str) { fFSCode.append(str); } 1.77 + 1.78 + /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or 1.79 + Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle 1.80 + order of the result depends on the GrTextureAccess associated with the TextureSampler. */ 1.81 + void appendTextureLookup(SkString* out, 1.82 + const TextureSampler&, 1.83 + const char* coordName, 1.84 + GrSLType coordType = kVec2f_GrSLType) const; 1.85 + 1.86 + /** Version of above that appends the result to the fragment shader code instead.*/ 1.87 + void fsAppendTextureLookup(const TextureSampler&, 1.88 + const char* coordName, 1.89 + GrSLType coordType = kVec2f_GrSLType); 1.90 + 1.91 + 1.92 + /** Does the work of appendTextureLookup and modulates the result by modulation. The result is 1.93 + always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or 1.94 + float. If modulation is "" or NULL it this function acts as though appendTextureLookup were 1.95 + called. */ 1.96 + void fsAppendTextureLookupAndModulate(const char* modulation, 1.97 + const TextureSampler&, 1.98 + const char* coordName, 1.99 + GrSLType coordType = kVec2f_GrSLType); 1.100 + 1.101 + /** Emits a helper function outside of main() in the fragment shader. */ 1.102 + void fsEmitFunction(GrSLType returnType, 1.103 + const char* name, 1.104 + int argCnt, 1.105 + const GrGLShaderVar* args, 1.106 + const char* body, 1.107 + SkString* outName); 1.108 + 1.109 + typedef uint8_t DstReadKey; 1.110 + typedef uint8_t FragPosKey; 1.111 + 1.112 + /** Returns a key for adding code to read the copy-of-dst color in service of effects that 1.113 + require reading the dst. It must not return 0 because 0 indicates that there is no dst 1.114 + copy read at all (in which case this function should not be called). */ 1.115 + static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&); 1.116 + 1.117 + /** Returns a key for reading the fragment location. This should only be called if there is an 1.118 + effect that will requires the fragment position. If the fragment position is not required, 1.119 + the key is 0. */ 1.120 + static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&); 1.121 + 1.122 + /** If texture swizzling is available using tex parameters then it is preferred over mangling 1.123 + the generated shader code. This potentially allows greater reuse of cached shaders. */ 1.124 + static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps); 1.125 + 1.126 + /** Add a uniform variable to the current program, that has visibility in one or more shaders. 1.127 + visibility is a bitfield of ShaderVisibility values indicating from which shaders the 1.128 + uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not 1.129 + supported at this time. The actual uniform name will be mangled. If outName is not NULL then 1.130 + it will refer to the final uniform name after return. Use the addUniformArray variant to add 1.131 + an array of uniforms. 1.132 + */ 1.133 + GrGLUniformManager::UniformHandle addUniform(uint32_t visibility, 1.134 + GrSLType type, 1.135 + const char* name, 1.136 + const char** outName = NULL) { 1.137 + return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName); 1.138 + } 1.139 + GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility, 1.140 + GrSLType type, 1.141 + const char* name, 1.142 + int arrayCount, 1.143 + const char** outName = NULL); 1.144 + 1.145 + const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle u) const { 1.146 + return fUniformManager.getBuilderUniform(fUniforms, u).fVariable; 1.147 + } 1.148 + 1.149 + /** 1.150 + * Shortcut for getUniformVariable(u).c_str() 1.151 + */ 1.152 + const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const { 1.153 + return this->getUniformVariable(u).c_str(); 1.154 + } 1.155 + 1.156 + /** 1.157 + * This returns a variable name to access the 2D, perspective correct version of the coords in 1.158 + * the fragment shader. If the coordinates at index are 3-dimensional, it immediately emits a 1.159 + * perspective divide into the fragment shader (xy / z) to convert them to 2D. 1.160 + */ 1.161 + SkString ensureFSCoords2D(const TransformedCoordsArray&, int index); 1.162 + 1.163 + /** Returns a variable name that represents the position of the fragment in the FS. The position 1.164 + is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */ 1.165 + const char* fragmentPosition(); 1.166 + 1.167 + /** Returns the color of the destination pixel. This may be NULL if no effect advertised 1.168 + that it will read the destination. */ 1.169 + const char* dstColor(); 1.170 + 1.171 + /** 1.172 + * Interfaces used by GrGLProgram. 1.173 + */ 1.174 + const GrGLSLExpr4& getInputColor() const { 1.175 + return fInputColor; 1.176 + } 1.177 + const GrGLSLExpr4& getInputCoverage() const { 1.178 + return fInputCoverage; 1.179 + } 1.180 + 1.181 + /** 1.182 + * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for 1.183 + * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key 1.184 + * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and 1.185 + * is updated to be the output color of the last stage. 1.186 + * The handles to texture samplers for effectStage[i] are added to 1.187 + * effectSamplerHandles[i]. 1.188 + */ 1.189 + virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], 1.190 + const EffectKey effectKeys[], 1.191 + int effectCnt, 1.192 + GrGLSLExpr4* inOutFSColor) = 0; 1.193 + 1.194 + const char* getColorOutputName() const; 1.195 + const char* enableSecondaryOutput(); 1.196 + 1.197 + GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; } 1.198 + GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const { 1.199 + return fDstCopyTopLeftUniform; 1.200 + } 1.201 + GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const { 1.202 + return fDstCopyScaleUniform; 1.203 + } 1.204 + GrGLUniformManager::UniformHandle getColorUniform() const { return fColorUniform; } 1.205 + GrGLUniformManager::UniformHandle getCoverageUniform() const { return fCoverageUniform; } 1.206 + GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const { 1.207 + return fDstCopySamplerUniform; 1.208 + } 1.209 + 1.210 + bool finish(GrGLuint* outProgramId); 1.211 + 1.212 + const GrGLContextInfo& ctxInfo() const; 1.213 + 1.214 + /** 1.215 + * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder 1.216 + * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that 1.217 + * our shaders print pretty without effect writers tracking indentation. 1.218 + */ 1.219 + class FSBlock { 1.220 + public: 1.221 + FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) { 1.222 + SkASSERT(NULL != builder); 1.223 + fBuilder->fsCodeAppend("\t{\n"); 1.224 + } 1.225 + 1.226 + ~FSBlock() { 1.227 + fBuilder->fsCodeAppend("\t}\n"); 1.228 + } 1.229 + private: 1.230 + GrGLShaderBuilder* fBuilder; 1.231 + }; 1.232 + 1.233 +protected: 1.234 + GrGpuGL* gpu() const { return fGpu; } 1.235 + 1.236 + void setInputColor(const GrGLSLExpr4& inputColor) { fInputColor = inputColor; } 1.237 + void setInputCoverage(const GrGLSLExpr4& inputCoverage) { fInputCoverage = inputCoverage; } 1.238 + 1.239 + /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */ 1.240 + GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); } 1.241 + 1.242 + // Generates a name for a variable. The generated string will be name prefixed by the prefix 1.243 + // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're 1.244 + // generating stage code. 1.245 + void nameVariable(SkString* out, char prefix, const char* name); 1.246 + 1.247 + // Helper for emitEffects(). 1.248 + void createAndEmitEffects(GrGLProgramEffectsBuilder*, 1.249 + const GrEffectStage* effectStages[], 1.250 + const EffectKey effectKeys[], 1.251 + int effectCnt, 1.252 + GrGLSLExpr4* inOutFSColor); 1.253 + 1.254 + virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const; 1.255 + virtual void bindProgramLocations(GrGLuint programId) const; 1.256 + 1.257 + void appendDecls(const VarArray&, SkString*) const; 1.258 + void appendUniformDecls(ShaderVisibility, SkString*) const; 1.259 + 1.260 +private: 1.261 + class CodeStage : public SkNoncopyable { 1.262 + public: 1.263 + CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} 1.264 + 1.265 + bool inStageCode() const { 1.266 + this->validate(); 1.267 + return NULL != fEffectStage; 1.268 + } 1.269 + 1.270 + const GrEffectStage* effectStage() const { 1.271 + this->validate(); 1.272 + return fEffectStage; 1.273 + } 1.274 + 1.275 + int stageIndex() const { 1.276 + this->validate(); 1.277 + return fCurrentIndex; 1.278 + } 1.279 + 1.280 + class AutoStageRestore : public SkNoncopyable { 1.281 + public: 1.282 + AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) { 1.283 + SkASSERT(NULL != codeStage); 1.284 + fSavedIndex = codeStage->fCurrentIndex; 1.285 + fSavedEffectStage = codeStage->fEffectStage; 1.286 + 1.287 + if (NULL == newStage) { 1.288 + codeStage->fCurrentIndex = -1; 1.289 + } else { 1.290 + codeStage->fCurrentIndex = codeStage->fNextIndex++; 1.291 + } 1.292 + codeStage->fEffectStage = newStage; 1.293 + 1.294 + fCodeStage = codeStage; 1.295 + } 1.296 + ~AutoStageRestore() { 1.297 + fCodeStage->fCurrentIndex = fSavedIndex; 1.298 + fCodeStage->fEffectStage = fSavedEffectStage; 1.299 + } 1.300 + private: 1.301 + CodeStage* fCodeStage; 1.302 + int fSavedIndex; 1.303 + const GrEffectStage* fSavedEffectStage; 1.304 + }; 1.305 + private: 1.306 + void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); } 1.307 + int fNextIndex; 1.308 + int fCurrentIndex; 1.309 + const GrEffectStage* fEffectStage; 1.310 + } fCodeStage; 1.311 + 1.312 + /** 1.313 + * Features that should only be enabled by GrGLShaderBuilder itself. 1.314 + */ 1.315 + enum GLSLPrivateFeature { 1.316 + kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1, 1.317 + kEXTShaderFramebufferFetch_GLSLPrivateFeature, 1.318 + kNVShaderFramebufferFetch_GLSLPrivateFeature, 1.319 + }; 1.320 + bool enablePrivateFeature(GLSLPrivateFeature); 1.321 + 1.322 + // If we ever have VS/GS features we can expand this to take a bitmask of ShaderVisibility and 1.323 + // track the enables separately for each shader. 1.324 + void addFSFeature(uint32_t featureBit, const char* extensionName); 1.325 + 1.326 + // Interpretation of DstReadKey when generating code 1.327 + enum { 1.328 + kNoDstRead_DstReadKey = 0, 1.329 + kYesDstRead_DstReadKeyBit = 0x1, // Set if we do a dst-copy-read. 1.330 + kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only. 1.331 + kTopLeftOrigin_DstReadKeyBit = 0x4, // Set if dst-copy origin is top-left. 1.332 + }; 1.333 + 1.334 + enum { 1.335 + kNoFragPosRead_FragPosKey = 0, // The fragment positition will not be needed. 1.336 + kTopLeftFragPosRead_FragPosKey = 0x1,// Read frag pos relative to top-left. 1.337 + kBottomLeftFragPosRead_FragPosKey = 0x2,// Read frag pos relative to bottom-left. 1.338 + }; 1.339 + 1.340 + GrGpuGL* fGpu; 1.341 + GrGLUniformManager& fUniformManager; 1.342 + uint32_t fFSFeaturesAddedMask; 1.343 + SkString fFSFunctions; 1.344 + SkString fFSExtensions; 1.345 + VarArray fFSInputs; 1.346 + VarArray fFSOutputs; 1.347 + GrGLUniformManager::BuilderUniformArray fUniforms; 1.348 + 1.349 + SkString fFSCode; 1.350 + 1.351 + bool fSetupFragPosition; 1.352 + GrGLUniformManager::UniformHandle fDstCopySamplerUniform; 1.353 + 1.354 + GrGLSLExpr4 fInputColor; 1.355 + GrGLSLExpr4 fInputCoverage; 1.356 + 1.357 + bool fHasCustomColorOutput; 1.358 + bool fHasSecondaryOutput; 1.359 + 1.360 + GrGLUniformManager::UniformHandle fRTHeightUniform; 1.361 + GrGLUniformManager::UniformHandle fDstCopyTopLeftUniform; 1.362 + GrGLUniformManager::UniformHandle fDstCopyScaleUniform; 1.363 + GrGLUniformManager::UniformHandle fColorUniform; 1.364 + GrGLUniformManager::UniformHandle fCoverageUniform; 1.365 + 1.366 + bool fTopLeftFragPosRead; 1.367 +}; 1.368 + 1.369 +//////////////////////////////////////////////////////////////////////////////// 1.370 + 1.371 +class GrGLFullShaderBuilder : public GrGLShaderBuilder { 1.372 +public: 1.373 + GrGLFullShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); 1.374 + 1.375 + /** 1.376 + * Called by GrGLEffects to add code to one of the shaders. 1.377 + */ 1.378 + void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 1.379 + va_list args; 1.380 + va_start(args, format); 1.381 + fVSCode.appendVAList(format, args); 1.382 + va_end(args); 1.383 + } 1.384 + 1.385 + void vsCodeAppend(const char* str) { fVSCode.append(str); } 1.386 + 1.387 + /** Add a vertex attribute to the current program that is passed in from the vertex data. 1.388 + Returns false if the attribute was already there, true otherwise. */ 1.389 + bool addAttribute(GrSLType type, const char* name); 1.390 + 1.391 + /** Add a varying variable to the current program to pass values between vertex and fragment 1.392 + shaders. If the last two parameters are non-NULL, they are filled in with the name 1.393 + generated. */ 1.394 + void addVarying(GrSLType type, 1.395 + const char* name, 1.396 + const char** vsOutName = NULL, 1.397 + const char** fsInName = NULL); 1.398 + 1.399 + /** Returns a vertex attribute that represents the vertex position in the VS. This is the 1.400 + pre-matrix position and is commonly used by effects to compute texture coords via a matrix. 1.401 + */ 1.402 + const GrGLShaderVar& positionAttribute() const { return *fPositionVar; } 1.403 + 1.404 + /** Returns a vertex attribute that represents the local coords in the VS. This may be the same 1.405 + as positionAttribute() or it may not be. It depends upon whether the rendering code 1.406 + specified explicit local coords or not in the GrDrawState. */ 1.407 + const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; } 1.408 + 1.409 + /** 1.410 + * Are explicit local coordinates provided as input to the vertex shader. 1.411 + */ 1.412 + bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } 1.413 + 1.414 + bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name); 1.415 + const SkString* getEffectAttributeName(int attributeIndex) const; 1.416 + 1.417 + virtual GrGLProgramEffects* createAndEmitEffects( 1.418 + const GrEffectStage* effectStages[], 1.419 + const EffectKey effectKeys[], 1.420 + int effectCnt, 1.421 + GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; 1.422 + 1.423 + GrGLUniformManager::UniformHandle getViewMatrixUniform() const { 1.424 + return fViewMatrixUniform; 1.425 + } 1.426 + 1.427 +protected: 1.428 + virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE; 1.429 + virtual void bindProgramLocations(GrGLuint programId) const SK_OVERRIDE; 1.430 + 1.431 +private: 1.432 + const GrGLProgramDesc& fDesc; 1.433 + VarArray fVSAttrs; 1.434 + VarArray fVSOutputs; 1.435 + VarArray fGSInputs; 1.436 + VarArray fGSOutputs; 1.437 + 1.438 + SkString fVSCode; 1.439 + 1.440 + struct AttributePair { 1.441 + void set(int index, const SkString& name) { 1.442 + fIndex = index; fName = name; 1.443 + } 1.444 + int fIndex; 1.445 + SkString fName; 1.446 + }; 1.447 + SkSTArray<10, AttributePair, true> fEffectAttributes; 1.448 + 1.449 + GrGLUniformManager::UniformHandle fViewMatrixUniform; 1.450 + 1.451 + GrGLShaderVar* fPositionVar; 1.452 + GrGLShaderVar* fLocalCoordsVar; 1.453 + 1.454 + typedef GrGLShaderBuilder INHERITED; 1.455 +}; 1.456 + 1.457 +//////////////////////////////////////////////////////////////////////////////// 1.458 + 1.459 +class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder { 1.460 +public: 1.461 + GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); 1.462 + 1.463 + int getNumTexCoordSets() const { return fNumTexCoordSets; } 1.464 + int addTexCoordSets(int count); 1.465 + 1.466 + virtual GrGLProgramEffects* createAndEmitEffects( 1.467 + const GrEffectStage* effectStages[], 1.468 + const EffectKey effectKeys[], 1.469 + int effectCnt, 1.470 + GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; 1.471 + 1.472 +private: 1.473 + int fNumTexCoordSets; 1.474 + 1.475 + typedef GrGLShaderBuilder INHERITED; 1.476 +}; 1.477 + 1.478 +#endif