BsD3D11InputLayoutManager.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include "BsD3D11InputLayoutManager.h"
  2. #include "BsD3D11Mappings.h"
  3. #include "BsD3D11RenderSystem.h"
  4. #include "BsD3D11Device.h"
  5. #include "BsD3D11GpuProgram.h"
  6. #include "BsHardwareBufferManager.h"
  7. #include "BsRenderStats.h"
  8. #include "BsDebug.h"
  9. #include "BsUtil.h"
  10. namespace BansheeEngine
  11. {
  12. size_t D3D11InputLayoutManager::HashFunc::operator()
  13. (const D3D11InputLayoutManager::VertexDeclarationKey &key) const
  14. {
  15. size_t hash = 0;
  16. hash_combine(hash, key.vertxDeclId);
  17. hash_combine(hash, key.vertexProgramId);
  18. return hash;
  19. }
  20. bool D3D11InputLayoutManager::EqualFunc::operator()
  21. (const D3D11InputLayoutManager::VertexDeclarationKey &a, const D3D11InputLayoutManager::VertexDeclarationKey &b) const
  22. {
  23. if (a.vertxDeclId != b.vertxDeclId)
  24. return false;
  25. if(a.vertexProgramId != b.vertexProgramId)
  26. return false;
  27. return true;
  28. }
  29. D3D11InputLayoutManager::D3D11InputLayoutManager()
  30. :mLastUsedCounter(0), mWarningShown(false)
  31. {
  32. }
  33. D3D11InputLayoutManager::~D3D11InputLayoutManager()
  34. {
  35. while(mInputLayoutMap.begin() != mInputLayoutMap.end())
  36. {
  37. auto firstElem = mInputLayoutMap.begin();
  38. SAFE_RELEASE(firstElem->second->inputLayout);
  39. bs_delete<PoolAlloc>(firstElem->second);
  40. mInputLayoutMap.erase(firstElem);
  41. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_InputLayout);
  42. }
  43. }
  44. ID3D11InputLayout* D3D11InputLayoutManager::retrieveInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
  45. {
  46. VertexDeclarationKey pair;
  47. pair.vertxDeclId = vertexBufferDecl->getId();
  48. pair.vertexProgramId = vertexProgram.getProgramId();
  49. auto iterFind = mInputLayoutMap.find(pair);
  50. if(iterFind == mInputLayoutMap.end())
  51. {
  52. if(mInputLayoutMap.size() >= DECLARATION_BUFFER_SIZE)
  53. removeLeastUsed(); // Prune so the buffer doesn't just infinitely grow
  54. addNewInputLayout(vertexShaderDecl, vertexBufferDecl, vertexProgram);
  55. iterFind = mInputLayoutMap.find(pair);
  56. if(iterFind == mInputLayoutMap.end()) // We failed to create input layout
  57. return nullptr;
  58. }
  59. iterFind->second->lastUsedIdx = ++mLastUsedCounter;
  60. return iterFind->second->inputLayout;
  61. }
  62. void D3D11InputLayoutManager::addNewInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
  63. {
  64. if(!areCompatible(vertexShaderDecl, vertexBufferDecl))
  65. return; // Error was already reported, so just quit here
  66. const VertexDeclarationProperties& declProps = vertexBufferDecl->getProperties();
  67. UINT32 numElements = declProps.getElementCount();
  68. D3D11_INPUT_ELEMENT_DESC* declElements = bs_newN<D3D11_INPUT_ELEMENT_DESC, ScratchAlloc>(numElements);
  69. ZeroMemory(declElements, sizeof(D3D11_INPUT_ELEMENT_DESC) * numElements);
  70. unsigned int idx = 0;
  71. for (auto iter = declProps.getElements().begin(); iter != declProps.getElements().end(); ++iter)
  72. {
  73. declElements[idx].SemanticName = D3D11Mappings::get(iter->getSemantic());
  74. declElements[idx].SemanticIndex = iter->getSemanticIdx();
  75. declElements[idx].Format = D3D11Mappings::get(iter->getType());
  76. declElements[idx].InputSlot = iter->getStreamIdx();
  77. declElements[idx].AlignedByteOffset = static_cast<WORD>(iter->getOffset());
  78. declElements[idx].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  79. declElements[idx].InstanceDataStepRate = 0;
  80. idx++;
  81. }
  82. D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
  83. D3D11Device& device = d3d11rs->getPrimaryDevice();
  84. const HLSLMicroCode& microcode = vertexProgram.getMicroCode();
  85. InputLayoutEntry* newEntry = bs_new<InputLayoutEntry, PoolAlloc>();
  86. newEntry->lastUsedIdx = ++mLastUsedCounter;
  87. newEntry->inputLayout = nullptr;
  88. HRESULT hr = device.getD3D11Device()->CreateInputLayout(
  89. declElements,
  90. numElements,
  91. &microcode[0],
  92. microcode.size(),
  93. &newEntry->inputLayout);
  94. bs_deleteN<ScratchAlloc>(declElements, numElements);
  95. if (FAILED(hr)|| device.hasError())
  96. BS_EXCEPT(RenderingAPIException, "Unable to set D3D11 vertex declaration" + device.getErrorDescription());
  97. // Create key and add to the layout map
  98. VertexDeclarationKey pair;
  99. pair.vertxDeclId = vertexBufferDecl->getId();
  100. pair.vertexProgramId = vertexProgram.getProgramId();
  101. mInputLayoutMap[pair] = newEntry;
  102. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_InputLayout);
  103. }
  104. void D3D11InputLayoutManager::removeLeastUsed()
  105. {
  106. if(!mWarningShown)
  107. {
  108. 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" \
  109. " 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.");
  110. mWarningShown = true;
  111. }
  112. Map<UINT32, VertexDeclarationKey> leastFrequentlyUsedMap;
  113. for(auto iter = mInputLayoutMap.begin(); iter != mInputLayoutMap.end(); ++iter)
  114. leastFrequentlyUsedMap[iter->second->lastUsedIdx] = iter->first;
  115. UINT32 elemsRemoved = 0;
  116. for(auto iter = leastFrequentlyUsedMap.begin(); iter != leastFrequentlyUsedMap.end(); ++iter)
  117. {
  118. auto inputLayoutIter = mInputLayoutMap.find(iter->second);
  119. SAFE_RELEASE(inputLayoutIter->second->inputLayout);
  120. bs_delete<PoolAlloc>(inputLayoutIter->second);
  121. mInputLayoutMap.erase(inputLayoutIter);
  122. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_InputLayout);
  123. elemsRemoved++;
  124. if(elemsRemoved >= NUM_ELEMENTS_TO_PRUNE)
  125. break;
  126. }
  127. }
  128. bool D3D11InputLayoutManager::areCompatible(const SPtr<VertexDeclarationCore>& vertexShaderDecl, const SPtr<VertexDeclarationCore>& vertexBufferDecl)
  129. {
  130. const List<VertexElement>& shaderElems = vertexShaderDecl->getProperties().getElements();
  131. const List<VertexElement>& bufferElems = vertexBufferDecl->getProperties().getElements();
  132. for (auto shaderIter = shaderElems.begin(); shaderIter != shaderElems.end(); ++shaderIter)
  133. {
  134. const VertexElement* foundElement = nullptr;
  135. for (auto bufferIter = bufferElems.begin(); bufferIter != bufferElems.end(); ++bufferIter)
  136. {
  137. if(shaderIter->getSemantic() == bufferIter->getSemantic() && shaderIter->getSemanticIdx() == bufferIter->getSemanticIdx())
  138. {
  139. foundElement = &(*bufferIter);
  140. break;
  141. }
  142. }
  143. if(foundElement == nullptr)
  144. {
  145. LOGWRN("Provided vertex buffer doesn't have a required input attribute: " + toString(shaderIter->getSemantic()) + toString(shaderIter->getSemanticIdx()));
  146. return false;
  147. }
  148. }
  149. return true;
  150. }
  151. }