gfxGLShader.cpp
Engine/source/gfx/gl/gfxGLShader.cpp
Classes:
Public Defines
define
CHECK_AARG(pos, name) static attr_##name = ->insert(#name); (argName == attr_##name) { glBindAttribLocation(mProgram, pos, attr_##name); continue; }
Public Functions
Detailed Description
Public Defines
CHECK_AARG(pos, name) static attr_##name = ->insert(#name); (argName == attr_##name) { glBindAttribLocation(mProgram, pos, attr_##name); continue; }
Public Functions
shaderConstTypeSize(GFXShaderConstType type)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "gfx/gl/gfxGLShader.h" 26#include "gfx/gl/gfxGLVertexAttribLocation.h" 27#include "gfx/gl/gfxGLDevice.h" 28 29#include "core/frameAllocator.h" 30#include "core/stream/fileStream.h" 31#include "core/strings/stringFunctions.h" 32#include "math/mPoint2.h" 33#include "gfx/gfxStructs.h" 34#include "console/console.h" 35 36#define CHECK_AARG(pos, name) static StringTableEntry attr_##name = StringTable->insert(#name); if (argName == attr_##name) { glBindAttribLocation(mProgram, pos, attr_##name); continue; } 37 38 39class GFXGLShaderConstHandle : public GFXShaderConstHandle 40{ 41 friend class GFXGLShader; 42 43public: 44 45 GFXGLShaderConstHandle( GFXGLShader *shader ); 46 GFXGLShaderConstHandle( GFXGLShader *shader, const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ); 47 virtual ~GFXGLShaderConstHandle(); 48 49 void reinit( const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ); 50 51 const String& getName() const { return mDesc.name; } 52 GFXShaderConstType getType() const { return mDesc.constType; } 53 U32 getArraySize() const { return mDesc.arraySize; } 54 55 U32 getSize() const; 56 void setValid( bool valid ) { mValid = valid; } 57 /// @warning This will always return the value assigned when the shader was 58 /// initialized. If the value is later changed this method won't reflect that. 59 S32 getSamplerRegister() const { return mSamplerNum; } 60 61 GFXShaderConstDesc mDesc; 62 GFXGLShader* mShader; 63 GLuint mLocation; 64 U32 mOffset; 65 U32 mSize; 66 S32 mSamplerNum; 67 bool mInstancingConstant; 68}; 69 70GFXGLShaderConstHandle::GFXGLShaderConstHandle( GFXGLShader *shader ) 71 : mShader( shader ), mLocation(0), mOffset(0), mSize(0), mSamplerNum(-1), mInstancingConstant(false) 72{ 73 dMemset(&mDesc, 0, sizeof(mDesc)); 74 mValid = false; 75} 76 77static U32 shaderConstTypeSize(GFXShaderConstType type) 78{ 79 switch(type) 80 { 81 case GFXSCT_Float: 82 case GFXSCT_Int: 83 case GFXSCT_Sampler: 84 case GFXSCT_SamplerCube: 85 case GFXSCT_SamplerCubeArray: 86 case GFXSCT_SamplerTextureArray: 87 return 4; 88 case GFXSCT_Float2: 89 case GFXSCT_Int2: 90 return 8; 91 case GFXSCT_Float3: 92 case GFXSCT_Int3: 93 return 12; 94 case GFXSCT_Float4: 95 case GFXSCT_Int4: 96 return 16; 97 case GFXSCT_Float2x2: 98 return 16; 99 case GFXSCT_Float3x3: 100 return 36; 101 case GFXSCT_Float4x3: 102 return 48; 103 case GFXSCT_Float4x4: 104 return 64; 105 default: 106 AssertFatal(false,"shaderConstTypeSize - Unrecognized constant type"); 107 return 0; 108 } 109} 110 111GFXGLShaderConstHandle::GFXGLShaderConstHandle( GFXGLShader *shader, const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ) 112 : mShader(shader), mInstancingConstant(false) 113{ 114 reinit(desc, loc, samplerNum); 115} 116 117void GFXGLShaderConstHandle::reinit( const GFXShaderConstDesc& desc, GLuint loc, S32 samplerNum ) 118{ 119 mDesc = desc; 120 mLocation = loc; 121 mSamplerNum = samplerNum; 122 mOffset = 0; 123 mInstancingConstant = false; 124 125 U32 elemSize = shaderConstTypeSize(mDesc.constType); 126 AssertFatal(elemSize, "GFXGLShaderConst::GFXGLShaderConst - elemSize is 0"); 127 mSize = mDesc.arraySize * elemSize; 128 mValid = true; 129} 130 131 132U32 GFXGLShaderConstHandle::getSize() const 133{ 134 return mSize; 135} 136 137GFXGLShaderConstHandle::~GFXGLShaderConstHandle() 138{ 139} 140 141GFXGLShaderConstBuffer::GFXGLShaderConstBuffer(GFXGLShader* shader, U32 bufSize, U8* existingConstants) 142{ 143 mShader = shader; 144 mBuffer = new U8[bufSize]; 145 mWasLost = true; 146 147 // Copy the existing constant buffer to preserve sampler numbers 148 /// @warning This preserves a lot more than sampler numbers, obviously. If there 149 /// is any code that assumes a new constant buffer will have everything set to 150 /// 0, it will break. 151 dMemcpy(mBuffer, existingConstants, bufSize); 152} 153 154GFXGLShaderConstBuffer::~GFXGLShaderConstBuffer() 155{ 156 delete[] mBuffer; 157 158 if ( mShader ) 159 mShader->_unlinkBuffer( this ); 160} 161 162template<typename ConstType> 163void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const ConstType& param) 164{ 165 AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!" ); 166 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!" ); 167 AssertFatal(dynamic_cast<GFXGLShaderConstHandle*>(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); 168 169 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 170 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 171 U8 *buf = mBuffer + _glHandle->mOffset; 172 173 if(_glHandle->mInstancingConstant) 174 buf = mInstPtr + _glHandle->mOffset; 175 176 dMemcpy(buf, ¶m, sizeof(ConstType)); 177} 178 179void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) 180{ 181 internalSet(handle, fv); 182} 183 184void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2F& fv) 185{ 186 internalSet(handle, fv); 187} 188 189void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3F& fv) 190{ 191 internalSet(handle, fv); 192} 193 194void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4F& fv) 195{ 196 internalSet(handle, fv); 197} 198 199void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const PlaneF& fv) 200{ 201 internalSet(handle, fv); 202} 203 204void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const LinearColorF& fv) 205{ 206 internalSet(handle, fv); 207} 208 209void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const S32 fv) 210{ 211 internalSet(handle, fv); 212} 213 214void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2I& fv) 215{ 216 internalSet(handle, fv); 217} 218 219void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3I& fv) 220{ 221 internalSet(handle, fv); 222} 223 224void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4I& fv) 225{ 226 internalSet(handle, fv); 227} 228 229template<typename ConstType> 230void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const AlignedArray<ConstType>& fv) 231{ 232 AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!" ); 233 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!" ); 234 AssertFatal(dynamic_cast<GFXGLShaderConstHandle*>(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); 235 236 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 237 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 238 AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for array"); 239 const U8* fvBuffer = static_cast<const U8*>(fv.getBuffer()); 240 for(U32 i = 0; i < fv.size(); ++i) 241 { 242 dMemcpy(mBuffer + _glHandle->mOffset + i * sizeof(ConstType), fvBuffer, sizeof(ConstType)); 243 fvBuffer += fv.getElementSize(); 244 } 245} 246 247void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<F32>& fv) 248{ 249 internalSet(handle, fv); 250} 251 252void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2F>& fv) 253{ 254 internalSet(handle, fv); 255} 256 257void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3F>& fv) 258{ 259 internalSet(handle, fv); 260} 261 262void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4F>& fv) 263{ 264 internalSet(handle, fv); 265} 266 267void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<S32>& fv) 268{ 269 internalSet(handle, fv); 270} 271 272void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2I>& fv) 273{ 274 internalSet(handle, fv); 275} 276 277void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3I>& fv) 278{ 279 internalSet(handle, fv); 280} 281 282void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4I>& fv) 283{ 284 internalSet(handle, fv); 285} 286 287void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matType) 288{ 289 AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!" ); 290 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!" ); 291 AssertFatal(dynamic_cast<GFXGLShaderConstHandle*>(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); 292 293 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 294 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 295 AssertFatal(!_glHandle->mInstancingConstant || matType == GFXSCT_Float4x4, "GFXGLShaderConstBuffer::set - Only support GFXSCT_Float4x4 for instancing"); 296 297 switch(matType) 298 { 299 case GFXSCT_Float2x2: 300 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[0] = mat[0]; 301 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[1] = mat[1]; 302 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[2] = mat[4]; 303 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[3] = mat[5]; 304 break; 305 case GFXSCT_Float3x3: 306 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[0] = mat[0]; 307 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[1] = mat[1]; 308 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[2] = mat[2]; 309 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[3] = mat[4]; 310 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[4] = mat[5]; 311 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[5] = mat[6]; 312 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[6] = mat[8]; 313 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[7] = mat[9]; 314 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[8] = mat[10]; 315 break; 316 case GFXSCT_Float4x3: 317 dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, (sizeof(F32) * 12));// matrix with end row chopped off 318 break; 319 case GFXSCT_Float4x4: 320 { 321 if(_glHandle->mInstancingConstant) 322 { 323 MatrixF transposed; 324 mat.transposeTo(transposed); 325 dMemcpy( mInstPtr + _glHandle->mOffset, (const F32*)transposed, sizeof(MatrixF) ); 326 return; 327 } 328 329 dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, sizeof(MatrixF)); 330 break; 331 } 332 default: 333 AssertFatal(false, "GFXGLShaderConstBuffer::set - Invalid matrix type"); 334 break; 335 } 336} 337 338void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType) 339{ 340 AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!" ); 341 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!" ); 342 343 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 344 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 345 AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for matrix arrays"); 346 347 switch (matrixType) { 348 case GFXSCT_Float4x3: 349 // Copy each item with the last row chopped off 350 for (int i = 0; i<arraySize; i++) 351 { 352 dMemcpy(mBuffer + _glHandle->mOffset + (i*(sizeof(F32) * 12)), (F32*)(mat + i), sizeof(F32) * 12); 353 } 354 break; 355 case GFXSCT_Float4x4: 356 dMemcpy(mBuffer + _glHandle->mOffset, (F32*)mat, _glHandle->getSize()); 357 break; 358 default: 359 AssertFatal(false, "GFXGLShaderConstBuffer::set - setting array of non 4x4 matrices!"); 360 break; 361 } 362} 363 364void GFXGLShaderConstBuffer::activate() 365{ 366 PROFILE_SCOPE(GFXGLShaderConstBuffer_activate); 367 mShader->setConstantsFromBuffer(this); 368 mWasLost = false; 369} 370 371const String GFXGLShaderConstBuffer::describeSelf() const 372{ 373 return String(); 374} 375 376void GFXGLShaderConstBuffer::onShaderReload( GFXGLShader *shader ) 377{ 378 AssertFatal( shader == mShader, "GFXGLShaderConstBuffer::onShaderReload, mismatched shaders!" ); 379 380 delete[] mBuffer; 381 mBuffer = new U8[mShader->mConstBufferSize]; 382 dMemset(mBuffer, 0, mShader->mConstBufferSize); 383 mWasLost = true; 384} 385 386GFXGLShader::GFXGLShader() : 387 mVertexShader(0), 388 mPixelShader(0), 389 mProgram(0), 390 mConstBufferSize(0), 391 mConstBuffer(NULL) 392{ 393} 394 395GFXGLShader::~GFXGLShader() 396{ 397 clearShaders(); 398 for(HandleMap::Iterator i = mHandles.begin(); i != mHandles.end(); i++) 399 delete i->value; 400 401 delete[] mConstBuffer; 402} 403 404void GFXGLShader::clearShaders() 405{ 406 glDeleteProgram(mProgram); 407 glDeleteShader(mVertexShader); 408 glDeleteShader(mPixelShader); 409 410 mProgram = 0; 411 mVertexShader = 0; 412 mPixelShader = 0; 413} 414 415bool GFXGLShader::_init() 416{ 417 PROFILE_SCOPE(GFXGLShader_Init); 418 // Don't initialize empty shaders. 419 if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() ) 420 return false; 421 422 clearShaders(); 423 424 mProgram = glCreateProgram(); 425 426 // Set the macros and add the global ones. 427 Vector<GFXShaderMacro> macros; 428 macros.merge( mMacros ); 429 macros.merge( smGlobalMacros ); 430 431 macros.increment(); 432 macros.last().name = "TORQUE_SM"; 433 macros.last().value = 40; 434 macros.increment(); 435 macros.last().name = "TORQUE_VERTEX_SHADER"; 436 macros.last().value = ""; 437 438 // Default to true so we're "successful" if a vertex/pixel shader wasn't specified. 439 bool compiledVertexShader = true; 440 bool compiledPixelShader = true; 441 442 // Compile the vertex and pixel shaders if specified. 443 if(!mVertexFile.isEmpty()) 444 compiledVertexShader = initShader(mVertexFile, true, macros); 445 446 macros.last().name = "TORQUE_PIXEL_SHADER"; 447 if(!mPixelFile.isEmpty()) 448 compiledPixelShader = initShader(mPixelFile, false, macros); 449 450 // If either shader was present and failed to compile, bail. 451 if(!compiledVertexShader || !compiledPixelShader) 452 return false; 453 454 // Link it! 455 glLinkProgram( mProgram ); 456 457 GLint activeAttribs = 0; 458 glGetProgramiv(mProgram, GL_ACTIVE_ATTRIBUTES, &activeAttribs ); 459 460 GLint maxLength; 461 glGetProgramiv(mProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength); 462 463 FrameTemp<GLchar> tempData(maxLength+1); 464 *tempData.address() = '\0'; 465 // Check atributes 466 for (U32 i=0; i<activeAttribs; i++) 467 { 468 GLint size; 469 GLenum type; 470 471 glGetActiveAttrib(mProgram, i, maxLength + 1, NULL, &size, &type, tempData.address()); 472 473 StringTableEntry argName = StringTable->insert(tempData.address()); 474 475 CHECK_AARG(Torque::GL_VertexAttrib_Position, vPosition); 476 CHECK_AARG(Torque::GL_VertexAttrib_Normal, vNormal); 477 CHECK_AARG(Torque::GL_VertexAttrib_Color, vColor); 478 CHECK_AARG(Torque::GL_VertexAttrib_Tangent, vTangent); 479 CHECK_AARG(Torque::GL_VertexAttrib_TangentW, vTangentW); 480 CHECK_AARG(Torque::GL_VertexAttrib_Binormal, vBinormal); 481 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord0, vTexCoord0); 482 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord1, vTexCoord1); 483 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord2, vTexCoord2); 484 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord3, vTexCoord3); 485 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord4, vTexCoord4); 486 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord5, vTexCoord5); 487 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord6, vTexCoord6); 488 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord7, vTexCoord7); 489 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord8, vTexCoord8); 490 CHECK_AARG(Torque::GL_VertexAttrib_TexCoord9, vTexCoord9); 491 } 492 493 //always have OUT_col 494 glBindFragDataLocation(mProgram, 0, "OUT_col"); 495 // Check OUT_colN 496 for(U32 i=1;i<4;i++) 497 { 498 char buffer[10]; 499 dSprintf(buffer, sizeof(buffer), "OUT_col%u",i); 500 GLint location = glGetFragDataLocation(mProgram, buffer); 501 if(location>0) 502 glBindFragDataLocation(mProgram, i, buffer); 503 504 } 505 506 // Link it again! 507 glLinkProgram( mProgram ); 508 509 GLint linkStatus; 510 glGetProgramiv( mProgram, GL_LINK_STATUS, &linkStatus ); 511 512 // Dump the info log to the console 513 U32 logLength = 0; 514 glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, (GLint*)&logLength); 515 if ( logLength ) 516 { 517 FrameAllocatorMarker fam; 518 char* log = (char*)fam.alloc( logLength ); 519 glGetProgramInfoLog( mProgram, logLength, NULL, log ); 520 521 if ( linkStatus == GL_FALSE ) 522 { 523 if ( smLogErrors ) 524 { 525 Con::errorf( "GFXGLShader::init - Error linking shader!" ); 526 Con::errorf( "Program %s / %s: %s", 527 mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); 528 } 529 } 530 else if ( smLogWarnings ) 531 { 532 Con::warnf( "Program %s / %s: %s", 533 mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); 534 } 535 } 536 537 538 // If we failed to link, bail. 539 if ( linkStatus == GL_FALSE ) 540 return false; 541 542 initConstantDescs(); 543 initHandles(); 544 545 // Notify Buffers we might have changed in size. 546 // If this was our first init then we won't have any activeBuffers 547 // to worry about unnecessarily calling. 548 Vector<GFXShaderConstBuffer*>::iterator biter = mActiveBuffers.begin(); 549 for ( ; biter != mActiveBuffers.end(); biter++ ) 550 ((GFXGLShaderConstBuffer*)(*biter))->onShaderReload( this ); 551 552 return true; 553} 554 555void GFXGLShader::initConstantDescs() 556{ 557 mConstants.clear(); 558 GLint numUniforms; 559 glGetProgramiv(mProgram, GL_ACTIVE_UNIFORMS, &numUniforms); 560 GLint maxNameLength; 561 glGetProgramiv(mProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); 562 563 if(!maxNameLength) 564 return; 565 566 FrameTemp<GLchar> uniformName(maxNameLength); 567 568 for(U32 i = 0; i < numUniforms; i++) 569 { 570 GLint size; 571 GLenum type; 572 glGetActiveUniform(mProgram, i, maxNameLength, NULL, &size, &type, uniformName); 573 GFXShaderConstDesc desc; 574 575 desc.name = String((char*)uniformName); 576 577 // Remove array brackets from the name 578 desc.name = desc.name.substr(0, desc.name.find('[')); 579 580 // Insert $ to match D3D behavior of having a $ prepended to parameters to main. 581 desc.name.insert(0, '$'); 582 desc.arraySize = size; 583 584 switch(type) 585 { 586 case GL_FLOAT: 587 desc.constType = GFXSCT_Float; 588 break; 589 case GL_FLOAT_VEC2: 590 desc.constType = GFXSCT_Float2; 591 break; 592 case GL_FLOAT_VEC3: 593 desc.constType = GFXSCT_Float3; 594 break; 595 case GL_FLOAT_VEC4: 596 desc.constType = GFXSCT_Float4; 597 break; 598 case GL_INT: 599 desc.constType = GFXSCT_Int; 600 break; 601 case GL_INT_VEC2: 602 desc.constType = GFXSCT_Int2; 603 break; 604 case GL_INT_VEC3: 605 desc.constType = GFXSCT_Int3; 606 break; 607 case GL_INT_VEC4: 608 desc.constType = GFXSCT_Int4; 609 break; 610 case GL_FLOAT_MAT2: 611 desc.constType = GFXSCT_Float2x2; 612 break; 613 case GL_FLOAT_MAT3: 614 desc.constType = GFXSCT_Float3x3; 615 break; 616 case GL_FLOAT_MAT4: 617 desc.constType = GFXSCT_Float4x4; 618 break; 619 case GL_FLOAT_MAT4x3: // jamesu - columns, rows 620 desc.constType = GFXSCT_Float4x3; 621 break; 622 case GL_SAMPLER_1D: 623 case GL_SAMPLER_2D: 624 case GL_SAMPLER_3D: 625 case GL_SAMPLER_1D_SHADOW: 626 case GL_SAMPLER_2D_SHADOW: 627 desc.constType = GFXSCT_Sampler; 628 break; 629 case GL_SAMPLER_CUBE: 630 desc.constType = GFXSCT_SamplerCube; 631 break; 632 case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: 633 desc.constType = GFXSCT_SamplerCubeArray; 634 break; 635 case GL_SAMPLER_2D_ARRAY: 636 desc.constType = GFXSCT_SamplerTextureArray; 637 break; 638 default: 639 AssertFatal(false, "GFXGLShader::initConstantDescs - unrecognized uniform type"); 640 // If we don't recognize the constant don't add its description. 641 continue; 642 } 643 644 mConstants.push_back(desc); 645 } 646} 647 648void GFXGLShader::initHandles() 649{ 650 // Mark all existing handles as invalid. 651 // Those that are found when parsing the descriptions will then be marked valid again. 652 for ( HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter ) 653 (iter->value)->setValid( false ); 654 mValidHandles.clear(); 655 656 // Loop through all ConstantDescriptions, 657 // if they aren't in the HandleMap add them, if they are reinitialize them. 658 for ( U32 i = 0; i < mConstants.size(); i++ ) 659 { 660 GFXShaderConstDesc &desc = mConstants[i]; 661 662 // Index element 1 of the name to skip the '$' we inserted earier. 663 GLint loc = glGetUniformLocation(mProgram, &desc.name.c_str()[1]); 664 665 AssertFatal(loc != -1, ""); 666 667 HandleMap::Iterator handle = mHandles.find(desc.name); 668 S32 sampler = -1; 669 if(desc.constType == GFXSCT_Sampler || 670 desc.constType == GFXSCT_SamplerCube || 671 desc.constType == GFXSCT_SamplerCubeArray || 672 desc.constType == GFXSCT_SamplerTextureArray) 673 { 674 S32 idx = mSamplerNamesOrdered.find_next(desc.name); 675 AssertFatal(idx != -1, ""); 676 sampler = idx; //assignedSamplerNum++; 677 } 678 if ( handle != mHandles.end() ) 679 { 680 handle->value->reinit( desc, loc, sampler ); 681 } 682 else 683 { 684 mHandles[desc.name] = new GFXGLShaderConstHandle( this, desc, loc, sampler ); 685 } 686 } 687 688 // Loop through handles once more to set their offset and calculate our 689 // constBuffer size. 690 691 if ( mConstBuffer ) 692 delete[] mConstBuffer; 693 mConstBufferSize = 0; 694 695 for ( HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter ) 696 { 697 GFXGLShaderConstHandle* handle = iter->value; 698 if ( handle->isValid() ) 699 { 700 mValidHandles.push_back(handle); 701 handle->mOffset = mConstBufferSize; 702 mConstBufferSize += handle->getSize(); 703 } 704 } 705 706 mConstBuffer = new U8[mConstBufferSize]; 707 dMemset(mConstBuffer, 0, mConstBufferSize); 708 709 // Set our program so uniforms are assigned properly. 710 glUseProgram(mProgram); 711 // Iterate through uniforms to set sampler numbers. 712 for (HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter) 713 { 714 GFXGLShaderConstHandle* handle = iter->value; 715 if(handle->isValid() && 716 (handle->getType() == GFXSCT_Sampler || 717 handle->getType() == GFXSCT_SamplerCube || 718 handle->getType() == GFXSCT_SamplerCubeArray || 719 handle->getType() == GFXSCT_SamplerTextureArray)) 720 { 721 // Set sampler number on our program. 722 glUniform1i(handle->mLocation, handle->mSamplerNum); 723 // Set sampler in constant buffer so it does not get unset later. 724 dMemcpy(mConstBuffer + handle->mOffset, &handle->mSamplerNum, handle->getSize()); 725 } 726 } 727 glUseProgram(0); 728 729 //instancing 730 if (!mInstancingFormat) 731 return; 732 733 U32 offset = 0; 734 735 for ( U32 i=0; i < mInstancingFormat->getElementCount(); i++ ) 736 { 737 const GFXVertexElement &element = mInstancingFormat->getElement( i ); 738 739 String constName = String::ToString( "$%s", element.getSemantic().c_str() ); 740 741 HandleMap::Iterator handle = mHandles.find(constName); 742 if ( handle != mHandles.end() ) 743 { 744 AssertFatal(0, ""); 745 } 746 else 747 { 748 GFXShaderConstDesc desc; 749 desc.name = constName; 750 desc.arraySize = 1; 751 switch(element.getType()) 752 { 753 case GFXDeclType_Float4: 754 desc.constType = GFXSCT_Float4; 755 break; 756 757 default: 758 desc.constType = GFXSCT_Float; 759 break; 760 } 761 762 GFXGLShaderConstHandle *h = new GFXGLShaderConstHandle( this, desc, -1, -1 ); 763 h->mInstancingConstant = true; 764 h->mOffset = offset; 765 mHandles[constName] = h; 766 767 offset += element.getSizeInBytes(); 768 ++i; 769 770 // If this is a matrix we will have 2 or 3 more of these 771 // semantics with the same name after it. 772 for ( ; i < mInstancingFormat->getElementCount(); i++ ) 773 { 774 const GFXVertexElement &nextElement = mInstancingFormat->getElement( i ); 775 if ( nextElement.getSemantic() != element.getSemantic() ) 776 { 777 i--; 778 break; 779 } 780 ++desc.arraySize; 781 if(desc.arraySize == 4 && desc.constType == GFXSCT_Float4) 782 { 783 desc.arraySize = 1; 784 desc.constType = GFXSCT_Float4x4; 785 } 786 offset += nextElement.getSizeInBytes(); 787 } 788 } 789 790 } 791} 792 793GFXShaderConstHandle* GFXGLShader::getShaderConstHandle(const String& name) 794{ 795 HandleMap::Iterator i = mHandles.find(name); 796 if(i != mHandles.end()) 797 return i->value; 798 else 799 { 800 GFXGLShaderConstHandle* handle = new GFXGLShaderConstHandle( this ); 801 mHandles[ name ] = handle; 802 803 return handle; 804 } 805} 806 807GFXShaderConstHandle* GFXGLShader::findShaderConstHandle(const String& name) 808{ 809 HandleMap::Iterator i = mHandles.find(name); 810 if(i != mHandles.end()) 811 return i->value; 812 else 813 { 814 return NULL; 815 } 816} 817 818void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer) 819{ 820 for(Vector<GFXGLShaderConstHandle*>::iterator i = mValidHandles.begin(); i != mValidHandles.end(); ++i) 821 { 822 GFXGLShaderConstHandle* handle = *i; 823 AssertFatal(handle, "GFXGLShader::setConstantsFromBuffer - Null handle"); 824 825 if(handle->mInstancingConstant) 826 continue; 827 828 // Don't set if the value has not be changed. 829 if(dMemcmp(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()) == 0) 830 continue; 831 832 // Copy new value into our const buffer and set in GL. 833 dMemcpy(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()); 834 switch(handle->mDesc.constType) 835 { 836 case GFXSCT_Float: 837 glUniform1fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 838 break; 839 case GFXSCT_Float2: 840 glUniform2fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 841 break; 842 case GFXSCT_Float3: 843 glUniform3fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 844 break; 845 case GFXSCT_Float4: 846 glUniform4fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 847 break; 848 case GFXSCT_Int: 849 case GFXSCT_Sampler: 850 case GFXSCT_SamplerCube: 851 case GFXSCT_SamplerCubeArray: 852 case GFXSCT_SamplerTextureArray: 853 glUniform1iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 854 break; 855 case GFXSCT_Int2: 856 glUniform2iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 857 break; 858 case GFXSCT_Int3: 859 glUniform3iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 860 break; 861 case GFXSCT_Int4: 862 glUniform4iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 863 break; 864 case GFXSCT_Float2x2: 865 glUniformMatrix2fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 866 break; 867 case GFXSCT_Float3x3: 868 glUniformMatrix3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 869 break; 870 case GFXSCT_Float4x3: 871 // NOTE: To save a transpose here we could store the matrix transposed (i.e. column major) in the constant buffer. 872 // See _mesa_uniform_matrix in the mesa source for the correct transpose algorithm for a 4x3 matrix. 873 glUniformMatrix4x3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 874 break; 875 case GFXSCT_Float4x4: 876 glUniformMatrix4fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 877 break; 878 default: 879 AssertFatal(0,""); 880 break; 881 } 882 } 883} 884 885GFXShaderConstBufferRef GFXGLShader::allocConstBuffer() 886{ 887 GFXGLShaderConstBuffer* buffer = new GFXGLShaderConstBuffer(this, mConstBufferSize, mConstBuffer); 888 buffer->registerResourceWithDevice(getOwningDevice()); 889 mActiveBuffers.push_back( buffer ); 890 return buffer; 891} 892 893void GFXGLShader::useProgram() 894{ 895 glUseProgram(mProgram); 896} 897 898void GFXGLShader::zombify() 899{ 900 clearShaders(); 901 dMemset(mConstBuffer, 0, mConstBufferSize); 902} 903 904char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) 905{ 906 // TODO: The #line pragma on GLSL takes something called a 907 // "source-string-number" which it then never explains. 908 // 909 // Until i resolve this mystery i disabled this. 910 // 911 //String linePragma = String::ToString( "#line 1 \r\n"); 912 //U32 linePragmaLen = linePragma.length(); 913 914 U32 shaderLen = s->getStreamSize(); 915 char* buffer = (char*)dMalloc(shaderLen + 1); 916 //dStrncpy( buffer, linePragma.c_str(), linePragmaLen ); 917 s->read(shaderLen, buffer); 918 buffer[shaderLen] = 0; 919 920 char* p = dStrstr(buffer, "#include"); 921 while(p) 922 { 923 char* q = p; 924 p += 8; 925 if(dIsspace(*p)) 926 { 927 U32 n = 0; 928 while(dIsspace(*p)) ++p; 929 AssertFatal(*p == '"', "Bad #include directive"); 930 ++p; 931 static char includeFile[256]; 932 while(*p != '"') 933 { 934 AssertFatal(*p != 0, "Bad #include directive"); 935 includeFile[n++] = *p++; 936 AssertFatal(n < sizeof(includeFile), "#include directive too long"); 937 } 938 ++p; 939 includeFile[n] = 0; 940 941 // First try it as a local file. 942 Torque::Path includePath = Torque::Path::Join(path.getPath(), '/', includeFile); 943 includePath = Torque::Path::CompressPath(includePath); 944 945 FileStream includeStream; 946 947 if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) 948 { 949 // Try again assuming the path is absolute 950 // and/or relative. 951 includePath = String( includeFile ); 952 includePath = Torque::Path::CompressPath(includePath); 953 if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) 954 { 955 AssertISV(false, avar("failed to open include '%s'.", includePath.getFullPath().c_str())); 956 957 if ( smLogErrors ) 958 Con::errorf( "GFXGLShader::_handleIncludes - Failed to open include '%s'.", 959 includePath.getFullPath().c_str() ); 960 961 // Fail... don't return the buffer. 962 dFree(buffer); 963 return NULL; 964 } 965 } 966 967 char* includedText = _handleIncludes(includePath, &includeStream); 968 969 // If a sub-include fails... cleanup and return. 970 if ( !includedText ) 971 { 972 dFree(buffer); 973 return NULL; 974 } 975 976 // TODO: Disabled till this is fixed correctly. 977 // 978 // Count the number of lines in the file 979 // before the include. 980 /* 981 U32 includeLine = 0; 982 { 983 char* nl = dStrstr( buffer, "\n" ); 984 while ( nl ) 985 { 986 includeLine++; 987 nl = dStrstr( nl, "\n" ); 988 if(nl) ++nl; 989 } 990 } 991 */ 992 993 String manip(buffer); 994 manip.erase(q-buffer, p-q); 995 String sItx(includedText); 996 997 // TODO: Disabled till this is fixed correctly. 998 // 999 // Add a new line pragma to restore the proper 1000 // file and line number after the include. 1001 //sItx += String::ToString( "\r\n#line %d \r\n", includeLine ); 1002 1003 dFree(includedText); 1004 manip.insert(q-buffer, sItx); 1005 char* manipBuf = dStrdup(manip.c_str()); 1006 p = manipBuf + (q - buffer); 1007 dFree(buffer); 1008 buffer = manipBuf; 1009 } 1010 p = dStrstr(p, "#include"); 1011 } 1012 1013 return buffer; 1014} 1015 1016bool GFXGLShader::_loadShaderFromStream( GLuint shader, 1017 const Torque::Path &path, 1018 FileStream *s, 1019 const Vector<GFXShaderMacro> ¯os ) 1020{ 1021 Vector<char*> buffers; 1022 Vector<U32> lengths; 1023 1024 // The GLSL version declaration must go first! 1025 const char *versionDecl = "#version 330\n"; 1026 buffers.push_back( dStrdup( versionDecl ) ); 1027 lengths.push_back( dStrlen( versionDecl ) ); 1028 1029 //Required extensions. These are already checked when creating the GFX adapter, if we make it this far it's supported 1030 const char* cubeArrayExt = "#extension GL_ARB_texture_cube_map_array : enable\n"; 1031 buffers.push_back(dStrdup(cubeArrayExt)); 1032 lengths.push_back(dStrlen(cubeArrayExt)); 1033 1034 const char* gpuShader5Ext = "#extension GL_ARB_gpu_shader5 : enable\n"; 1035 buffers.push_back(dStrdup(gpuShader5Ext)); 1036 lengths.push_back(dStrlen(gpuShader5Ext)); 1037 1038 const char* newLine = "\r\n"; 1039 buffers.push_back(dStrdup(newLine)); 1040 lengths.push_back(dStrlen(newLine)); 1041 1042 // Now add all the macros. 1043 for( U32 i = 0; i < macros.size(); i++ ) 1044 { 1045 if(macros[i].name.isEmpty()) // TODO OPENGL 1046 continue; 1047 1048 String define = String::ToString( "#define %s %s\n", macros[i].name.c_str(), macros[i].value.c_str() ); 1049 buffers.push_back( dStrdup( define.c_str() ) ); 1050 lengths.push_back( define.length() ); 1051 } 1052 1053 // Now finally add the shader source. 1054 U32 shaderLen = s->getStreamSize(); 1055 char *buffer = _handleIncludes(path, s); 1056 if ( !buffer ) 1057 return false; 1058 1059 buffers.push_back(buffer); 1060 lengths.push_back(shaderLen); 1061 1062 glShaderSource(shader, buffers.size(), (const GLchar**)const_cast<const char**>(buffers.address()), NULL); 1063 1064#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) 1065 FileStream stream; 1066 if ( !stream.open( path.getFullPath()+"_DEBUG", Torque::FS::File::Write ) ) 1067 { 1068 AssertISV(false, avar("GFXGLShader::initShader - failed to write debug shader '%s'.", path.getFullPath().c_str())); 1069 } 1070 1071 for(int i = 0; i < buffers.size(); ++i) 1072 stream.writeText(buffers[i]); 1073#endif 1074 1075 // Cleanup the shader source buffer. 1076 for ( U32 i=0; i < buffers.size(); i++ ) 1077 dFree( buffers[i] ); 1078 1079 glCompileShader(shader); 1080 1081 return true; 1082} 1083 1084bool GFXGLShader::initShader( const Torque::Path &file, 1085 bool isVertex, 1086 const Vector<GFXShaderMacro> ¯os ) 1087{ 1088 PROFILE_SCOPE(GFXGLShader_CompileShader); 1089 GLuint activeShader = glCreateShader(isVertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER); 1090 if(isVertex) 1091 mVertexShader = activeShader; 1092 else 1093 mPixelShader = activeShader; 1094 glAttachShader(mProgram, activeShader); 1095 1096 1097 // Ok it's not in the shader gen manager, so ask Torque for it 1098 FileStream stream; 1099 if ( !stream.open( file, Torque::FS::File::Read ) ) 1100 { 1101 AssertISV(false, avar("GFXGLShader::initShader - failed to open shader '%s'.", file.getFullPath().c_str())); 1102 1103 if ( smLogErrors ) 1104 Con::errorf( "GFXGLShader::initShader - Failed to open shader file '%s'.", 1105 file.getFullPath().c_str() ); 1106 1107 return false; 1108 } 1109 1110 if ( !_loadShaderFromStream( activeShader, file, &stream, macros ) ) 1111 return false; 1112 1113 GLint compile; 1114 glGetShaderiv(activeShader, GL_COMPILE_STATUS, &compile); 1115 1116 // Dump the info log to the console 1117 U32 logLength = 0; 1118 glGetShaderiv(activeShader, GL_INFO_LOG_LENGTH, (GLint*)&logLength); 1119 1120 GLint compileStatus = GL_TRUE; 1121 if ( logLength ) 1122 { 1123 FrameAllocatorMarker fam; 1124 char* log = (char*)fam.alloc(logLength); 1125 glGetShaderInfoLog(activeShader, logLength, NULL, log); 1126 1127 // Always print errors 1128 glGetShaderiv( activeShader, GL_COMPILE_STATUS, &compileStatus ); 1129 1130 if ( compileStatus == GL_FALSE ) 1131 { 1132 if ( smLogErrors ) 1133 { 1134 Con::errorf( "GFXGLShader::initShader - Error compiling shader!" ); 1135 Con::errorf( "Program %s: %s", file.getFullPath().c_str(), log ); 1136 } 1137 } 1138 else if ( smLogWarnings ) 1139 Con::warnf( "Program %s: %s", file.getFullPath().c_str(), log ); 1140 } 1141 1142 return compileStatus != GL_FALSE; 1143} 1144 1145/// Returns our list of shader constants, the material can get this and just set the constants it knows about 1146const Vector<GFXShaderConstDesc>& GFXGLShader::getShaderConstDesc() const 1147{ 1148 PROFILE_SCOPE(GFXGLShader_GetShaderConstants); 1149 return mConstants; 1150} 1151 1152/// Returns the alignment value for constType 1153U32 GFXGLShader::getAlignmentValue(const GFXShaderConstType constType) const 1154{ 1155 // Alignment is the same thing as size for us. 1156 return shaderConstTypeSize(constType); 1157} 1158 1159const String GFXGLShader::describeSelf() const 1160{ 1161 String ret; 1162 ret = String::ToString(" Program: %i", mProgram); 1163 ret += String::ToString(" Vertex Path: %s", mVertexFile.getFullPath().c_str()); 1164 ret += String::ToString(" Pixel Path: %s", mPixelFile.getFullPath().c_str()); 1165 1166 return ret; 1167} 1168