BsD3D11InputLayoutManager.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include "BsD3D11InputLayoutManager.h"
  2. #include "BsD3D11Mappings.h"
  3. #include "BsD3D11RenderAPI.h"
  4. #include "BsD3D11Device.h"
  5. #include "BsD3D11GpuProgram.h"
  6. #include "BsHardwareBufferManager.h"
  7. #include "BsRenderStats.h"
  8. #include "BsDebug.h"
  9. namespace BansheeEngine
  10. {
  11. size_t D3D11InputLayoutManager::HashFunc::operator()
  12. (const D3D11InputLayoutManager::VertexDeclarationKey &key) const
  13. {
  14. size_t hash = 0;
  15. hash_combine(hash, key.vertxDeclId);
  16. hash_combine(hash, key.vertexProgramId);
  17. return hash;
  18. }
  19. bool D3D11InputLayoutManager::EqualFunc::operator()
  20. (const D3D11InputLayoutManager::VertexDeclarationKey &a, const D3D11InputLayoutManager::VertexDeclarationKey &b) const
  21. {
  22. if (a.vertxDeclId != b.vertxDeclId)
  23. return false;
  24. if(a.vertexProgramId != b.vertexProgramId)
  25. return false;
  26. return true;
  27. }
  28. D3D11InputLayoutManager::D3D11InputLayoutManager()
  29. :mLastUsedCounter(0), mWarningShown(false)
  30. {
  31. }
  32. D3D11InputLayoutManager::~D3D11InputLayoutManager()
  33. {
  34. while(mInputLayoutMap.begin() != mInputLayoutMap.end())
  35. {
  36. auto firstElem = mInputLayoutMap.begin();
  37. SAFE_RELEASE(firstElem->second->inputLayout);
  38. bs_delete(firstElem->second);
  39. mInputLayoutMap.erase(firstElem);
  40. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_InputLayout);
  41. }
  42. }
  43. ID3D11InputLayout* D3D11InputLayoutManager::retrieveInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
  44. {
  45. VertexDeclarationKey pair;
  46. pair.vertxDeclId = vertexBufferDecl->getId();
  47. pair.vertexProgramId = vertexProgram.getProgramId();
  48. auto iterFind = mInputLayoutMap.find(pair);
  49. if(iterFind == mInputLayoutMap.end())
  50. {
  51. if(mInputLayoutMap.size() >= DECLARATION_BUFFER_SIZE)
  52. removeLeastUsed(); // Prune so the buffer doesn't just infinitely grow
  53. addNewInputLayout(vertexShaderDecl, vertexBufferDecl, vertexProgram);
  54. iterFind = mInputLayoutMap.find(pair);
  55. if(iterFind == mInputLayoutMap.end()) // We failed to create input layout
  56. return nullptr;
  57. }
  58. iterFind->second->lastUsedIdx = ++mLastUsedCounter;
  59. return iterFind->second->inputLayout;
  60. }
  61. void D3D11InputLayoutManager::addNewInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
  62. {
  63. if (!vertexBufferDecl->isCompatible(vertexShaderDecl))
  64. return; // Error was already reported, so just quit here
  65. const VertexDeclarationProperties& declProps = vertexBufferDecl->getProperties();
  66. UINT32 numElements = declProps.getElementCount();
  67. D3D11_INPUT_ELEMENT_DESC* declElements = bs_newN<D3D11_INPUT_ELEMENT_DESC>(numElements);
  68. ZeroMemory(declElements, sizeof(D3D11_INPUT_ELEMENT_DESC) * numElements);
  69. unsigned int idx = 0;
  70. for (auto iter = declProps.getElements().begin(); iter != declProps.getElements().end(); ++iter)
  71. {
  72. declElements[idx].SemanticName = D3D11Mappings::get(iter->getSemantic());
  73. declElements[idx].SemanticIndex = iter->getSemanticIdx();
  74. declElements[idx].Format = D3D11Mappings::get(iter->getType());
  75. declElements[idx].InputSlot = iter->getStreamIdx();
  76. declElements[idx].AlignedByteOffset = static_cast<WORD>(iter->getOffset());
  77. declElements[idx].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  78. declElements[idx].InstanceDataStepRate = 0;
  79. idx++;
  80. }
  81. D3D11RenderAPI* d3d11rs = static_cast<D3D11RenderAPI*>(RenderAPICore::instancePtr());
  82. D3D11Device& device = d3d11rs->getPrimaryDevice();
  83. const HLSLMicroCode& microcode = vertexProgram.getMicroCode();
  84. InputLayoutEntry* newEntry = bs_new<InputLayoutEntry>();
  85. newEntry->lastUsedIdx = ++mLastUsedCounter;
  86. newEntry->inputLayout = nullptr;
  87. HRESULT hr = device.getD3D11Device()->CreateInputLayout(
  88. declElements,
  89. numElements,
  90. &microcode[0],
  91. microcode.size(),
  92. &newEntry->inputLayout);
  93. bs_deleteN(declElements, numElements);
  94. if (FAILED(hr)|| device.hasError())
  95. BS_EXCEPT(RenderingAPIException, "Unable to set D3D11 vertex declaration" + device.getErrorDescription());
  96. // Create key and add to the layout map
  97. VertexDeclarationKey pair;
  98. pair.vertxDeclId = vertexBufferDecl->getId();
  99. pair.vertexProgramId = vertexProgram.getProgramId();
  100. mInputLayoutMap[pair] = newEntry;
  101. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_InputLayout);
  102. }
  103. void D3D11InputLayoutManager::removeLeastUsed()
  104. {
  105. if(!mWarningShown)
  106. {
  107. LOGWRN("Input layout buffer is full, pruning last " + toString(NUM_ELEMENTS_TO_PRUNE) + " elements. This is probably okay unless you are creating a massive amount of input layouts" \
  108. " as they will get re-created every frame. In that case you should increase the layout buffer size. This warning won't be shown again.");
  109. mWarningShown = true;
  110. }
  111. Map<UINT32, VertexDeclarationKey> leastFrequentlyUsedMap;
  112. for(auto iter = mInputLayoutMap.begin(); iter != mInputLayoutMap.end(); ++iter)
  113. leastFrequentlyUsedMap[iter->second->lastUsedIdx] = iter->first;
  114. UINT32 elemsRemoved = 0;
  115. for(auto iter = leastFrequentlyUsedMap.begin(); iter != leastFrequentlyUsedMap.end(); ++iter)
  116. {
  117. auto inputLayoutIter = mInputLayoutMap.find(iter->second);
  118. SAFE_RELEASE(inputLayoutIter->second->inputLayout);
  119. bs_delete(inputLayoutIter->second);
  120. mInputLayoutMap.erase(inputLayoutIter);
  121. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_InputLayout);
  122. elemsRemoved++;
  123. if(elemsRemoved >= NUM_ELEMENTS_TO_PRUNE)
  124. break;
  125. }
  126. }
  127. }