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