2
0

BsVulkanVertexInputManager.cpp 6.8 KB

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