gfxD3D9Shader.cpp
Engine/source/gfx/D3D9/gfxD3D9Shader.cpp
Classes:
class
D3DXInclude plugin.
Public Variables
Detailed Description
Public Variables
bool gDisassembleAllShaders
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 26#if defined(TORQUE_OS_XENON) 27# include <xtl.h> 28#else 29# include <d3d9.h> 30#endif 31 32#include "gfx/D3D9/gfxD3D9Shader.h" 33#include "gfx/D3D9/gfxD3D9Device.h" 34 35#include "core/frameAllocator.h" 36#include "core/stream/fileStream.h" 37#include "core/util/safeDelete.h" 38#include "console/console.h" 39#include "math/mMathFn.h" 40 41 42using namespace Torque; 43 44extern bool gDisassembleAllShaders; 45 46/// D3DXInclude plugin 47class _gfxD3DXInclude : public ID3DXInclude, public StrongRefBase 48{ 49private: 50 51 Vector<String> mLastPath; 52 53public: 54 55 void setPath( const String &path ) 56 { 57 mLastPath.clear(); 58 mLastPath.push_back( path ); 59 } 60 61 _gfxD3DXInclude() {} 62 virtual ~_gfxD3DXInclude() {} 63 64 STDMETHOD(Close)(THIS_ LPCVOID pData); 65 66 // 360 67 STDMETHOD(Open)(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes, /* OUT */ LPSTR pFullPath, DWORD cbFullPath); 68 69 // PC 70 STDMETHOD(Open)(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) 71 { 72 return Open( IncludeType, pFileName, pParentData, ppData, pBytes, NULL, 0 ); 73 } 74}; 75 76_gfxD3DXIncludeRef GFXD3D9Shader::smD3DXInclude = NULL; 77 78HRESULT _gfxD3DXInclude::Open(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, 79 LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes, 80 LPSTR pFullPath, DWORD cbFullPath) 81{ 82 // First try making the path relative to the parent. 83 Torque::Path path = Torque::Path::Join( mLastPath.last(), '/', pFileName ); 84 path = Torque::Path::CompressPath( path ); 85 86 if ( !Torque::FS::ReadFile( path, (void *&)*ppData, *pBytes, true ) ) 87 { 88 // Ok... now try using the path as is. 89 path = String( pFileName ); 90 path = Torque::Path::CompressPath( path ); 91 92 if ( !Torque::FS::ReadFile( path, (void *&)*ppData, *pBytes, true ) ) 93 { 94 AssertISV(false, avar( "Failed to open include '%s'.", pFileName)); 95 return E_FAIL; 96 } 97 } 98 99 // If the data was of zero size then we cannot recurse 100 // into this file and DX won't call Close() below. 101 // 102 // So in this case don't push on the path. 103 if ( *pBytes > 0 ) 104 mLastPath.push_back( path.getRootAndPath() ); 105 106 return S_OK; 107} 108 109HRESULT _gfxD3DXInclude::Close( THIS_ LPCVOID pData ) 110{ 111 // Free the data file and pop its path off the stack. 112 delete [] (U8*)pData; 113 mLastPath.pop_back(); 114 115 return S_OK; 116} 117 118GFXD3D9ShaderConstHandle::GFXD3D9ShaderConstHandle() 119{ 120 clear(); 121} 122 123const String& GFXD3D9ShaderConstHandle::getName() const 124{ 125 if ( mVertexConstant ) 126 return mVertexHandle.name; 127 else 128 return mPixelHandle.name; 129} 130 131GFXShaderConstType GFXD3D9ShaderConstHandle::getType() const 132{ 133 if ( mVertexConstant ) 134 return mVertexHandle.constType; 135 else 136 return mPixelHandle.constType; 137} 138 139U32 GFXD3D9ShaderConstHandle::getArraySize() const 140{ 141 if ( mVertexConstant ) 142 return mVertexHandle.arraySize; 143 else 144 return mPixelHandle.arraySize; 145} 146 147S32 GFXD3D9ShaderConstHandle::getSamplerRegister() const 148{ 149 if ( !mValid || !isSampler() ) 150 return -1; 151 152 // We always store sampler type and register index in the pixelHandle, 153 // sampler registers are shared between vertex and pixel shaders anyway. 154 155 return mPixelHandle.offset; 156} 157 158//------------------------------------------------------------------------------ 159//------------------------------------------------------------------------------ 160 161 162bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer) 163{ 164 PROFILE_SCOPE(GFXD3D9ShaderBufferLayout_setMatrix); 165 166 if (pd.constType == GFXSCT_Float4x4) 167 { 168 // Special case, we can just blast this guy. 169 AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!"); 170 if (dMemcmp(basePointer+pd.offset, data, size) != 0) 171 { 172 dMemcpy(basePointer+pd.offset, data, size); 173 return true; 174 } 175 176 return false; 177 } 178 else if (pd.constType == GFXSCT_Float4x3) 179 { 180 const U32 csize = 48; 181 182 // Loop through and copy 183 bool ret = false; 184 U8* currDestPointer = basePointer + pd.offset; 185 const U8* currSourcePointer = static_cast<const U8*>(data); 186 const U8* endData = currSourcePointer + size; 187 while (currSourcePointer < endData) 188 { 189#ifdef TORQUE_DOUBLE_CHECK_43MATS 190 Point4F col; 191 ((MatrixF*)currSourcePointer)->getRow(3, &col); 192 AssertFatal(col.x == 0.0f && col.y == 0.0f && col.z == 0.0f && col.w == 1.0f, "3rd row used"); 193#endif 194 195 if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0) 196 { 197 dMemcpy(currDestPointer, currSourcePointer, csize); 198 ret = true; 199 } 200 else if (pd.constType == GFXSCT_Float4x3) 201 { 202 ret = true; 203 } 204 205 currDestPointer += csize; 206 currSourcePointer += sizeof(MatrixF); 207 } 208 209 return ret; 210 } 211 else 212 { 213 PROFILE_SCOPE(GFXD3D9ShaderBufferLayout_setMatrix_not4x4); 214 215 // Figure out how big of a chunk we are copying. We're going to copy 4 columns by N rows of data 216 U32 csize; 217 switch (pd.constType) 218 { 219 case GFXSCT_Float2x2 : 220 csize = 32; 221 break; 222 case GFXSCT_Float3x3 : 223 csize = 48; 224 break; 225 case GFXSCT_Float3x4 : 226 csize = 64; 227 break; 228 default: 229 AssertFatal(false, "Unhandled case!"); 230 return false; 231 break; 232 } 233 234 // Loop through and copy 235 bool ret = false; 236 U8* currDestPointer = basePointer+pd.offset; 237 const U8* currSourcePointer = static_cast<const U8*>(data); 238 const U8* endData = currSourcePointer + size; 239 while (currSourcePointer < endData) 240 { 241 if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0) 242 { 243 dMemcpy(currDestPointer, currSourcePointer, csize); 244 ret = true; 245 } 246 else if (pd.constType == GFXSCT_Float4x3) 247 { 248 ret = true; 249 } 250 251 currDestPointer += csize; 252 currSourcePointer += sizeof(MatrixF); 253 } 254 255 return ret; 256 } 257} 258 259//------------------------------------------------------------------------------ 260GFXD3D9ShaderConstBuffer::GFXD3D9ShaderConstBuffer( GFXD3D9Shader* shader, 261 GFXD3D9ShaderBufferLayout* vertexLayoutF, 262 GFXD3D9ShaderBufferLayout* vertexLayoutI, 263 GFXD3D9ShaderBufferLayout* pixelLayoutF, 264 GFXD3D9ShaderBufferLayout* pixelLayoutI ) 265{ 266 AssertFatal( shader, "GFXD3D9ShaderConstBuffer() - Got a null shader!" ); 267 268 // We hold on to this so we don't have to call 269 // this virtual method during activation. 270 mDevice = static_cast<GFXD3D9Device*>( GFX )->getDevice(); 271 272 mShader = shader; 273 274 // TODO: Remove buffers and layouts that don't exist for performance? 275 276 mVertexConstBufferLayoutF = vertexLayoutF; 277 mVertexConstBufferF = new GenericConstBuffer(vertexLayoutF); 278 mVertexConstBufferLayoutI = vertexLayoutI; 279 mVertexConstBufferI = new GenericConstBuffer(vertexLayoutI); 280 mPixelConstBufferLayoutF = pixelLayoutF; 281 mPixelConstBufferF = new GenericConstBuffer(pixelLayoutF); 282 mPixelConstBufferLayoutI = pixelLayoutI; 283 mPixelConstBufferI = new GenericConstBuffer(pixelLayoutI); 284} 285 286GFXD3D9ShaderConstBuffer::~GFXD3D9ShaderConstBuffer() 287{ 288 SAFE_DELETE(mVertexConstBufferF); 289 SAFE_DELETE(mPixelConstBufferF); 290 SAFE_DELETE(mVertexConstBufferI); 291 SAFE_DELETE(mPixelConstBufferI); 292 293 if ( mShader ) 294 mShader->_unlinkBuffer( this ); 295} 296 297GFXShader* GFXD3D9ShaderConstBuffer::getShader() 298{ 299 return mShader; 300} 301 302// This is kind of cheesy, but I don't think templates would work well here because 303// these functions potentially need to be handled differently by other derived types 304template<class T> 305inline void GFXD3D9ShaderConstBuffer::SET_CONSTANT( GFXShaderConstHandle* handle, const T& fv, GenericConstBuffer *vBuffer, GenericConstBuffer *pBuffer ) 306{ 307 AssertFatal(dynamic_cast<const GFXD3D9ShaderConstHandle*>(handle), "Incorrect const buffer type!"); 308 const GFXD3D9ShaderConstHandle* h = static_cast<const GFXD3D9ShaderConstHandle*>(handle); 309 AssertFatal(h, "Handle is NULL!" ); 310 AssertFatal(h->isValid(), "Handle is not valid!" ); 311 AssertFatal(!h->isSampler(), "Handle is sampler constant!" ); 312 AssertFatal(!mShader.isNull(), "Buffer's shader is null!" ); 313 AssertFatal(!h->mShader.isNull(), "Handle's shader is null!" ); 314 AssertFatal(h->mShader.getPointer() == mShader.getPointer(), "Mismatched shaders!"); 315 if ( h->mInstancingConstant ) 316 { 317 dMemcpy( mInstPtr+h->mPixelHandle.offset, &fv, sizeof( fv ) ); 318 return; 319 } 320 if (h->mVertexConstant) 321 vBuffer->set(h->mVertexHandle, fv); 322 if (h->mPixelConstant) 323 pBuffer->set(h->mPixelHandle, fv); 324} 325 326void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) 327{ 328 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 329} 330 331void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2F& fv) 332{ 333 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 334} 335 336void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3F& fv) 337{ 338 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 339} 340 341void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4F& fv) 342{ 343 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 344} 345 346void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const PlaneF& fv) 347{ 348 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 349} 350 351void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const ColorF& fv) 352{ 353 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 354} 355 356void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const S32 f) 357{ 358 // This is the only type that is allowed to be used 359 // with a sampler shader constant type, but it is only 360 // allowed to be set from GLSL. 361 // 362 // So we ignore it here... all other cases will assert. 363 // 364 if ( ((GFXD3D9ShaderConstHandle*)handle)->isSampler() ) 365 return; 366 367 SET_CONSTANT(handle, f, mVertexConstBufferI, mPixelConstBufferI); 368} 369 370void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2I& fv) 371{ 372 SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI); 373} 374 375void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3I& fv) 376{ 377 SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI); 378} 379 380void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4I& fv) 381{ 382 SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI); 383} 384 385void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<F32>& fv) 386{ 387 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 388} 389 390void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2F>& fv) 391{ 392 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 393} 394 395void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3F>& fv) 396{ 397 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 398} 399 400void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4F>& fv) 401{ 402 SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF); 403} 404 405void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<S32>& fv) 406{ 407 SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI); 408} 409 410void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2I>& fv) 411{ 412 SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI); 413} 414 415void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3I>& fv) 416{ 417 SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI); 418} 419 420void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4I>& fv) 421{ 422 SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI); 423} 424#undef SET_CONSTANT 425 426void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matrixType) 427{ 428 AssertFatal(handle, "Handle is NULL!" ); 429 AssertFatal(handle->isValid(), "Handle is not valid!" ); 430 431 AssertFatal(dynamic_cast<const GFXD3D9ShaderConstHandle*>(handle), "Incorrect const buffer type!"); 432 const GFXD3D9ShaderConstHandle* h = static_cast<const GFXD3D9ShaderConstHandle*>(handle); 433 AssertFatal(!h->isSampler(), "Handle is sampler constant!" ); 434 AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 435 436 MatrixF transposed; 437 if (matrixType == GFXSCT_Float4x3) 438 { 439 transposed = mat; 440 } 441 else 442 { 443 mat.transposeTo(transposed); 444 } 445 446 if (h->mInstancingConstant) 447 { 448 if ( matrixType == GFXSCT_Float4x4 ) 449 dMemcpy( mInstPtr+h->mPixelHandle.offset, mat, sizeof( mat ) ); 450 451 // TODO: Support 3x3 and 2x2 matricies? 452 return; 453 } 454 455 if (h->mVertexConstant) 456 mVertexConstBufferF->set(h->mVertexHandle, transposed, matrixType); 457 if (h->mPixelConstant) 458 mPixelConstBufferF->set(h->mPixelHandle, transposed, matrixType); 459} 460 461void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType) 462{ 463 AssertFatal(handle, "Handle is NULL!" ); 464 AssertFatal(handle->isValid(), "Handle is not valid!" ); 465 466 AssertFatal(dynamic_cast<const GFXD3D9ShaderConstHandle*>(handle), "Incorrect const buffer type!"); 467 const GFXD3D9ShaderConstHandle* h = static_cast<const GFXD3D9ShaderConstHandle*>(handle); 468 AssertFatal(!h->isSampler(), "Handle is sampler constant!" ); 469 AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 470 471 static Vector<MatrixF> transposed; 472 if (arraySize > transposed.size()) 473 transposed.setSize(arraySize); 474 475 if (matrixType == GFXSCT_Float4x3) 476 { 477 dMemcpy(transposed.address(), mat, arraySize * sizeof(MatrixF)); 478 } 479 else 480 { 481 for (U32 i = 0; i < arraySize; i++) 482 mat[i].transposeTo(transposed[i]); 483 } 484 485 // TODO: Maybe support this in the future? 486 if (h->mInstancingConstant) 487 return; 488 489 if (h->mVertexConstant) 490 mVertexConstBufferF->set(h->mVertexHandle, transposed.begin(), arraySize, matrixType); 491 if (h->mPixelConstant) 492 mPixelConstBufferF->set(h->mPixelHandle, transposed.begin(), arraySize, matrixType); 493} 494 495const String GFXD3D9ShaderConstBuffer::describeSelf() const 496{ 497 String ret; 498 ret = String(" GFXD3D9ShaderConstBuffer\n"); 499 500 for (U32 i = 0; i < mVertexConstBufferLayoutF->getParameterCount(); i++) 501 { 502 GenericConstBufferLayout::ParamDesc pd; 503 mVertexConstBufferLayoutF->getDesc(i, pd); 504 505 ret += String::ToString(" Constant name: %s", pd.name.c_str()); 506 } 507 508 return ret; 509} 510 511void GFXD3D9ShaderConstBuffer::zombify() 512{ 513} 514 515void GFXD3D9ShaderConstBuffer::resurrect() 516{ 517} 518 519bool GFXD3D9ShaderConstBuffer::isDirty() 520{ 521 bool ret = mVertexConstBufferF->isDirty(); 522 ret |= mVertexConstBufferI->isDirty(); 523 ret |= mPixelConstBufferF->isDirty(); 524 ret |= mPixelConstBufferI->isDirty(); 525 return ret; 526} 527 528void GFXD3D9ShaderConstBuffer::activate( GFXD3D9ShaderConstBuffer *prevShaderBuffer ) 529{ 530 PROFILE_SCOPE(GFXD3D9ShaderConstBuffer_activate); 531 532 // NOTE: This is a really critical function as it gets 533 // called between every draw call to update the constants. 534 // 535 // Alot of the calls here are inlined... be careful 536 // what you change. 537 538 // If the buffer has changed we need to compare it 539 // with the new buffer to see if we can skip copying 540 // equal buffer content. 541 // 542 // If the buffer hasn't changed then we only will 543 // be copying the changes that have occured since 544 // the last activate call. 545 // 546 if ( prevShaderBuffer != this ) 547 { 548 // If the previous buffer is dirty, than we can't compare 549 // against it, because it hasn't sent its contents to the 550 // card yet and must be copied. 551 if ( prevShaderBuffer && !prevShaderBuffer->isDirty() ) 552 { 553 PROFILE_SCOPE(GFXD3D9ShaderConstBuffer_activate_dirty_check_1); 554 555 // If the buffer content is equal then we set the dirty 556 // flag to false knowing the current state of the card matches 557 // the new buffer. 558 // 559 // If the content is not equal we set the dirty flag to 560 // true which causes the full content of the buffer to be 561 // copied to the card. 562 // 563 mVertexConstBufferF->setDirty( !prevShaderBuffer->mVertexConstBufferF->isEqual( mVertexConstBufferF ) ); 564 mPixelConstBufferF->setDirty( !prevShaderBuffer->mPixelConstBufferF->isEqual( mPixelConstBufferF ) ); 565 mVertexConstBufferI->setDirty( !prevShaderBuffer->mVertexConstBufferF->isEqual( mVertexConstBufferI ) ); 566 mPixelConstBufferI->setDirty( !prevShaderBuffer->mPixelConstBufferF->isEqual( mPixelConstBufferI ) ); 567 } 568 else 569 { 570 // This happens rarely... but it can happen. 571 // 572 // We copy the entire dirty state to the card. 573 574 PROFILE_SCOPE(GFXD3D9ShaderConstBuffer_activate_dirty_check_2); 575 576 mVertexConstBufferF->setDirty( true ); 577 mPixelConstBufferF->setDirty( true ); 578 mVertexConstBufferI->setDirty( true ); 579 mPixelConstBufferI->setDirty( true ); 580 } 581 } 582 583 const U32 bytesToFloat4 = 16; 584 const U32 bytesToInt4 = 16; 585 U32 start, bufferSize; 586 const U8* buf; 587 588 if ( mVertexConstBufferF->isDirty() ) 589 { 590 buf = mVertexConstBufferF->getDirtyBuffer( &start, &bufferSize ); 591 mDevice->SetVertexShaderConstantF( start / bytesToFloat4, (float*)buf, bufferSize / bytesToFloat4 ); 592 } 593 594 if ( mPixelConstBufferF->isDirty() ) 595 { 596 buf = mPixelConstBufferF->getDirtyBuffer( &start, &bufferSize ); 597 mDevice->SetPixelShaderConstantF( start / bytesToFloat4, (float*)buf, bufferSize / bytesToFloat4 ); 598 } 599 600 if ( mVertexConstBufferI->isDirty() ) 601 { 602 buf = mVertexConstBufferI->getDirtyBuffer( &start, &bufferSize ); 603 mDevice->SetVertexShaderConstantI( start / bytesToInt4, (int*)buf, bufferSize / bytesToInt4 ); 604 } 605 606 if ( mPixelConstBufferI->isDirty() ) 607 { 608 buf = mPixelConstBufferI->getDirtyBuffer( &start, &bufferSize ); 609 mDevice->SetPixelShaderConstantI( start / bytesToInt4, (int*)buf, bufferSize / bytesToInt4 ); 610 } 611 612 #ifdef TORQUE_DEBUG 613 614 // Make sure all the constants for this buffer were assigned. 615 if ( mWasLost ) 616 { 617 mVertexConstBufferF->assertUnassignedConstants( mShader->getVertexShaderFile().c_str() ); 618 mVertexConstBufferI->assertUnassignedConstants( mShader->getVertexShaderFile().c_str() ); 619 mPixelConstBufferF->assertUnassignedConstants( mShader->getPixelShaderFile().c_str() ); 620 mPixelConstBufferI->assertUnassignedConstants( mShader->getPixelShaderFile().c_str() ); 621 } 622 623 #endif 624 625 // Clear the lost state. 626 mWasLost = false; 627} 628 629void GFXD3D9ShaderConstBuffer::onShaderReload( GFXD3D9Shader *shader ) 630{ 631 AssertFatal( shader == mShader, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" ); 632 633 SAFE_DELETE( mVertexConstBufferF ); 634 SAFE_DELETE( mPixelConstBufferF ); 635 SAFE_DELETE( mVertexConstBufferI ); 636 SAFE_DELETE( mPixelConstBufferI ); 637 638 AssertFatal( mVertexConstBufferLayoutF == shader->mVertexConstBufferLayoutF, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" ); 639 AssertFatal( mPixelConstBufferLayoutF == shader->mPixelConstBufferLayoutF, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" ); 640 AssertFatal( mVertexConstBufferLayoutI == shader->mVertexConstBufferLayoutI, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" ); 641 AssertFatal( mPixelConstBufferLayoutI == shader->mPixelConstBufferLayoutI, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" ); 642 643 mVertexConstBufferF = new GenericConstBuffer( mVertexConstBufferLayoutF ); 644 mVertexConstBufferI = new GenericConstBuffer( mVertexConstBufferLayoutI ); 645 mPixelConstBufferF = new GenericConstBuffer( mPixelConstBufferLayoutF ); 646 mPixelConstBufferI = new GenericConstBuffer( mPixelConstBufferLayoutI ); 647 648 // Set the lost state. 649 mWasLost = true; 650} 651 652//------------------------------------------------------------------------------ 653 654GFXD3D9Shader::GFXD3D9Shader() 655{ 656 VECTOR_SET_ASSOCIATION( mShaderConsts ); 657 658 mD3D9Device = dynamic_cast<GFXD3D9Device *>(GFX)->getDevice(); 659 AssertFatal(mD3D9Device, "Invalid device for shader."); 660 mVertShader = NULL; 661 mPixShader = NULL; 662 mVertexConstBufferLayoutF = NULL; 663 mPixelConstBufferLayoutF = NULL; 664 mVertexConstBufferLayoutI = NULL; 665 mPixelConstBufferLayoutI = NULL; 666 667 if( smD3DXInclude == NULL ) 668 smD3DXInclude = new _gfxD3DXInclude; 669} 670 671//------------------------------------------------------------------------------ 672 673GFXD3D9Shader::~GFXD3D9Shader() 674{ 675 for (HandleMap::Iterator i = mHandles.begin(); i != mHandles.end(); i++) 676 delete i->value; 677 SAFE_DELETE(mVertexConstBufferLayoutF); 678 SAFE_DELETE(mPixelConstBufferLayoutF); 679 SAFE_DELETE(mVertexConstBufferLayoutI); 680 SAFE_DELETE(mPixelConstBufferLayoutI); 681 SAFE_RELEASE(mVertShader); 682 SAFE_RELEASE(mPixShader); 683} 684 685bool GFXD3D9Shader::_init() 686{ 687 PROFILE_SCOPE( GFXD3D9Shader_Init ); 688 689 if ( mPixVersion > GFX->getPixelShaderVersion() ) 690 { 691 if ( smLogErrors ) 692 Con::errorf( "GFXD3D9Shader::init - Bad pixel shader version!" ); 693 694 return false; 695 } 696 697 if ( mPixVersion < 1.0f && mPixelFile.getFileName().isNotEmpty() ) 698 { 699 if ( smLogErrors ) 700 Con::errorf( "GFXD3D9Shader::init - Pixel shaders not supported on SM %.1f!", mPixVersion ); 701 702 return false; 703 } 704 705 SAFE_RELEASE(mVertShader); 706 SAFE_RELEASE(mPixShader); 707 708 U32 mjVer = (U32)mFloor( mPixVersion ); 709 U32 mnVer = (U32)( ( mPixVersion - F32( mjVer ) ) * 10.01f ); // 10.01 instead of 10.0 because of floating point issues 710 711 String vertTarget = String::ToString("vs_%d_%d", mjVer, mnVer); 712 String pixTarget = String::ToString("ps_%d_%d", mjVer, mnVer); 713 714 // Adjust version for vertex shaders 715 if (mjVer == 2 && mnVer == 1) 716 { 717 pixTarget = "ps_2_a"; 718 vertTarget = "vs_2_0"; 719 } 720 else if ( mjVer == 2 && mnVer == 2 ) 721 { 722 pixTarget = "ps_2_b"; 723 vertTarget = "vs_2_0"; 724 } 725 else if ( ( mPixVersion < 2.0f ) && ( mPixVersion > 1.101f ) ) 726 vertTarget = "vs_1_1"; 727 728 // Create the macro array including the system wide macros. 729 const U32 macroCount = smGlobalMacros.size() + mMacros.size() + 2; 730 FrameTemp<D3DXMACRO> d3dXMacros( macroCount ); 731 for ( U32 i=0; i < smGlobalMacros.size(); i++ ) 732 { 733 d3dXMacros[i].Name = smGlobalMacros[i].name.c_str(); 734 d3dXMacros[i].Definition = smGlobalMacros[i].value.c_str(); 735 } 736 for ( U32 i=0; i < mMacros.size(); i++ ) 737 { 738 d3dXMacros[i+smGlobalMacros.size()].Name = mMacros[i].name.c_str(); 739 d3dXMacros[i+smGlobalMacros.size()].Definition = mMacros[i].value.c_str(); 740 } 741 String smVersion = String::ToString( mjVer * 10 + mnVer ); 742 d3dXMacros[macroCount - 2].Name = "TORQUE_SM"; 743 d3dXMacros[macroCount - 2].Definition = smVersion.c_str(); 744 d3dXMacros[macroCount - 1].Name = NULL; 745 d3dXMacros[macroCount - 1].Definition = NULL; 746 747 if ( !mVertexConstBufferLayoutF ) 748 mVertexConstBufferLayoutF = new GFXD3D9ShaderBufferLayout(); 749 else 750 mVertexConstBufferLayoutF->clear(); 751 752 if ( !mVertexConstBufferLayoutI ) 753 mVertexConstBufferLayoutI = new GFXD3D9ShaderBufferLayout(); 754 else 755 mVertexConstBufferLayoutI->clear(); 756 757 if ( !mPixelConstBufferLayoutF ) 758 mPixelConstBufferLayoutF = new GFXD3D9ShaderBufferLayout(); 759 else 760 mPixelConstBufferLayoutF->clear(); 761 762 if ( !mPixelConstBufferLayoutI ) 763 mPixelConstBufferLayoutI = new GFXD3D9ShaderBufferLayout(); 764 else 765 mPixelConstBufferLayoutI->clear(); 766 767 mSamplerDescriptions.clear(); 768 mShaderConsts.clear(); 769 770 if ( GFXD3DX.isLoaded && !Con::getBoolVariable( "$shaders::forceLoadCSF", false ) ) 771 { 772 if ( !mVertexFile.isEmpty() && 773 !_compileShader( mVertexFile, vertTarget, d3dXMacros, mVertexConstBufferLayoutF, mVertexConstBufferLayoutI, mSamplerDescriptions ) ) 774 return false; 775 776 if ( !mPixelFile.isEmpty() && 777 !_compileShader( mPixelFile, pixTarget, d3dXMacros, mPixelConstBufferLayoutF, mPixelConstBufferLayoutI, mSamplerDescriptions ) ) 778 return false; 779 } 780 else 781 { 782 if ( !_loadCompiledOutput( mVertexFile, vertTarget, mVertexConstBufferLayoutF, mVertexConstBufferLayoutI, mSamplerDescriptions ) ) 783 { 784 if ( smLogErrors ) 785 Con::errorf( "GFXD3D9Shader::init - Unable to load precompiled vertex shader for '%s'.", 786 mVertexFile.getFullPath().c_str() ); 787 788 return false; 789 } 790 791 if ( !_loadCompiledOutput( mPixelFile, pixTarget, mPixelConstBufferLayoutF, mPixelConstBufferLayoutI, mSamplerDescriptions ) ) 792 { 793 if ( smLogErrors ) 794 Con::errorf( "GFXD3D9Shader::init - Unable to load precompiled pixel shader for '%s'.", 795 mPixelFile.getFullPath().c_str() ); 796 797 return false; 798 } 799 } 800 801 // Existing handles are resored to an uninitialized state. 802 // Those that are found when parsing the layout parameters 803 // will then be re-initialized. 804 HandleMap::Iterator iter = mHandles.begin(); 805 for ( ; iter != mHandles.end(); iter++ ) 806 (iter->value)->clear(); 807 808 _buildShaderConstantHandles(mVertexConstBufferLayoutF, true); 809 _buildShaderConstantHandles(mVertexConstBufferLayoutI, true); 810 _buildShaderConstantHandles(mPixelConstBufferLayoutF, false); 811 _buildShaderConstantHandles(mPixelConstBufferLayoutI, false); 812 _buildSamplerShaderConstantHandles( mSamplerDescriptions ); 813 _buildInstancingShaderConstantHandles(); 814 815 // Notify any existing buffers that the buffer 816 // layouts have changed and they need to update. 817 Vector<GFXShaderConstBuffer*>::iterator biter = mActiveBuffers.begin(); 818 for ( ; biter != mActiveBuffers.end(); biter++ ) 819 ((GFXD3D9ShaderConstBuffer*)(*biter))->onShaderReload( this ); 820 821 return true; 822} 823 824bool GFXD3D9Shader::_compileShader( const Torque::Path &filePath, 825 const String& target, 826 const D3DXMACRO *defines, 827 GenericConstBufferLayout* bufferLayoutF, 828 GenericConstBufferLayout* bufferLayoutI, 829 Vector<GFXShaderConstDesc> &samplerDescriptions ) 830{ 831 PROFILE_SCOPE( GFXD3D9Shader_CompileShader ); 832 833 HRESULT res = D3DERR_INVALIDCALL; 834 LPD3DXBUFFER code = NULL; 835 LPD3DXBUFFER errorBuff = NULL; 836 837#ifdef TORQUE_DEBUG 838 U32 flags = D3DXSHADER_DEBUG; 839#else 840 U32 flags = 0; 841#endif 842 843#ifdef TORQUE_OS_XENON 844 flags |= D3DXSHADER_PREFER_FLOW_CONTROL; 845#endif 846 847#ifdef D3DXSHADER_USE_LEGACY_D3DX9_31_DLL 848 if( D3DX_SDK_VERSION >= 32 ) 849 { 850 // will need to use old compiler for 1_1 shaders - check for pixel 851 // or vertex shader with appropriate version. 852 if ((target.compare("vs1", 3) == 0) || (target.compare("vs_1", 4) == 0)) 853 flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL; 854 855 if ((target.compare("ps1", 3) == 0) || (target.compare("ps_1", 4) == 0)) 856 flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL; 857 } 858#endif 859 860#if !defined(TORQUE_OS_XENON) && (D3DX_SDK_VERSION <= 40) 861#error This version of the DirectX SDK is too old. Please install a newer version of the DirectX SDK: http://msdn.microsoft.com/en-us/directx/default.aspx 862#endif 863 864 ID3DXConstantTable* table = NULL; 865 866 static String sHLSLStr( "hlsl" ); 867 static String sOBJStr( "obj" ); 868 869 // Is it an HLSL shader? 870 if ( filePath.getExtension().equal(sHLSLStr, String::NoCase) ) 871 { 872 FrameAllocatorMarker fam; 873 char *buffer = NULL; 874 875 // Set this so that the D3DXInclude::Open will have this 876 // information for relative paths. 877 smD3DXInclude->setPath( filePath.getRootAndPath() ); 878 879 FileStream s; 880 if ( !s.open( filePath, Torque::FS::File::Read ) ) 881 { 882 AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str())); 883 884 if ( smLogErrors ) 885 Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", 886 filePath.getFullPath().c_str() ); 887 888 return false; 889 } 890 891 // Convert the path which might have virtualized 892 // mount paths to a real file system path. 893 Torque::Path realPath; 894 if ( !FS::GetFSPath( filePath, realPath ) ) 895 realPath = filePath; 896 897 // Add a #line pragma so that error and warning messages 898 // returned by the HLSL compiler report the right file. 899 String linePragma = String::ToString( "#line 1 \"%s\"\r\n", realPath.getFullPath().c_str() ); 900 U32 linePragmaLen = linePragma.length(); 901 902 U32 bufSize = s.getStreamSize(); 903 buffer = (char *)fam.alloc( bufSize + linePragmaLen + 1 ); 904 dStrncpy( buffer, linePragma.c_str(), linePragmaLen ); 905 s.read( bufSize, buffer + linePragmaLen ); 906 buffer[bufSize+linePragmaLen] = 0; 907 908 res = GFXD3DX.D3DXCompileShader( buffer, bufSize + linePragmaLen, defines, smD3DXInclude, "main", 909 target, flags, &code, &errorBuff, &table ); 910 } 911 912 // Is it a precompiled obj shader? 913 else if ( filePath.getExtension().equal( sOBJStr, String::NoCase ) ) 914 { 915 FileStream s; 916 if(!s.open(filePath, Torque::FS::File::Read)) 917 { 918 AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str())); 919 920 if ( smLogErrors ) 921 Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", 922 filePath.getFullPath().c_str() ); 923 924 return false; 925 } 926 927 res = GFXD3DX.D3DXCreateBuffer(s.getStreamSize(), &code); 928 AssertISV(res == D3D_OK, "Unable to create buffer!"); 929 s.read(s.getStreamSize(), code->GetBufferPointer()); 930 931 if (res == D3D_OK) 932 { 933 DWORD* data = (DWORD*) code->GetBufferPointer(); 934 res = GFXD3DX.D3DXGetShaderConstantTable(data, &table); 935 } 936 } 937 else 938 { 939 if ( smLogErrors ) 940 Con::errorf( "GFXD3D9Shader::_compileShader - Unsupported shader file type '%s'.", 941 filePath.getFullPath().c_str() ); 942 943 return false; 944 } 945 946 if ( res != D3D_OK && smLogErrors ) 947 Con::errorf( "GFXD3D9Shader::_compileShader - Error compiling shader: %s: %s (%x)", 948 DXGetErrorStringA(res), DXGetErrorDescriptionA(res), res ); 949 950 if ( errorBuff ) 951 { 952 // remove \n at end of buffer 953 U8 *buffPtr = (U8*) errorBuff->GetBufferPointer(); 954 U32 len = dStrlen( (const char*) buffPtr ); 955 buffPtr[len-1] = '\0'; 956 957 if( res != D3D_OK ) 958 { 959 if ( smLogErrors ) 960 Con::errorf( " %s", (const char*) errorBuff->GetBufferPointer() ); 961 } 962 else 963 { 964 if ( smLogWarnings ) 965 Con::warnf( "%s", (const char*) errorBuff->GetBufferPointer() ); 966 } 967 } 968 else if ( code == NULL && smLogErrors ) 969 Con::errorf( "GFXD3D9Shader::_compileShader - no compiled code produced; possibly missing file '%s'.", 970 filePath.getFullPath().c_str() ); 971 972 // Create the proper shader if we have code 973 if( code != NULL ) 974 { 975 #ifndef TORQUE_SHIPPING 976 977 LPD3DXBUFFER disassem = NULL; 978 D3DXDisassembleShader( (DWORD*)code->GetBufferPointer(), false, NULL, &disassem ); 979 mDissasembly = (const char*)disassem->GetBufferPointer(); 980 SAFE_RELEASE( disassem ); 981 982 if ( gDisassembleAllShaders ) 983 { 984 String filename = filePath.getFullPath(); 985 filename.replace( ".hlsl", "_dis.txt" ); 986 987 FileStream *fstream = FileStream::createAndOpen( filename, Torque::FS::File::Write ); 988 if ( fstream ) 989 { 990 fstream->write( mDissasembly ); 991 fstream->close(); 992 delete fstream; 993 } 994 } 995 996 #endif 997 998 if (target.compare("ps_", 3) == 0) 999 res = mD3D9Device->CreatePixelShader( (DWORD*)code->GetBufferPointer(), &mPixShader ); 1000 else 1001 res = mD3D9Device->CreateVertexShader( (DWORD*)code->GetBufferPointer(), &mVertShader ); 1002 1003 if (res == S_OK) 1004 _getShaderConstants(table, bufferLayoutF, bufferLayoutI, samplerDescriptions); 1005 1006#ifdef TORQUE_ENABLE_CSF_GENERATION 1007 1008 // Ok, we've got a valid shader and constants, let's write them all out. 1009 if ( !_saveCompiledOutput(filePath, code, bufferLayoutF, bufferLayoutI) && smLogErrors ) 1010 Con::errorf( "GFXD3D9Shader::_compileShader - Unable to save shader compile output for: %s", 1011 filePath.getFullPath().c_str() ); 1012 1013#endif 1014 1015 SAFE_RELEASE(table); 1016 1017 if ( res != S_OK && smLogErrors ) 1018 Con::errorf( "GFXD3D9Shader::_compileShader - Unable to create shader for '%s'.", 1019 filePath.getFullPath().c_str() ); 1020 } 1021 1022 bool result = code != NULL && res == S_OK; 1023 1024 SAFE_RELEASE( code ); 1025 SAFE_RELEASE( errorBuff ); 1026 1027 return result; 1028} 1029 1030void GFXD3D9Shader::_getShaderConstants( ID3DXConstantTable *table, 1031 GenericConstBufferLayout *bufferLayoutF, 1032 GenericConstBufferLayout* bufferLayoutI, 1033 Vector<GFXShaderConstDesc> &samplerDescriptions ) 1034{ 1035 PROFILE_SCOPE( GFXD3D9Shader_GetShaderConstants ); 1036 1037 AssertFatal(table, "NULL constant table not allowed, is this an assembly shader?"); 1038 1039 D3DXCONSTANTTABLE_DESC tableDesc; 1040 D3D9Assert(table->GetDesc(&tableDesc), "Unable to get constant table info."); 1041 1042 for (U32 i = 0; i < tableDesc.Constants; i++) 1043 { 1044 D3DXHANDLE handle = table->GetConstant(0, i); 1045 const U32 descSize=16; 1046 D3DXCONSTANT_DESC constantDescArray[descSize]; 1047 U32 size = descSize; 1048 if (table->GetConstantDesc(handle, constantDescArray, &size) == S_OK) 1049 { 1050 D3DXCONSTANT_DESC& constantDesc = constantDescArray[0]; 1051 GFXShaderConstDesc desc; 1052 1053 desc.name = String(constantDesc.Name); 1054 // Prepend a "$" if it doesn't exist. Just to make things consistent. 1055 if (desc.name.find("$") != 0) 1056 desc.name = String::ToString("$%s", desc.name.c_str()); 1057 //Con::printf("name %s: , offset: %d, size: %d, constantDesc.Elements: %d", desc.name.c_str(), constantDesc.RegisterIndex, constantDesc.Bytes, constantDesc.Elements); 1058 desc.arraySize = constantDesc.Elements; 1059 1060 GenericConstBufferLayout* bufferLayout = NULL; 1061 switch (constantDesc.RegisterSet) 1062 { 1063 case D3DXRS_INT4 : 1064 { 1065 bufferLayout = bufferLayoutI; 1066 switch (constantDesc.Class) 1067 { 1068 case D3DXPC_SCALAR : 1069 desc.constType = GFXSCT_Int; 1070 break; 1071 case D3DXPC_VECTOR : 1072 { 1073 switch (constantDesc.Columns) 1074 { 1075 case 1 : 1076 desc.constType = GFXSCT_Int; 1077 break; 1078 case 2 : 1079 desc.constType = GFXSCT_Int2; 1080 break; 1081 case 3 : 1082 desc.constType = GFXSCT_Int3; 1083 break; 1084 case 4 : 1085 desc.constType = GFXSCT_Int4; 1086 break; 1087 default: 1088 AssertFatal(false, "Unknown int vector type!"); 1089 break; 1090 } 1091 } 1092 break; 1093 } 1094 desc.constType = GFXSCT_Int4; 1095 break; 1096 } 1097 case D3DXRS_FLOAT4 : 1098 { 1099 bufferLayout = bufferLayoutF; 1100 switch (constantDesc.Class) 1101 { 1102 case D3DXPC_SCALAR: 1103 desc.constType = GFXSCT_Float; 1104 break; 1105 case D3DXPC_VECTOR : 1106 { 1107 switch (constantDesc.Columns) 1108 { 1109 case 1 : 1110 desc.constType = GFXSCT_Float; 1111 break; 1112 case 2 : 1113 desc.constType = GFXSCT_Float2; 1114 break; 1115 case 3 : 1116 desc.constType = GFXSCT_Float3; 1117 break; 1118 case 4 : 1119 desc.constType = GFXSCT_Float4; 1120 break; 1121 default: 1122 AssertFatal(false, "Unknown float vector type!"); 1123 break; 1124 } 1125 } 1126 break; 1127 case D3DXPC_MATRIX_ROWS : 1128 case D3DXPC_MATRIX_COLUMNS : 1129 { 1130 S32 fd, sd; 1131 fd = constantDesc.RegisterCount / constantDesc.Elements; 1132 sd = constantDesc.Class == D3DXPC_MATRIX_ROWS ? constantDesc.Columns : constantDesc.Rows; 1133 1134 switch (fd) 1135 { 1136 case 2 : 1137 AssertFatal(sd == 2, "non-square 2x? mats not supported"); 1138 desc.constType = GFXSCT_Float2x2; 1139 break; 1140 case 3 : 1141 switch (sd) 1142 { 1143 case 3 : 1144 desc.constType = GFXSCT_Float3x3; 1145 break; 1146 case 4 : 1147 desc.constType = GFXSCT_Float4x3; 1148 break; 1149 default: 1150 AssertFatal(false, "Unsupported matrix size"); 1151 break; 1152 } 1153 break; 1154 case 4 : 1155 switch (sd) 1156 { 1157 case 3: 1158 desc.constType = GFXSCT_Float3x4; 1159 break; 1160 case 4: 1161 desc.constType = GFXSCT_Float4x4; 1162 break; 1163 default: 1164 AssertFatal(false, "Unsupported matrix size"); 1165 break; 1166 } 1167 break; 1168 } 1169 } 1170 break; 1171 case D3DXPC_OBJECT : 1172 case D3DXPC_STRUCT : 1173 bufferLayout = NULL; 1174 break; 1175 } 1176 } 1177 break; 1178 case D3DXRS_SAMPLER : 1179 { 1180 AssertFatal( constantDesc.Elements == 1, "Sampler Arrays not yet supported!" ); 1181 1182 switch (constantDesc.Type) 1183 { 1184 case D3DXPT_SAMPLER : 1185 case D3DXPT_SAMPLER1D : 1186 case D3DXPT_SAMPLER2D : 1187 case D3DXPT_SAMPLER3D : 1188 // Hi-jack the desc's arraySize to store the registerIndex. 1189 desc.constType = GFXSCT_Sampler; 1190 desc.arraySize = constantDesc.RegisterIndex; 1191 samplerDescriptions.push_back( desc ); 1192 mShaderConsts.push_back(desc); 1193 break; 1194 case D3DXPT_SAMPLERCUBE : 1195 desc.constType = GFXSCT_SamplerCube; 1196 desc.arraySize = constantDesc.RegisterIndex; 1197 samplerDescriptions.push_back( desc ); 1198 mShaderConsts.push_back(desc); 1199 break; 1200 } 1201 } 1202 break; 1203 default: 1204 AssertFatal(false, "Unknown shader constant class enum"); 1205 break; 1206 } 1207 1208 if (bufferLayout) 1209 { 1210 mShaderConsts.push_back(desc); 1211 1212 U32 alignBytes = getAlignmentValue(desc.constType); 1213 U32 paramSize = alignBytes * desc.arraySize; 1214 bufferLayout->addParameter( desc.name, 1215 desc.constType, 1216 constantDesc.RegisterIndex * sizeof(Point4F), 1217 paramSize, 1218 desc.arraySize, 1219 alignBytes ); 1220 } 1221 } 1222 else 1223 AssertFatal(false, "Unable to get shader constant description! (may need more elements of constantDesc"); 1224 } 1225} 1226 1227const U32 GFXD3D9Shader::smCompiledShaderTag = MakeFourCC('t','c','s','f'); 1228 1229bool GFXD3D9Shader::_saveCompiledOutput( const Torque::Path &filePath, 1230 LPD3DXBUFFER buffer, 1231 GenericConstBufferLayout *bufferLayoutF, 1232 GenericConstBufferLayout *bufferLayoutI, 1233 Vector<GFXShaderConstDesc> &samplerDescriptions ) 1234{ 1235 Torque::Path outputPath(filePath); 1236 outputPath.setExtension("csf"); // "C"ompiled "S"hader "F"ile (fancy!) 1237 1238 FileStream f; 1239 if (!f.open(outputPath, Torque::FS::File::Write)) 1240 return false; 1241 if (!f.write(smCompiledShaderTag)) 1242 return false; 1243 // We could reverse engineer the structure in the compiled output, but this 1244 // is a bit easier because we can just read it into the struct that we want. 1245 if (!bufferLayoutF->write(&f)) 1246 return false; 1247 if (!bufferLayoutI->write(&f)) 1248 return false; 1249 U32 bufferSize = buffer->GetBufferSize(); 1250 if (!f.write(bufferSize)) 1251 return false; 1252 if (!f.write(bufferSize, buffer->GetBufferPointer())) 1253 return false; 1254 1255 // Write out sampler descriptions. 1256 1257 f.write( samplerDescriptions.size() ); 1258 1259 for ( U32 i = 0; i < samplerDescriptions.size(); i++ ) 1260 { 1261 f.write( samplerDescriptions[i].name ); 1262 f.write( (U32)(samplerDescriptions[i].constType) ); 1263 f.write( samplerDescriptions[i].arraySize ); 1264 } 1265 1266 f.close(); 1267 1268 return true; 1269} 1270 1271bool GFXD3D9Shader::_loadCompiledOutput( const Torque::Path &filePath, 1272 const String &target, 1273 GenericConstBufferLayout *bufferLayoutF, 1274 GenericConstBufferLayout *bufferLayoutI, 1275 Vector<GFXShaderConstDesc> &samplerDescriptions ) 1276{ 1277 Torque::Path outputPath(filePath); 1278 outputPath.setExtension("csf"); // "C"ompiled "S"hader "F"ile (fancy!) 1279 1280 FileStream f; 1281 if (!f.open(outputPath, Torque::FS::File::Read)) 1282 return false; 1283 U32 fileTag; 1284 if (!f.read(&fileTag)) 1285 return false; 1286 if (fileTag != smCompiledShaderTag) 1287 return false; 1288 if (!bufferLayoutF->read(&f)) 1289 return false; 1290 if (!bufferLayoutI->read(&f)) 1291 return false; 1292 U32 bufferSize; 1293 if (!f.read(&bufferSize)) 1294 return false; 1295 U32 waterMark = FrameAllocator::getWaterMark(); 1296 DWORD* buffer = static_cast<DWORD*>(FrameAllocator::alloc(bufferSize)); 1297 if (!f.read(bufferSize, buffer)) 1298 return false; 1299 1300 // Read sampler descriptions. 1301 1302 U32 samplerCount; 1303 f.read( &samplerCount ); 1304 1305 for ( U32 i = 0; i < samplerCount; i++ ) 1306 { 1307 GFXShaderConstDesc samplerDesc; 1308 f.read( &(samplerDesc.name) ); 1309 f.read( (U32*)&(samplerDesc.constType) ); 1310 f.read( &(samplerDesc.arraySize) ); 1311 1312 samplerDescriptions.push_back( samplerDesc ); 1313 } 1314 1315 f.close(); 1316 1317 HRESULT res; 1318 if (target.compare("ps_", 3) == 0) 1319 res = mD3D9Device->CreatePixelShader(buffer, &mPixShader ); 1320 else 1321 res = mD3D9Device->CreateVertexShader(buffer, &mVertShader ); 1322 AssertFatal(SUCCEEDED(res), "Unable to load shader!"); 1323 1324 FrameAllocator::setWaterMark(waterMark); 1325 return SUCCEEDED(res); 1326} 1327 1328void GFXD3D9Shader::_buildShaderConstantHandles(GenericConstBufferLayout* layout, bool vertexConst) 1329{ 1330 for (U32 i = 0; i < layout->getParameterCount(); i++) 1331 { 1332 GenericConstBufferLayout::ParamDesc pd; 1333 layout->getDesc(i, pd); 1334 1335 GFXD3D9ShaderConstHandle* handle; 1336 HandleMap::Iterator j = mHandles.find(pd.name); 1337 1338 if (j != mHandles.end()) 1339 { 1340 handle = j->value; 1341 handle->mShader = this; 1342 handle->setValid( true ); 1343 } 1344 else 1345 { 1346 handle = new GFXD3D9ShaderConstHandle(); 1347 handle->mShader = this; 1348 mHandles[pd.name] = handle; 1349 handle->setValid( true ); 1350 } 1351 1352 if ( vertexConst ) 1353 { 1354 handle->mVertexConstant = true; 1355 handle->mVertexHandle = pd; 1356 } 1357 else 1358 { 1359 handle->mPixelConstant = true; 1360 handle->mPixelHandle = pd; 1361 } 1362 } 1363} 1364 1365void GFXD3D9Shader::_buildSamplerShaderConstantHandles( Vector<GFXShaderConstDesc> &samplerDescriptions ) 1366{ 1367 Vector<GFXShaderConstDesc>::iterator iter = samplerDescriptions.begin(); 1368 for ( ; iter != samplerDescriptions.end(); iter++ ) 1369 { 1370 const GFXShaderConstDesc &desc = *iter; 1371 1372 AssertFatal( desc.constType == GFXSCT_Sampler || 1373 desc.constType == GFXSCT_SamplerCube, 1374 "GFXD3D9Shader::_buildSamplerShaderConstantHandles - Invalid samplerDescription type!" ); 1375 1376 GFXD3D9ShaderConstHandle *handle; 1377 HandleMap::Iterator j = mHandles.find(desc.name); 1378 1379 if ( j != mHandles.end() ) 1380 handle = j->value; 1381 else 1382 { 1383 handle = new GFXD3D9ShaderConstHandle(); 1384 mHandles[desc.name] = handle; 1385 } 1386 1387 handle->mShader = this; 1388 handle->setValid( true ); 1389 handle->mPixelConstant = true; 1390 handle->mPixelHandle.name = desc.name; 1391 handle->mPixelHandle.constType = desc.constType; 1392 handle->mPixelHandle.offset = desc.arraySize; 1393 } 1394} 1395 1396void GFXD3D9Shader::_buildInstancingShaderConstantHandles() 1397{ 1398 // If we have no instancing than just return 1399 if (!mInstancingFormat) 1400 return; 1401 1402 U32 offset = 0; 1403 1404 for ( U32 i=0; i < mInstancingFormat->getElementCount(); i++ ) 1405 { 1406 const GFXVertexElement &element = mInstancingFormat->getElement( i ); 1407 1408 String constName = String::ToString( "$%s", element.getSemantic().c_str() ); 1409 1410 GFXD3D9ShaderConstHandle *handle; 1411 HandleMap::Iterator j = mHandles.find( constName ); 1412 1413 if ( j != mHandles.end() ) 1414 handle = j->value; 1415 else 1416 { 1417 handle = new GFXD3D9ShaderConstHandle(); 1418 mHandles[ constName ] = handle; 1419 } 1420 1421 handle->mShader = this; 1422 handle->setValid( true ); 1423 handle->mInstancingConstant = true; 1424 1425 // We shouldn't have an instancing constant that is also 1426 // a vertex or pixel constant! This means the shader features 1427 // are confused as to what is instanced. 1428 // 1429 AssertFatal( !handle->mVertexConstant && 1430 !handle->mPixelConstant, 1431 "GFXD3D9Shader::_buildInstancingShaderConstantHandles - Bad instanced constant!" ); 1432 1433 // HACK: The GFXD3D9ShaderConstHandle will check mVertexConstant then 1434 // fall back to reading the mPixelHandle values. We depend on this here 1435 // and store the data we need in the mPixelHandle constant although its 1436 // not a pixel shader constant. 1437 // 1438 handle->mPixelHandle.name = constName; 1439 handle->mPixelHandle.offset = offset; 1440 1441 // If this is a matrix we will have 2 or 3 more of these 1442 // semantics with the same name after it. 1443 for ( ; i < mInstancingFormat->getElementCount(); i++ ) 1444 { 1445 const GFXVertexElement &nextElement = mInstancingFormat->getElement( i ); 1446 if ( nextElement.getSemantic() != element.getSemantic() ) 1447 { 1448 i--; 1449 break; 1450 } 1451 offset += nextElement.getSizeInBytes(); 1452 } 1453 } 1454} 1455 1456GFXShaderConstBufferRef GFXD3D9Shader::allocConstBuffer() 1457{ 1458 if (mVertexConstBufferLayoutF && mPixelConstBufferLayoutF) 1459 { 1460 GFXD3D9ShaderConstBuffer* buffer = new GFXD3D9ShaderConstBuffer(this, mVertexConstBufferLayoutF, mVertexConstBufferLayoutI, mPixelConstBufferLayoutF, mPixelConstBufferLayoutI); 1461 mActiveBuffers.push_back( buffer ); 1462 buffer->registerResourceWithDevice(getOwningDevice()); 1463 return buffer; 1464 } else { 1465 return NULL; 1466 } 1467} 1468 1469/// Returns a shader constant handle for name 1470GFXShaderConstHandle* GFXD3D9Shader::getShaderConstHandle(const String& name) 1471{ 1472 HandleMap::Iterator i = mHandles.find(name); 1473 if ( i != mHandles.end() ) 1474 { 1475 return i->value; 1476 } 1477 else 1478 { 1479 GFXD3D9ShaderConstHandle *handle = new GFXD3D9ShaderConstHandle(); 1480 handle->setValid( false ); 1481 handle->mShader = this; 1482 mHandles[name] = handle; 1483 1484 return handle; 1485 } 1486} 1487 1488/// Returns a shader constant handle for name, if the variable doesn't exist NULL is returned. 1489GFXShaderConstHandle* GFXD3D9Shader::findShaderConstHandle(const String& name) 1490{ 1491 HandleMap::Iterator i = mHandles.find(name); 1492 if ( i != mHandles.end() ) 1493 { 1494 return i->value; 1495 } 1496 else 1497 { 1498 return NULL; 1499 } 1500} 1501 1502const Vector<GFXShaderConstDesc>& GFXD3D9Shader::getShaderConstDesc() const 1503{ 1504 return mShaderConsts; 1505} 1506 1507U32 GFXD3D9Shader::getAlignmentValue(const GFXShaderConstType constType) const 1508{ 1509 const U32 mRowSizeF = 16; 1510 const U32 mRowSizeI = 16; 1511 1512 switch (constType) 1513 { 1514 case GFXSCT_Float : 1515 case GFXSCT_Float2 : 1516 case GFXSCT_Float3 : 1517 case GFXSCT_Float4 : 1518 return mRowSizeF; 1519 break; 1520 // Matrices 1521 case GFXSCT_Float2x2 : 1522 return mRowSizeF * 2; 1523 break; 1524 case GFXSCT_Float3x3 : 1525 return mRowSizeF * 3; 1526 break; 1527 case GFXSCT_Float3x4 : 1528 return mRowSizeF * 4; 1529 break; 1530 case GFXSCT_Float4x4 : 1531 return mRowSizeF * 4; 1532 break; 1533 case GFXSCT_Float4x3 : 1534 return mRowSizeF * 3; 1535 break; 1536 //// Scalar 1537 case GFXSCT_Int : 1538 case GFXSCT_Int2 : 1539 case GFXSCT_Int3 : 1540 case GFXSCT_Int4 : 1541 return mRowSizeI; 1542 break; 1543 default: 1544 AssertFatal(false, "Unsupported type!"); 1545 return 0; 1546 break; 1547 } 1548} 1549 1550void GFXD3D9Shader::zombify() 1551{ 1552 // Shaders don't need zombification 1553} 1554 1555void GFXD3D9Shader::resurrect() 1556{ 1557 // Shaders are never zombies, and therefore don't have to be brought back. 1558} 1559
