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