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