GrGLShaderBuilder.h revision 26e18b593ab65e4d92dfbce92579d8bc180d4c2c
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 20class GrGLContextInfo; 21class GrEffectStage; 22class 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*/ 28class GrGLShaderBuilder { 29public: 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 * Called by GrGLEffects to add code to one of the shaders. 111 */ 112 void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 113 va_list args; 114 va_start(args, format); 115 this->codeAppendf(kVertex_ShaderType, format, args); 116 va_end(args); 117 } 118 119 void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 120 va_list args; 121 va_start(args, format); 122 this->codeAppendf(kGeometry_ShaderType, format, args); 123 va_end(args); 124 } 125 126 void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 127 va_list args; 128 va_start(args, format); 129 this->codeAppendf(kFragment_ShaderType, format, args); 130 va_end(args); 131 } 132 133 void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); } 134 void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); } 135 void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); } 136 137 /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or 138 Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle 139 order of the result depends on the GrTextureAccess associated with the TextureSampler. */ 140 void appendTextureLookup(SkString* out, 141 const TextureSampler&, 142 const char* coordName, 143 GrSLType coordType = kVec2f_GrSLType) const; 144 145 /** Version of above that appends the result to the shader code rather than an SkString. 146 Currently the shader type must be kFragment */ 147 void appendTextureLookup(ShaderType, 148 const TextureSampler&, 149 const char* coordName, 150 GrSLType coordType = kVec2f_GrSLType); 151 152 153 /** Does the work of appendTextureLookup and modulates the result by modulation. The result is 154 always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or 155 float. If modulation is "" or NULL it this function acts as though appendTextureLookup were 156 called. */ 157 void appendTextureLookupAndModulate(ShaderType, 158 const char* modulation, 159 const TextureSampler&, 160 const char* coordName, 161 GrSLType coordType = kVec2f_GrSLType); 162 163 /** Emits a helper function outside of main(). Currently ShaderType must be 164 kFragment_ShaderType. */ 165 void emitFunction(ShaderType shader, 166 GrSLType returnType, 167 const char* name, 168 int argCnt, 169 const GrGLShaderVar* args, 170 const char* body, 171 SkString* outName); 172 173 /** Generates a EffectKey for the shader code based on the texture access parameters and the 174 capabilities of the GL context. This is useful for keying the shader programs that may 175 have multiple representations, based on the type/format of textures used. */ 176 static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&, 177 const GrGLCaps&); 178 179 typedef uint8_t DstReadKey; 180 181 /** Returns a key for adding code to read the copy-of-dst color in service of effects that 182 require reading the dst. It must not return 0 because 0 indicates that there is no dst 183 copy read at all. */ 184 static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&); 185 186 /** If texture swizzling is available using tex parameters then it is preferred over mangling 187 the generated shader code. This potentially allows greater reuse of cached shaders. */ 188 static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps); 189 190 /** Add a uniform variable to the current program, that has visibility in one or more shaders. 191 visibility is a bitfield of ShaderType values indicating from which shaders the uniform 192 should be accessible. At least one bit must be set. Geometry shader uniforms are not 193 supported at this time. The actual uniform name will be mangled. If outName is not NULL then 194 it will refer to the final uniform name after return. Use the addUniformArray variant to add 195 an array of uniforms. 196 */ 197 GrGLUniformManager::UniformHandle addUniform(uint32_t visibility, 198 GrSLType type, 199 const char* name, 200 const char** outName = NULL) { 201 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName); 202 } 203 GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility, 204 GrSLType type, 205 const char* name, 206 int arrayCount, 207 const char** outName = NULL); 208 209 const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const; 210 211 /** 212 * Shortcut for getUniformVariable(u).c_str() 213 */ 214 const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const { 215 return this->getUniformVariable(u).c_str(); 216 } 217 218 /** Add a vertex attribute to the current program that is passed in from the vertex data. 219 Returns false if the attribute was already there, true otherwise. */ 220 bool addAttribute(GrSLType type, const char* name); 221 222 /** Add a varying variable to the current program to pass values between vertex and fragment 223 shaders. If the last two parameters are non-NULL, they are filled in with the name 224 generated. */ 225 void addVarying(GrSLType type, 226 const char* name, 227 const char** vsOutName = NULL, 228 const char** fsInName = NULL); 229 230 /** Returns a variable name that represents the position of the fragment in the FS. The position 231 is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */ 232 const char* fragmentPosition(); 233 234 /** Returns a vertex attribute that represents the vertex position in the VS. This is the 235 pre-matrix position and is commonly used by effects to compute texture coords via a matrix. 236 */ 237 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; } 238 239 /** Returns a vertex attribute that represents the local coords in the VS. This may be the same 240 as positionAttribute() or it may not be. It depends upon whether the rendering code 241 specified explicit local coords or not in the GrDrawState. */ 242 const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; } 243 244 /** Returns the color of the destination pixel. This may be NULL if no effect advertised 245 that it will read the destination. */ 246 const char* dstColor() const; 247 248 /** 249 * Are explicit local coordinates provided as input to the vertex shader. 250 */ 251 bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } 252 253 /** 254 * Interfaces used by GrGLProgram. 255 * TODO: Hide these from the GrEffects using friend or splitting this into two related classes. 256 * Also, GrGLProgram's shader string construction should be moved to this class. 257 */ 258 259 /** Called after building is complete to get the final shader string. */ 260 void getShader(ShaderType, SkString*) const; 261 262 void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; } 263 void setNonStage() { fCurrentStageIdx = kNonStageIdx; } 264 // TODO: move remainder of shader code generation to this class and call this privately 265 // Handles of sampler uniforms generated for the effect are appended to samplerHandles. 266 GrGLEffect* createAndEmitGLEffect( 267 const GrEffectStage& stage, 268 GrBackendEffectFactory::EffectKey key, 269 const char* fsInColor, // NULL means no incoming color 270 const char* fsOutColor, 271 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles); 272 273 GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; } 274 GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const { 275 return fDstCopyTopLeftUniform; 276 } 277 GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const { 278 return fDstCopyScaleUniform; 279 } 280 GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const { 281 return fDstCopySampler.fSamplerUniform; 282 } 283 284 struct AttributePair { 285 void set(int index, const SkString& name) { 286 fIndex = index; fName = name; 287 } 288 int fIndex; 289 SkString fName; 290 }; 291 const SkTArray<AttributePair, true>& getEffectAttributes() const { 292 return fEffectAttributes; 293 } 294 const SkString* getEffectAttributeName(int attributeIndex) const; 295 296 // TODO: Make this do all the compiling, linking, etc. 297 void finished(GrGLuint programID); 298 299 const GrGLContextInfo& ctxInfo() const { return fCtxInfo; } 300 301private: 302 void codeAppendf(ShaderType type, const char format[], va_list args); 303 void codeAppend(ShaderType type, const char* str); 304 305 typedef GrTAllocator<GrGLShaderVar> VarArray; 306 307 void appendDecls(const VarArray&, SkString*) const; 308 void appendUniformDecls(ShaderType, SkString*) const; 309 310 typedef GrGLUniformManager::BuilderUniform BuilderUniform; 311 GrGLUniformManager::BuilderUniformArray fUniforms; 312 313 // TODO: Everything below here private. 314public: 315 316 SkString fHeader; // VS+FS, GLSL version, etc 317 VarArray fVSAttrs; 318 VarArray fVSOutputs; 319 VarArray fGSInputs; 320 VarArray fGSOutputs; 321 VarArray fFSInputs; 322 SkString fGSHeader; // layout qualifiers specific to GS 323 VarArray fFSOutputs; 324 325private: 326 enum { 327 kNonStageIdx = -1, 328 }; 329 330 // Interpretation of DstReadKey when generating code 331 enum { 332 kNoDstRead_DstReadKey = 0, 333 kYesDstRead_DstReadKeyBit = 0x1, // Set if we do a dst-copy-read. 334 kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only. 335 kTopLeftOrigin_DstReadKeyBit = 0x4, // Set if dst-copy origin is top-left. 336 }; 337 338 const GrGLContextInfo& fCtxInfo; 339 GrGLUniformManager& fUniformManager; 340 int fCurrentStageIdx; 341 SkString fFSFunctions; 342 SkString fFSHeader; 343 344 bool fUsesGS; 345 346 SkString fFSCode; 347 SkString fVSCode; 348 SkString fGSCode; 349 350 bool fSetupFragPosition; 351 TextureSampler fDstCopySampler; 352 353 GrGLUniformManager::UniformHandle fRTHeightUniform; 354 GrGLUniformManager::UniformHandle fDstCopyTopLeftUniform; 355 GrGLUniformManager::UniformHandle fDstCopyScaleUniform; 356 357 SkSTArray<10, AttributePair, true> fEffectAttributes; 358 359 GrGLShaderVar* fPositionVar; 360 GrGLShaderVar* fLocalCoordsVar; 361 362}; 363 364#endif 365