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 mValid = false; 74} 75 76static U32 shaderConstTypeSize(GFXShaderConstType type) 77{ 78 switch(type) 79 { 80 case GFXSCT_Float: 81 case GFXSCT_Int: 82 case GFXSCT_Sampler: 83 case GFXSCT_SamplerCube: 84 return 4; 85 case GFXSCT_Float2: 86 case GFXSCT_Int2: 87 return 8; 88 case GFXSCT_Float3: 89 case GFXSCT_Int3: 90 return 12; 91 case GFXSCT_Float4: 92 case GFXSCT_Int4: 93 return 16; 94 case GFXSCT_Float2x2: 95 return 16; 96 case GFXSCT_Float3x3: 97 return 36; 98 case GFXSCT_Float4x3: 99 return 48; 100 case GFXSCT_Float4x4: 101 return 64; 102 default: 103 AssertFatal(false,"shaderConstTypeSize - Unrecognized constant type"); 104 return 0; 105 } 106} 107 108GFXGLShaderConstHandle::GFXGLShaderConstHandle( GFXGLShader *shader, const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ) 109 : mShader(shader), mInstancingConstant(false) 110{ 111 reinit(desc, loc, samplerNum); 112} 113 114void GFXGLShaderConstHandle::reinit( const GFXShaderConstDesc& desc, GLuint loc, S32 samplerNum ) 115{ 116 mDesc = desc; 117 mLocation = loc; 118 mSamplerNum = samplerNum; 119 mOffset = 0; 120 mInstancingConstant = false; 121 122 U32 elemSize = shaderConstTypeSize(mDesc.constType); 123 AssertFatal(elemSize, "GFXGLShaderConst::GFXGLShaderConst - elemSize is 0"); 124 mSize = mDesc.arraySize * elemSize; 125 mValid = true; 126} 127 128 129U32 GFXGLShaderConstHandle::getSize() const 130{ 131 return mSize; 132} 133 134GFXGLShaderConstHandle::~GFXGLShaderConstHandle() 135{ 136} 137 138GFXGLShaderConstBuffer::GFXGLShaderConstBuffer(GFXGLShader* shader, U32 bufSize, U8* existingConstants) 139{ 140 mShader = shader; 141 mBuffer = new U8[bufSize]; 142 mWasLost = true; 143 144 // Copy the existing constant buffer to preserve sampler numbers 145 /// @warning This preserves a lot more than sampler numbers, obviously. If there 146 /// is any code that assumes a new constant buffer will have everything set to 147 /// 0, it will break. 148 dMemcpy(mBuffer, existingConstants, bufSize); 149} 150 151GFXGLShaderConstBuffer::~GFXGLShaderConstBuffer() 152{ 153 delete[] mBuffer; 154 155 if ( mShader ) 156 mShader->_unlinkBuffer( this ); 157} 158 159template<typename ConstType> 160void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const ConstType& param) 161{ 162 AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!" ); 163 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!" ); 164 AssertFatal(dynamic_cast<GFXGLShaderConstHandle*>(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); 165 166 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 167 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 168 U8 *buf = mBuffer + _glHandle->mOffset; 169 170 if(_glHandle->mInstancingConstant) 171 buf = mInstPtr + _glHandle->mOffset; 172 173 dMemcpy(buf, ¶m, sizeof(ConstType)); 174} 175 176void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) 177{ 178 internalSet(handle, fv); 179} 180 181void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2F& fv) 182{ 183 internalSet(handle, fv); 184} 185 186void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3F& fv) 187{ 188 internalSet(handle, fv); 189} 190 191void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4F& fv) 192{ 193 internalSet(handle, fv); 194} 195 196void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const PlaneF& fv) 197{ 198 internalSet(handle, fv); 199} 200 201void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const ColorF& fv) 202{ 203 internalSet(handle, fv); 204} 205 206void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const S32 fv) 207{ 208 internalSet(handle, fv); 209} 210 211void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2I& fv) 212{ 213 internalSet(handle, fv); 214} 215 216void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3I& fv) 217{ 218 internalSet(handle, fv); 219} 220 221void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4I& fv) 222{ 223 internalSet(handle, fv); 224} 225 226template<typename ConstType> 227void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const AlignedArray<ConstType>& fv) 228{ 229 AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!" ); 230 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!" ); 231 AssertFatal(dynamic_cast<GFXGLShaderConstHandle*>(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); 232 233 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 234 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 235 AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for array"); 236 const U8* fvBuffer = static_cast<const U8*>(fv.getBuffer()); 237 for(U32 i = 0; i < fv.size(); ++i) 238 { 239 dMemcpy(mBuffer + _glHandle->mOffset + i * sizeof(ConstType), fvBuffer, sizeof(ConstType)); 240 fvBuffer += fv.getElementSize(); 241 } 242} 243 244void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<F32>& fv) 245{ 246 internalSet(handle, fv); 247} 248 249void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2F>& fv) 250{ 251 internalSet(handle, fv); 252} 253 254void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3F>& fv) 255{ 256 internalSet(handle, fv); 257} 258 259void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4F>& fv) 260{ 261 internalSet(handle, fv); 262} 263 264void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<S32>& fv) 265{ 266 internalSet(handle, fv); 267} 268 269void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2I>& fv) 270{ 271 internalSet(handle, fv); 272} 273 274void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3I>& fv) 275{ 276 internalSet(handle, fv); 277} 278 279void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4I>& fv) 280{ 281 internalSet(handle, fv); 282} 283 284void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matType) 285{ 286 AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!" ); 287 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!" ); 288 AssertFatal(dynamic_cast<GFXGLShaderConstHandle*>(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); 289 290 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 291 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 292 AssertFatal(!_glHandle->mInstancingConstant || matType == GFXSCT_Float4x4, "GFXGLShaderConstBuffer::set - Only support GFXSCT_Float4x4 for instancing"); 293 294 switch(matType) 295 { 296 case GFXSCT_Float2x2: 297 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[0] = mat[0]; 298 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[1] = mat[1]; 299 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[2] = mat[4]; 300 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[3] = mat[5]; 301 break; 302 case GFXSCT_Float3x3: 303 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[0] = mat[0]; 304 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[1] = mat[1]; 305 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[2] = mat[2]; 306 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[3] = mat[4]; 307 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[4] = mat[5]; 308 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[5] = mat[6]; 309 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[6] = mat[8]; 310 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[7] = mat[9]; 311 reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[8] = mat[10]; 312 break; 313 case GFXSCT_Float4x3: 314 dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, (sizeof(F32) * 12));// matrix with end row chopped off 315 break; 316 case GFXSCT_Float4x4: 317 { 318 if(_glHandle->mInstancingConstant) 319 { 320 MatrixF transposed; 321 mat.transposeTo(transposed); 322 dMemcpy( mInstPtr + _glHandle->mOffset, (const F32*)transposed, sizeof(MatrixF) ); 323 return; 324 } 325 326 dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, sizeof(MatrixF)); 327 break; 328 } 329 default: 330 AssertFatal(false, "GFXGLShaderConstBuffer::set - Invalid matrix type"); 331 break; 332 } 333} 334 335void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType) 336{ 337 AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!" ); 338 AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!" ); 339 340 GFXGLShaderConstHandle* _glHandle = static_cast<GFXGLShaderConstHandle*>(handle); 341 AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); 342 AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for matrix arrays"); 343 344 switch (matrixType) { 345 case GFXSCT_Float4x3: 346 // Copy each item with the last row chopped off 347 for (int i = 0; i<arraySize; i++) 348 { 349 dMemcpy(mBuffer + _glHandle->mOffset + (i*(sizeof(F32) * 12)), (F32*)(mat + i), sizeof(F32) * 12); 350 } 351 break; 352 case GFXSCT_Float4x4: 353 dMemcpy(mBuffer + _glHandle->mOffset, (F32*)mat, _glHandle->getSize()); 354 break; 355 default: 356 AssertFatal(false, "GFXGLShaderConstBuffer::set - setting array of non 4x4 matrices!"); 357 break; 358 } 359} 360 361void GFXGLShaderConstBuffer::activate() 362{ 363 PROFILE_SCOPE(GFXGLShaderConstBuffer_activate); 364 mShader->setConstantsFromBuffer(this); 365 mWasLost = false; 366} 367 368const String GFXGLShaderConstBuffer::describeSelf() const 369{ 370 return String(); 371} 372 373void GFXGLShaderConstBuffer::onShaderReload( GFXGLShader *shader ) 374{ 375 AssertFatal( shader == mShader, "GFXGLShaderConstBuffer::onShaderReload, mismatched shaders!" ); 376 377 delete[] mBuffer; 378 mBuffer = new U8[mShader->mConstBufferSize]; 379 dMemset(mBuffer, 0, mShader->mConstBufferSize); 380 mWasLost = true; 381} 382 383GFXGLShader::GFXGLShader() : 384 mVertexShader(0), 385 mPixelShader(0), 386 mProgram(0), 387 mConstBufferSize(0), 388 mConstBuffer(NULL) 389{ 390} 391 392GFXGLShader::~GFXGLShader() 393{ 394 clearShaders(); 395 for(HandleMap::Iterator i = mHandles.begin(); i != mHandles.end(); i++) 396 delete i->value; 397 398 delete[] mConstBuffer; 399} 400 401void GFXGLShader::clearShaders() 402{ 403 glDeleteProgram(mProgram); 404 glDeleteShader(mVertexShader); 405 glDeleteShader(mPixelShader); 406 407 mProgram = 0; 408 mVertexShader = 0; 409 mPixelShader = 0; 410} 411 412bool GFXGLShader::_init() 413{ 414 PROFILE_SCOPE(GFXGLShader_Init); 415 // Don't initialize empty shaders. 416 if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() ) 417 return false; 418 419 clearShaders(); 420 421 mProgram = glCreateProgram(); 422 423 // Set the macros and add the global ones. 424 Vector<GFXShaderMacro> macros; 425 macros.merge( mMacros ); 426 macros.merge( smGlobalMacros ); 427 428 // Add the shader version to the macros. 429 const U32 mjVer = (U32)mFloor( mPixVersion ); 430 const U32 mnVer = (U32)( ( mPixVersion - F32( mjVer ) ) * 10.01f ); 431 macros.increment(); 432 macros.last().name = "TORQUE_SM"; 433 macros.last().value = String::ToString( mjVer * 10 + mnVer ); 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 default: 633 AssertFatal(false, "GFXGLShader::initConstantDescs - unrecognized uniform type"); 634 // If we don't recognize the constant don't add its description. 635 continue; 636 } 637 638 mConstants.push_back(desc); 639 } 640} 641 642void GFXGLShader::initHandles() 643{ 644 // Mark all existing handles as invalid. 645 // Those that are found when parsing the descriptions will then be marked valid again. 646 for ( HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter ) 647 (iter->value)->setValid( false ); 648 mValidHandles.clear(); 649 650 // Loop through all ConstantDescriptions, 651 // if they aren't in the HandleMap add them, if they are reinitialize them. 652 for ( U32 i = 0; i < mConstants.size(); i++ ) 653 { 654 GFXShaderConstDesc &desc = mConstants[i]; 655 656 // Index element 1 of the name to skip the '$' we inserted earier. 657 GLint loc = glGetUniformLocation(mProgram, &desc.name.c_str()[1]); 658 659 AssertFatal(loc != -1, ""); 660 661 HandleMap::Iterator handle = mHandles.find(desc.name); 662 S32 sampler = -1; 663 if(desc.constType == GFXSCT_Sampler || desc.constType == GFXSCT_SamplerCube) 664 { 665 S32 idx = mSamplerNamesOrdered.find_next(desc.name); 666 AssertFatal(idx != -1, ""); 667 sampler = idx; //assignedSamplerNum++; 668 } 669 if ( handle != mHandles.end() ) 670 { 671 handle->value->reinit( desc, loc, sampler ); 672 } 673 else 674 { 675 mHandles[desc.name] = new GFXGLShaderConstHandle( this, desc, loc, sampler ); 676 } 677 } 678 679 // Loop through handles once more to set their offset and calculate our 680 // constBuffer size. 681 682 if ( mConstBuffer ) 683 delete[] mConstBuffer; 684 mConstBufferSize = 0; 685 686 for ( HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter ) 687 { 688 GFXGLShaderConstHandle* handle = iter->value; 689 if ( handle->isValid() ) 690 { 691 mValidHandles.push_back(handle); 692 handle->mOffset = mConstBufferSize; 693 mConstBufferSize += handle->getSize(); 694 } 695 } 696 697 mConstBuffer = new U8[mConstBufferSize]; 698 dMemset(mConstBuffer, 0, mConstBufferSize); 699 700 // Set our program so uniforms are assigned properly. 701 glUseProgram(mProgram); 702 // Iterate through uniforms to set sampler numbers. 703 for (HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter) 704 { 705 GFXGLShaderConstHandle* handle = iter->value; 706 if(handle->isValid() && (handle->getType() == GFXSCT_Sampler || handle->getType() == GFXSCT_SamplerCube)) 707 { 708 // Set sampler number on our program. 709 glUniform1i(handle->mLocation, handle->mSamplerNum); 710 // Set sampler in constant buffer so it does not get unset later. 711 dMemcpy(mConstBuffer + handle->mOffset, &handle->mSamplerNum, handle->getSize()); 712 } 713 } 714 glUseProgram(0); 715 716 //instancing 717 if (!mInstancingFormat) 718 return; 719 720 U32 offset = 0; 721 722 for ( U32 i=0; i < mInstancingFormat->getElementCount(); i++ ) 723 { 724 const GFXVertexElement &element = mInstancingFormat->getElement( i ); 725 726 String constName = String::ToString( "$%s", element.getSemantic().c_str() ); 727 728 HandleMap::Iterator handle = mHandles.find(constName); 729 if ( handle != mHandles.end() ) 730 { 731 AssertFatal(0, ""); 732 } 733 else 734 { 735 GFXShaderConstDesc desc; 736 desc.name = constName; 737 desc.arraySize = 1; 738 switch(element.getType()) 739 { 740 case GFXDeclType_Float4: 741 desc.constType = GFXSCT_Float4; 742 break; 743 744 default: 745 desc.constType = GFXSCT_Float; 746 break; 747 } 748 749 GFXGLShaderConstHandle *h = new GFXGLShaderConstHandle( this, desc, -1, -1 ); 750 h->mInstancingConstant = true; 751 h->mOffset = offset; 752 mHandles[constName] = h; 753 754 offset += element.getSizeInBytes(); 755 ++i; 756 757 // If this is a matrix we will have 2 or 3 more of these 758 // semantics with the same name after it. 759 for ( ; i < mInstancingFormat->getElementCount(); i++ ) 760 { 761 const GFXVertexElement &nextElement = mInstancingFormat->getElement( i ); 762 if ( nextElement.getSemantic() != element.getSemantic() ) 763 { 764 i--; 765 break; 766 } 767 ++desc.arraySize; 768 if(desc.arraySize == 4 && desc.constType == GFXSCT_Float4) 769 { 770 desc.arraySize = 1; 771 desc.constType = GFXSCT_Float4x4; 772 } 773 offset += nextElement.getSizeInBytes(); 774 } 775 } 776 777 } 778} 779 780GFXShaderConstHandle* GFXGLShader::getShaderConstHandle(const String& name) 781{ 782 HandleMap::Iterator i = mHandles.find(name); 783 if(i != mHandles.end()) 784 return i->value; 785 else 786 { 787 GFXGLShaderConstHandle* handle = new GFXGLShaderConstHandle( this ); 788 mHandles[ name ] = handle; 789 790 return handle; 791 } 792} 793 794GFXShaderConstHandle* GFXGLShader::findShaderConstHandle(const String& name) 795{ 796 HandleMap::Iterator i = mHandles.find(name); 797 if(i != mHandles.end()) 798 return i->value; 799 else 800 { 801 return NULL; 802 } 803} 804 805void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer) 806{ 807 for(Vector<GFXGLShaderConstHandle*>::iterator i = mValidHandles.begin(); i != mValidHandles.end(); ++i) 808 { 809 GFXGLShaderConstHandle* handle = *i; 810 AssertFatal(handle, "GFXGLShader::setConstantsFromBuffer - Null handle"); 811 812 if(handle->mInstancingConstant) 813 continue; 814 815 // Don't set if the value has not be changed. 816 if(dMemcmp(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()) == 0) 817 continue; 818 819 // Copy new value into our const buffer and set in GL. 820 dMemcpy(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()); 821 switch(handle->mDesc.constType) 822 { 823 case GFXSCT_Float: 824 glUniform1fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 825 break; 826 case GFXSCT_Float2: 827 glUniform2fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 828 break; 829 case GFXSCT_Float3: 830 glUniform3fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 831 break; 832 case GFXSCT_Float4: 833 glUniform4fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); 834 break; 835 case GFXSCT_Int: 836 case GFXSCT_Sampler: 837 case GFXSCT_SamplerCube: 838 glUniform1iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 839 break; 840 case GFXSCT_Int2: 841 glUniform2iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 842 break; 843 case GFXSCT_Int3: 844 glUniform3iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 845 break; 846 case GFXSCT_Int4: 847 glUniform4iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); 848 break; 849 case GFXSCT_Float2x2: 850 glUniformMatrix2fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 851 break; 852 case GFXSCT_Float3x3: 853 glUniformMatrix3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 854 break; 855 case GFXSCT_Float4x3: 856 // NOTE: To save a transpose here we could store the matrix transposed (i.e. column major) in the constant buffer. 857 // See _mesa_uniform_matrix in the mesa source for the correct transpose algorithm for a 4x3 matrix. 858 glUniformMatrix4x3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 859 break; 860 case GFXSCT_Float4x4: 861 glUniformMatrix4fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); 862 break; 863 default: 864 AssertFatal(0,""); 865 break; 866 } 867 } 868} 869 870GFXShaderConstBufferRef GFXGLShader::allocConstBuffer() 871{ 872 GFXGLShaderConstBuffer* buffer = new GFXGLShaderConstBuffer(this, mConstBufferSize, mConstBuffer); 873 buffer->registerResourceWithDevice(getOwningDevice()); 874 mActiveBuffers.push_back( buffer ); 875 return buffer; 876} 877 878void GFXGLShader::useProgram() 879{ 880 glUseProgram(mProgram); 881} 882 883void GFXGLShader::zombify() 884{ 885 clearShaders(); 886 dMemset(mConstBuffer, 0, mConstBufferSize); 887} 888 889char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) 890{ 891 // TODO: The #line pragma on GLSL takes something called a 892 // "source-string-number" which it then never explains. 893 // 894 // Until i resolve this mystery i disabled this. 895 // 896 //String linePragma = String::ToString( "#line 1 \r\n"); 897 //U32 linePragmaLen = linePragma.length(); 898 899 U32 shaderLen = s->getStreamSize(); 900 char* buffer = (char*)dMalloc(shaderLen + 1); 901 //dStrncpy( buffer, linePragma.c_str(), linePragmaLen ); 902 s->read(shaderLen, buffer); 903 buffer[shaderLen] = 0; 904 905 char* p = dStrstr(buffer, "#include"); 906 while(p) 907 { 908 char* q = p; 909 p += 8; 910 if(dIsspace(*p)) 911 { 912 U32 n = 0; 913 while(dIsspace(*p)) ++p; 914 AssertFatal(*p == '"', "Bad #include directive"); 915 ++p; 916 static char includeFile[256]; 917 while(*p != '"') 918 { 919 AssertFatal(*p != 0, "Bad #include directive"); 920 includeFile[n++] = *p++; 921 AssertFatal(n < sizeof(includeFile), "#include directive too long"); 922 } 923 ++p; 924 includeFile[n] = 0; 925 926 // First try it as a local file. 927 Torque::Path includePath = Torque::Path::Join(path.getPath(), '/', includeFile); 928 includePath = Torque::Path::CompressPath(includePath); 929 930 FileStream includeStream; 931 932 if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) 933 { 934 // Try again assuming the path is absolute 935 // and/or relative. 936 includePath = String( includeFile ); 937 includePath = Torque::Path::CompressPath(includePath); 938 if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) 939 { 940 AssertISV(false, avar("failed to open include '%s'.", includePath.getFullPath().c_str())); 941 942 if ( smLogErrors ) 943 Con::errorf( "GFXGLShader::_handleIncludes - Failed to open include '%s'.", 944 includePath.getFullPath().c_str() ); 945 946 // Fail... don't return the buffer. 947 dFree(buffer); 948 return NULL; 949 } 950 } 951 952 char* includedText = _handleIncludes(includePath, &includeStream); 953 954 // If a sub-include fails... cleanup and return. 955 if ( !includedText ) 956 { 957 dFree(buffer); 958 return NULL; 959 } 960 961 // TODO: Disabled till this is fixed correctly. 962 // 963 // Count the number of lines in the file 964 // before the include. 965 /* 966 U32 includeLine = 0; 967 { 968 char* nl = dStrstr( buffer, "\n" ); 969 while ( nl ) 970 { 971 includeLine++; 972 nl = dStrstr( nl, "\n" ); 973 if(nl) ++nl; 974 } 975 } 976 */ 977 978 String manip(buffer); 979 manip.erase(q-buffer, p-q); 980 String sItx(includedText); 981 982 // TODO: Disabled till this is fixed correctly. 983 // 984 // Add a new line pragma to restore the proper 985 // file and line number after the include. 986 //sItx += String::ToString( "\r\n#line %d \r\n", includeLine ); 987 988 dFree(includedText); 989 manip.insert(q-buffer, sItx); 990 char* manipBuf = dStrdup(manip.c_str()); 991 p = manipBuf + (q - buffer); 992 dFree(buffer); 993 buffer = manipBuf; 994 } 995 p = dStrstr(p, "#include"); 996 } 997 998 return buffer; 999} 1000 1001bool GFXGLShader::_loadShaderFromStream( GLuint shader, 1002 const Torque::Path &path, 1003 FileStream *s, 1004 const Vector<GFXShaderMacro> ¯os ) 1005{ 1006 Vector<char*> buffers; 1007 Vector<U32> lengths; 1008 1009 // The GLSL version declaration must go first! 1010 const char *versionDecl = "#version 150\r\n"; 1011 buffers.push_back( dStrdup( versionDecl ) ); 1012 lengths.push_back( dStrlen( versionDecl ) ); 1013 1014 if(GFXGL->mCapabilities.shaderModel5) 1015 { 1016 const char *extension = "#extension GL_ARB_gpu_shader5 : enable\r\n"; 1017 buffers.push_back( dStrdup( extension ) ); 1018 lengths.push_back( dStrlen( extension ) ); 1019 } 1020 1021 const char *newLine = "\r\n"; 1022 buffers.push_back( dStrdup( newLine ) ); 1023 lengths.push_back( dStrlen( newLine ) ); 1024 1025 // Now add all the macros. 1026 for( U32 i = 0; i < macros.size(); i++ ) 1027 { 1028 if(macros[i].name.isEmpty()) // TODO OPENGL 1029 continue; 1030 1031 String define = String::ToString( "#define %s %s\n", macros[i].name.c_str(), macros[i].value.c_str() ); 1032 buffers.push_back( dStrdup( define.c_str() ) ); 1033 lengths.push_back( define.length() ); 1034 } 1035 1036 // Now finally add the shader source. 1037 U32 shaderLen = s->getStreamSize(); 1038 char *buffer = _handleIncludes(path, s); 1039 if ( !buffer ) 1040 return false; 1041 1042 buffers.push_back(buffer); 1043 lengths.push_back(shaderLen); 1044 1045 glShaderSource(shader, buffers.size(), (const GLchar**)const_cast<const char**>(buffers.address()), NULL); 1046 1047#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) 1048 FileStream stream; 1049 if ( !stream.open( path.getFullPath()+"_DEBUG", Torque::FS::File::Write ) ) 1050 { 1051 AssertISV(false, avar("GFXGLShader::initShader - failed to write debug shader '%s'.", path.getFullPath().c_str())); 1052 } 1053 1054 for(int i = 0; i < buffers.size(); ++i) 1055 stream.writeText(buffers[i]); 1056#endif 1057 1058 // Cleanup the shader source buffer. 1059 for ( U32 i=0; i < buffers.size(); i++ ) 1060 dFree( buffers[i] ); 1061 1062 glCompileShader(shader); 1063 1064 return true; 1065} 1066 1067bool GFXGLShader::initShader( const Torque::Path &file, 1068 bool isVertex, 1069 const Vector<GFXShaderMacro> ¯os ) 1070{ 1071 PROFILE_SCOPE(GFXGLShader_CompileShader); 1072 GLuint activeShader = glCreateShader(isVertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER); 1073 if(isVertex) 1074 mVertexShader = activeShader; 1075 else 1076 mPixelShader = activeShader; 1077 glAttachShader(mProgram, activeShader); 1078 1079 1080 // Ok it's not in the shader gen manager, so ask Torque for it 1081 FileStream stream; 1082 if ( !stream.open( file, Torque::FS::File::Read ) ) 1083 { 1084 AssertISV(false, avar("GFXGLShader::initShader - failed to open shader '%s'.", file.getFullPath().c_str())); 1085 1086 if ( smLogErrors ) 1087 Con::errorf( "GFXGLShader::initShader - Failed to open shader file '%s'.", 1088 file.getFullPath().c_str() ); 1089 1090 return false; 1091 } 1092 1093 if ( !_loadShaderFromStream( activeShader, file, &stream, macros ) ) 1094 return false; 1095 1096 GLint compile; 1097 glGetShaderiv(activeShader, GL_COMPILE_STATUS, &compile); 1098 1099 // Dump the info log to the console 1100 U32 logLength = 0; 1101 glGetShaderiv(activeShader, GL_INFO_LOG_LENGTH, (GLint*)&logLength); 1102 1103 GLint compileStatus = GL_TRUE; 1104 if ( logLength ) 1105 { 1106 FrameAllocatorMarker fam; 1107 char* log = (char*)fam.alloc(logLength); 1108 glGetShaderInfoLog(activeShader, logLength, NULL, log); 1109 1110 // Always print errors 1111 glGetShaderiv( activeShader, GL_COMPILE_STATUS, &compileStatus ); 1112 1113 if ( compileStatus == GL_FALSE ) 1114 { 1115 if ( smLogErrors ) 1116 { 1117 Con::errorf( "GFXGLShader::initShader - Error compiling shader!" ); 1118 Con::errorf( "Program %s: %s", file.getFullPath().c_str(), log ); 1119 } 1120 } 1121 else if ( smLogWarnings ) 1122 Con::warnf( "Program %s: %s", file.getFullPath().c_str(), log ); 1123 } 1124 1125 return compileStatus != GL_FALSE; 1126} 1127 1128/// Returns our list of shader constants, the material can get this and just set the constants it knows about 1129const Vector<GFXShaderConstDesc>& GFXGLShader::getShaderConstDesc() const 1130{ 1131 PROFILE_SCOPE(GFXGLShader_GetShaderConstants); 1132 return mConstants; 1133} 1134 1135/// Returns the alignment value for constType 1136U32 GFXGLShader::getAlignmentValue(const GFXShaderConstType constType) const 1137{ 1138 // Alignment is the same thing as size for us. 1139 return shaderConstTypeSize(constType); 1140} 1141 1142const String GFXGLShader::describeSelf() const 1143{ 1144 String ret; 1145 ret = String::ToString(" Program: %i", mProgram); 1146 ret += String::ToString(" Vertex Path: %s", mVertexFile.getFullPath().c_str()); 1147 ret += String::ToString(" Pixel Path: %s", mPixelFile.getFullPath().c_str()); 1148 1149 return ret; 1150} 1151
