CmD3D11InputLayoutManager.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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 CamelotEngine
  10. {
  11. size_t D3D11InputLayoutManager::HashFunc::operator()
  12. (const D3D11InputLayoutManager::VertexDeclarationPair &key) const
  13. {
  14. size_t hash = 0;
  15. hash_combine(hash, key.bufferDeclHash);
  16. hash_combine(hash, key.shaderDeclHash);
  17. return hash;
  18. }
  19. bool D3D11InputLayoutManager::EqualFunc::operator()
  20. (const D3D11InputLayoutManager::VertexDeclarationPair &a, const D3D11InputLayoutManager::VertexDeclarationPair &b) const
  21. {
  22. if(a.bufferDeclElements->size() != b.bufferDeclElements->size())
  23. return false;
  24. if(a.shaderDeclElements->size() != b.shaderDeclElements->size())
  25. return false;
  26. {
  27. auto iter1 = a.bufferDeclElements->begin();
  28. auto iter2 = b.bufferDeclElements->begin();
  29. for(; iter1 != a.bufferDeclElements->end(); ++iter1, ++iter2)
  30. {
  31. if((*iter1) != (*iter2))
  32. return false;
  33. }
  34. }
  35. {
  36. auto iter1 = a.shaderDeclElements->begin();
  37. auto iter2 = b.shaderDeclElements->begin();
  38. for(; iter1 != a.shaderDeclElements->end(); ++iter1, ++iter2)
  39. {
  40. if((*iter1) != (*iter2))
  41. return false;
  42. }
  43. }
  44. return true;
  45. }
  46. D3D11InputLayoutManager::D3D11InputLayoutManager()
  47. :mLastUsedCounter(0), mWarningShown(false)
  48. {
  49. }
  50. D3D11InputLayoutManager::~D3D11InputLayoutManager()
  51. {
  52. while(mInputLayoutMap.begin() != mInputLayoutMap.end())
  53. {
  54. auto firstElem = mInputLayoutMap.begin();
  55. delete firstElem->first.bufferDeclElements;
  56. delete firstElem->first.shaderDeclElements;
  57. SAFE_RELEASE(firstElem->second->inputLayout);
  58. delete firstElem->second;
  59. mInputLayoutMap.erase(firstElem);
  60. }
  61. }
  62. ID3D11InputLayout* D3D11InputLayoutManager::retrieveInputLayout(VertexDeclarationPtr vertexShaderDecl, VertexDeclarationPtr vertexBufferDecl, D3D11HLSLProgram& vertexProgram)
  63. {
  64. VertexDeclarationPair pair;
  65. pair.shaderDeclHash = vertexShaderDecl->getHash();
  66. pair.bufferDeclHash = vertexBufferDecl->getHash();
  67. pair.shaderDeclElements = &vertexShaderDecl->getElements();
  68. pair.bufferDeclElements = &vertexBufferDecl->getElements();
  69. auto iterFind = mInputLayoutMap.find(pair);
  70. if(iterFind == mInputLayoutMap.end())
  71. {
  72. if(mInputLayoutMap.size() >= DECLARATION_BUFFER_SIZE)
  73. removeLeastUsed(); // Prune so the buffer doesn't just infinitely grow
  74. addNewInputLayout(vertexShaderDecl, vertexBufferDecl, vertexProgram.getMicroCode());
  75. iterFind = mInputLayoutMap.find(pair);
  76. if(iterFind == mInputLayoutMap.end()) // We failed to create input layout
  77. return nullptr;
  78. }
  79. iterFind->second->lastUsedIdx = ++mLastUsedCounter;
  80. return iterFind->second->inputLayout;
  81. }
  82. void D3D11InputLayoutManager::addNewInputLayout(VertexDeclarationPtr vertexShaderDecl, VertexDeclarationPtr vertexBufferDecl, const HLSLMicroCode& microCode)
  83. {
  84. // Combine declarations and create input layout
  85. VertexDeclarationPtr newDecl = createCombinedDesc(vertexShaderDecl, vertexBufferDecl);
  86. if(newDecl == nullptr) // Error was already handled, so just quit here
  87. return;
  88. UINT32 numElements = newDecl->getElementCount();
  89. D3D11_INPUT_ELEMENT_DESC* declElements = new D3D11_INPUT_ELEMENT_DESC[numElements];
  90. ZeroMemory(declElements, sizeof(D3D11_INPUT_ELEMENT_DESC) * numElements);
  91. unsigned int idx;
  92. for(auto iter = newDecl->getElements().begin(); iter != newDecl->getElements().end(); ++iter)
  93. {
  94. declElements[idx].SemanticName = D3D11Mappings::get(iter->getSemantic());
  95. declElements[idx].SemanticIndex = iter->getIndex();
  96. declElements[idx].Format = D3D11Mappings::get(iter->getType());
  97. declElements[idx].InputSlot = iter->getSource();
  98. declElements[idx].AlignedByteOffset = static_cast<WORD>(iter->getOffset());
  99. declElements[idx].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  100. declElements[idx].InstanceDataStepRate = 0;
  101. idx++;
  102. }
  103. D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
  104. D3D11Device& device = d3d11rs->getPrimaryDevice();
  105. InputLayoutEntry* newEntry = new InputLayoutEntry();
  106. newEntry->lastUsedIdx = ++mLastUsedCounter;
  107. newEntry->inputLayout = nullptr;
  108. HRESULT hr = device.getD3D11Device()->CreateInputLayout(
  109. declElements,
  110. numElements,
  111. &microCode[0],
  112. microCode.size(),
  113. &newEntry->inputLayout);
  114. if (FAILED(hr)|| device.hasError())
  115. CM_EXCEPT(RenderingAPIException, "Unable to set D3D11 vertex declaration" + device.getErrorDescription());
  116. // Create key and add to the layout map
  117. VertexDeclarationPair pair;
  118. pair.shaderDeclHash = vertexShaderDecl->getHash();
  119. pair.bufferDeclHash = vertexBufferDecl->getHash();
  120. list<VertexElement>::type* shaderDeclElements = new list<VertexElement>::type();
  121. list<VertexElement>::type* bufferDeclElements = new list<VertexElement>::type();
  122. pair.shaderDeclElements = shaderDeclElements;
  123. pair.bufferDeclElements = bufferDeclElements;
  124. for(auto iter = vertexShaderDecl->getElements().begin(); iter != vertexShaderDecl->getElements().end(); ++iter)
  125. shaderDeclElements->push_back(*iter);
  126. for(auto iter = vertexBufferDecl->getElements().begin(); iter != vertexBufferDecl->getElements().end(); ++iter)
  127. bufferDeclElements->push_back(*iter);
  128. mInputLayoutMap[pair] = newEntry;
  129. }
  130. void D3D11InputLayoutManager::removeLeastUsed()
  131. {
  132. if(!mWarningShown)
  133. {
  134. 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" \
  135. " 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.");
  136. mWarningShown = true;
  137. }
  138. map<UINT32, VertexDeclarationPair>::type leastFrequentlyUsedMap;
  139. for(auto iter = mInputLayoutMap.begin(); iter != mInputLayoutMap.end(); ++iter)
  140. leastFrequentlyUsedMap[iter->second->lastUsedIdx] = iter->first;
  141. UINT32 elemsRemoved = 0;
  142. for(auto iter = leastFrequentlyUsedMap.begin(); iter != leastFrequentlyUsedMap.end(); ++iter)
  143. {
  144. auto inputLayoutIter = mInputLayoutMap.find(iter->second);
  145. delete inputLayoutIter->first.bufferDeclElements;
  146. delete inputLayoutIter->first.shaderDeclElements;
  147. SAFE_RELEASE(inputLayoutIter->second->inputLayout);
  148. delete inputLayoutIter->second;
  149. mInputLayoutMap.erase(inputLayoutIter);
  150. elemsRemoved++;
  151. if(elemsRemoved >= NUM_ELEMENTS_TO_PRUNE)
  152. break;
  153. }
  154. }
  155. VertexDeclarationPtr D3D11InputLayoutManager::createCombinedDesc(VertexDeclarationPtr vertexShaderDecl, VertexDeclarationPtr vertexBufferDecl)
  156. {
  157. VertexDeclarationPtr newDecl = HardwareBufferManager::instance().createVertexDeclaration();
  158. for(auto shaderIter = vertexShaderDecl->getElements().begin(); shaderIter != vertexShaderDecl->getElements().end(); ++shaderIter)
  159. {
  160. const VertexElement* foundElement = nullptr;
  161. for(auto bufferIter = vertexBufferDecl->getElements().begin(); bufferIter != vertexBufferDecl->getElements().end(); ++bufferIter)
  162. {
  163. if(shaderIter->getSemantic() == bufferIter->getSemantic() && shaderIter->getIndex() == bufferIter->getSemantic())
  164. {
  165. foundElement = &(*bufferIter);
  166. break;
  167. }
  168. }
  169. if(foundElement == nullptr)
  170. {
  171. // TODO - It's possible I can just skip this attribute and driver won't complain?
  172. LOGWRN("Provided vertex buffer doesn't have a required input attribute: " + toString(shaderIter->getSemantic()) + toString(shaderIter->getIndex()));
  173. return nullptr;
  174. }
  175. if(foundElement->getType() != shaderIter->getType())
  176. {
  177. // TODO - It's possible I can just cast to the smaller size and driver won't complain?
  178. LOGWRN("Shader input and vertex buffer types don't match for element with semantic: " + toString(shaderIter->getSemantic()) + toString(shaderIter->getIndex()) + ". " \
  179. "Buffer type is " + toString(foundElement->getType()) + " and shader type is " + toString(shaderIter->getType()));
  180. return nullptr;
  181. }
  182. newDecl->addElement(foundElement->getSource(), foundElement->getOffset(), foundElement->getType(), foundElement->getSemantic(), foundElement->getIndex());
  183. }
  184. return newDecl;
  185. }
  186. }