BsVulkanVertexInputManager.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Managers/BsVulkanVertexInputManager.h"
  4. #include "BsVulkanUtility.h"
  5. #include "RenderAPI/BsVertexDeclaration.h"
  6. #include "Profiling/BsRenderStats.h"
  7. namespace bs { namespace ct
  8. {
  9. VulkanVertexInput::VulkanVertexInput(UINT32 id, const VkPipelineVertexInputStateCreateInfo& createInfo)
  10. :mId(id), mCreateInfo(createInfo)
  11. { }
  12. size_t VulkanVertexInputManager::HashFunc::operator()(const VertexDeclarationKey& key) const
  13. {
  14. size_t hash = 0;
  15. hash_combine(hash, key.bufferDeclId);
  16. hash_combine(hash, key.shaderDeclId);
  17. return hash;
  18. }
  19. bool VulkanVertexInputManager::EqualFunc::operator()(const VertexDeclarationKey& a, const VertexDeclarationKey& b) const
  20. {
  21. if (a.bufferDeclId != b.bufferDeclId)
  22. return false;
  23. if (a.shaderDeclId != b.shaderDeclId)
  24. return false;
  25. return true;
  26. }
  27. VulkanVertexInputManager::VulkanVertexInputManager()
  28. {
  29. Lock lock(mMutex);
  30. mNextId = 1;
  31. mWarningShown = false;
  32. mLastUsedCounter = 0;
  33. }
  34. VulkanVertexInputManager::~VulkanVertexInputManager()
  35. {
  36. Lock lock(mMutex);
  37. while (mVertexInputMap.begin() != mVertexInputMap.end())
  38. {
  39. auto firstElem = mVertexInputMap.begin();
  40. mVertexInputMap.erase(firstElem);
  41. }
  42. }
  43. SPtr<VulkanVertexInput> VulkanVertexInputManager::getVertexInfo(
  44. const SPtr<VertexDeclaration>& vbDecl, const SPtr<VertexDeclaration>& shaderDecl)
  45. {
  46. Lock lock(mMutex);
  47. VertexDeclarationKey pair;
  48. pair.bufferDeclId = vbDecl->getId();
  49. pair.shaderDeclId = shaderDecl->getId();
  50. auto iterFind = mVertexInputMap.find(pair);
  51. if (iterFind == mVertexInputMap.end())
  52. {
  53. if (mVertexInputMap.size() >= DECLARATION_BUFFER_SIZE)
  54. removeLeastUsed(); // Prune so the buffer doesn't just infinitely grow
  55. addNew(vbDecl, shaderDecl);
  56. iterFind = mVertexInputMap.find(pair);
  57. }
  58. iterFind->second.lastUsedIdx = ++mLastUsedCounter;
  59. return iterFind->second.vertexInput;
  60. }
  61. void VulkanVertexInputManager::addNew(const SPtr<VertexDeclaration>& vbDecl,
  62. const SPtr<VertexDeclaration>& shaderInputDecl)
  63. {
  64. const List<VertexElement>& vbElements = vbDecl->getProperties().getElements();
  65. const List<VertexElement>& inputElements = shaderInputDecl->getProperties().getElements();
  66. UINT32 numAttributes = 0;
  67. UINT32 numBindings = 0;
  68. for (auto& vbElem : vbElements)
  69. {
  70. bool foundSemantic = false;
  71. for (auto& inputElem : inputElements)
  72. {
  73. if (inputElem.getSemantic() == vbElem.getSemantic() && inputElem.getSemanticIdx() == vbElem.getSemanticIdx())
  74. {
  75. foundSemantic = true;
  76. break;
  77. }
  78. }
  79. if (!foundSemantic) // Shader needs to have a matching input attribute, otherwise we skip it
  80. continue;
  81. numAttributes++;
  82. numBindings = std::max(numBindings, (UINT32)vbElem.getStreamIdx() + 1);
  83. }
  84. VertexInputEntry newEntry;
  85. GroupAlloc& alloc = newEntry.allocator;
  86. alloc.reserve<VkVertexInputAttributeDescription>(numAttributes)
  87. .reserve<VkVertexInputBindingDescription>(numBindings)
  88. .init();
  89. newEntry.attributes = alloc.alloc<VkVertexInputAttributeDescription>(numAttributes);
  90. newEntry.bindings = alloc.alloc<VkVertexInputBindingDescription>(numBindings);
  91. for (UINT32 i = 0; i < numBindings; i++)
  92. {
  93. VkVertexInputBindingDescription& binding = newEntry.bindings[i];
  94. binding.binding = i;
  95. binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
  96. binding.stride = vbDecl->getProperties().getVertexSize(i);
  97. }
  98. UINT32 attribIdx = 0;
  99. bool isFirstInBinding = true;
  100. for (auto& vbElem : vbElements)
  101. {
  102. VkVertexInputAttributeDescription& attribute = newEntry.attributes[attribIdx];
  103. bool foundSemantic = false;
  104. for (auto& inputElem : inputElements)
  105. {
  106. if (inputElem.getSemantic() == vbElem.getSemantic() && inputElem.getSemanticIdx() == vbElem.getSemanticIdx())
  107. {
  108. foundSemantic = true;
  109. attribute.location = inputElem.getOffset();
  110. break;
  111. }
  112. }
  113. if (!foundSemantic) // Shader needs to have a matching input attribute, otherwise we skip it
  114. continue;
  115. attribute.binding = vbElem.getStreamIdx();
  116. attribute.format = VulkanUtility::getVertexType(vbElem.getType());
  117. attribute.offset = vbElem.getOffset();
  118. VkVertexInputBindingDescription& binding = newEntry.bindings[attribute.binding];
  119. bool isPerVertex = vbElem.getInstanceStepRate() == 0;
  120. if (isFirstInBinding)
  121. {
  122. binding.inputRate = isPerVertex ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
  123. isFirstInBinding = false;
  124. }
  125. else
  126. {
  127. if ((binding.inputRate == VK_VERTEX_INPUT_RATE_VERTEX && !isPerVertex) ||
  128. (binding.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE && isPerVertex))
  129. {
  130. LOGERR("Found multiple vertex attributes belonging to the same binding but with different input rates. "
  131. "All attributes in a binding must have the same input rate. Ignoring invalid input rates.")
  132. }
  133. }
  134. attribIdx++;
  135. }
  136. numAttributes = attribIdx; // It's possible some attributes were invalid, in which case we keep the memory allocated but ignore them otherwise
  137. VkPipelineVertexInputStateCreateInfo vertexInputCI;
  138. vertexInputCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
  139. vertexInputCI.pNext = nullptr;
  140. vertexInputCI.flags = 0;
  141. vertexInputCI.pVertexBindingDescriptions = newEntry.bindings;
  142. vertexInputCI.vertexBindingDescriptionCount = numBindings;
  143. vertexInputCI.pVertexAttributeDescriptions = newEntry.attributes;
  144. vertexInputCI.vertexAttributeDescriptionCount = numAttributes;
  145. // Create key and add to the layout map
  146. VertexDeclarationKey pair;
  147. pair.bufferDeclId = vbDecl->getId();
  148. pair.shaderDeclId = shaderInputDecl->getId();
  149. newEntry.vertexInput = bs_shared_ptr_new<VulkanVertexInput>(mNextId++, vertexInputCI);
  150. newEntry.lastUsedIdx = ++mLastUsedCounter;
  151. mVertexInputMap[pair] = std::move(newEntry);
  152. }
  153. void VulkanVertexInputManager::removeLeastUsed()
  154. {
  155. Lock lock(mMutex);
  156. if (!mWarningShown)
  157. {
  158. LOGWRN("Vertex input buffer is full, pruning last " + toString(NUM_ELEMENTS_TO_PRUNE) + " elements. This is "
  159. "probably okay unless you are creating a massive amount of input layouts as they will get re-created every "
  160. "frame. In that case you should increase the layout buffer size. This warning won't be shown again.");
  161. mWarningShown = true;
  162. }
  163. Map<UINT32, VertexDeclarationKey> leastFrequentlyUsedMap;
  164. for (auto iter = mVertexInputMap.begin(); iter != mVertexInputMap.end(); ++iter)
  165. leastFrequentlyUsedMap[iter->second.lastUsedIdx] = iter->first;
  166. UINT32 elemsRemoved = 0;
  167. for (auto iter = leastFrequentlyUsedMap.begin(); iter != leastFrequentlyUsedMap.end(); ++iter)
  168. {
  169. auto inputLayoutIter = mVertexInputMap.find(iter->second);
  170. mVertexInputMap.erase(inputLayoutIter);
  171. elemsRemoved++;
  172. if (elemsRemoved >= NUM_ELEMENTS_TO_PRUNE)
  173. break;
  174. }
  175. }
  176. }}