BsVulkanDescriptorManager.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanDescriptorManager.h"
  4. #include "BsVulkanDescriptorLayout.h"
  5. #include "BsVulkanDescriptorSet.h"
  6. #include "BsVulkanDescriptorPool.h"
  7. #include "BsVulkanDevice.h"
  8. #include "BsVulkanResource.h"
  9. namespace bs
  10. {
  11. VulkanLayoutKey::VulkanLayoutKey(VkDescriptorSetLayoutBinding* bindings, UINT32 numBindings)
  12. :bindings(bindings), numBindings(numBindings)
  13. { }
  14. bool VulkanLayoutKey::operator==(const VulkanLayoutKey& rhs) const
  15. {
  16. // If both have a layout, use that to compare directly, otherwise do it per-binding
  17. if (layout != nullptr && rhs.layout != nullptr)
  18. return layout == rhs.layout;
  19. if (numBindings != rhs.numBindings)
  20. return false;
  21. for (UINT32 i = 0; i < numBindings; i++)
  22. {
  23. if (bindings[i].binding != rhs.bindings[i].binding)
  24. return false;
  25. if (bindings[i].descriptorType != rhs.bindings[i].descriptorType)
  26. return false;
  27. if (bindings[i].descriptorCount != rhs.bindings[i].descriptorCount)
  28. return false;
  29. if (bindings[i].stageFlags != rhs.bindings[i].stageFlags)
  30. return false;
  31. }
  32. return true;
  33. }
  34. VulkanPipelineLayoutKey::VulkanPipelineLayoutKey(VulkanDescriptorLayout** layouts, UINT32 numLayouts)
  35. :layouts(layouts), numLayouts(numLayouts)
  36. {
  37. }
  38. bool VulkanPipelineLayoutKey::operator==(const VulkanPipelineLayoutKey& rhs) const
  39. {
  40. if (numLayouts != rhs.numLayouts)
  41. return false;
  42. for (UINT32 i = 0; i < numLayouts; i++)
  43. {
  44. if (layouts[i] != rhs.layouts[i])
  45. return false;
  46. }
  47. return true;
  48. }
  49. size_t VulkanPipelineLayoutKey::calculateHash() const
  50. {
  51. size_t hash = 0;
  52. for (UINT32 i = 0; i < numLayouts; i++)
  53. hash_combine(hash, layouts[i]->getHash());
  54. return hash;
  55. }
  56. VulkanDescriptorManager::VulkanDescriptorManager(VulkanDevice& device)
  57. :mDevice(device)
  58. {
  59. mPools.push_back(bs_new<VulkanDescriptorPool>(device));
  60. }
  61. VulkanDescriptorManager::~VulkanDescriptorManager()
  62. {
  63. for (auto& entry : mLayouts)
  64. {
  65. bs_delete(entry.layout);
  66. bs_free(entry.bindings);
  67. }
  68. for(auto& entry : mPipelineLayouts)
  69. vkDestroyPipelineLayout(mDevice.getLogical(), entry.second, gVulkanAllocator);
  70. for (auto& entry : mPools)
  71. bs_delete(entry);
  72. }
  73. VulkanDescriptorLayout* VulkanDescriptorManager::getLayout(VkDescriptorSetLayoutBinding* bindings, UINT32 numBindings)
  74. {
  75. VulkanLayoutKey key(bindings, numBindings);
  76. auto iterFind = mLayouts.find(key);
  77. if (iterFind != mLayouts.end())
  78. return iterFind->layout;
  79. // Create new
  80. key.bindings = bs_allocN<VkDescriptorSetLayoutBinding>(numBindings);
  81. memcpy(key.bindings, bindings, numBindings * sizeof(VkDescriptorSetLayoutBinding));
  82. key.layout = bs_new<VulkanDescriptorLayout>(mDevice, key.bindings, numBindings);
  83. mLayouts.insert(key);
  84. return key.layout;
  85. }
  86. VulkanDescriptorSet* VulkanDescriptorManager::createSet(VulkanDescriptorLayout* layout)
  87. {
  88. // Note: We always retrieve the last created pool, even though there could be free room in earlier pools. However
  89. // that requires additional tracking. Since the assumption is that the first pool will be large enough for all
  90. // descriptors, and the only reason to create a second pool is fragmentation, this approach should not result in
  91. // a major resource waste.
  92. VkDescriptorSetLayout setLayout = layout->getHandle();
  93. VkDescriptorSetAllocateInfo allocateInfo;
  94. allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  95. allocateInfo.pNext = nullptr;
  96. allocateInfo.descriptorPool = mPools.back()->getHandle();
  97. allocateInfo.descriptorSetCount = 1;
  98. allocateInfo.pSetLayouts = &setLayout;
  99. VkDescriptorSet set;
  100. VkResult result = vkAllocateDescriptorSets(mDevice.getLogical(), &allocateInfo, &set);
  101. if(result < 0) // Possible fragmentation, try in a new pool
  102. {
  103. mPools.push_back(bs_new<VulkanDescriptorPool>(mDevice));
  104. allocateInfo.descriptorPool = mPools.back()->getHandle();
  105. result = vkAllocateDescriptorSets(mDevice.getLogical(), &allocateInfo, &set);
  106. assert(result == VK_SUCCESS);
  107. }
  108. return mDevice.getResourceManager().create<VulkanDescriptorSet>(set, allocateInfo.descriptorPool);
  109. }
  110. VkPipelineLayout VulkanDescriptorManager::getPipelineLayout(VulkanDescriptorLayout** layouts, UINT32 numLayouts)
  111. {
  112. VulkanPipelineLayoutKey key(layouts, numLayouts);
  113. auto iterFind = mPipelineLayouts.find(key);
  114. if (iterFind != mPipelineLayouts.end())
  115. return iterFind->second;
  116. // Create new
  117. VkDescriptorSetLayout* setLayouts = (VkDescriptorSetLayout*)bs_stack_alloc(sizeof(VkDescriptorSetLayout) * numLayouts);
  118. for(UINT32 i = 0; i < numLayouts; i++)
  119. setLayouts[i] = layouts[i]->getHandle();
  120. VkPipelineLayoutCreateInfo layoutCI;
  121. layoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  122. layoutCI.pNext = nullptr;
  123. layoutCI.flags = 0;
  124. layoutCI.pushConstantRangeCount = 0;
  125. layoutCI.pPushConstantRanges = nullptr;
  126. layoutCI.setLayoutCount = numLayouts;
  127. layoutCI.pSetLayouts = setLayouts;
  128. VkPipelineLayout pipelineLayout;
  129. VkResult result = vkCreatePipelineLayout(mDevice.getLogical(), &layoutCI, gVulkanAllocator, &pipelineLayout);
  130. assert(result != VK_SUCCESS);
  131. bs_stack_free(setLayouts);
  132. mPipelineLayouts.insert(std::make_pair(key, pipelineLayout));
  133. return pipelineLayout;
  134. }
  135. }