CmD3D11InputLayoutManager.cpp 7.0 KB

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