BsVulkanDescriptorManager.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Managers/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 { namespace ct
  10. {
  11. VulkanLayoutKey::VulkanLayoutKey(VkDescriptorSetLayoutBinding* bindings, UINT32 numBindings)
  12. :numBindings(numBindings), bindings(bindings), layout(nullptr)
  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. :numLayouts(numLayouts), layouts(layouts)
  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. {
  70. bs_free(entry.first.layouts);
  71. vkDestroyPipelineLayout(mDevice.getLogical(), entry.second, gVulkanAllocator);
  72. }
  73. for (auto& entry : mPools)
  74. bs_delete(entry);
  75. }
  76. VulkanDescriptorLayout* VulkanDescriptorManager::getLayout(VkDescriptorSetLayoutBinding* bindings, UINT32 numBindings)
  77. {
  78. VulkanLayoutKey key(bindings, numBindings);
  79. auto iterFind = mLayouts.find(key);
  80. if (iterFind != mLayouts.end())
  81. return iterFind->layout;
  82. // Create new
  83. key.bindings = bs_allocN<VkDescriptorSetLayoutBinding>(numBindings);
  84. memcpy(key.bindings, bindings, numBindings * sizeof(VkDescriptorSetLayoutBinding));
  85. key.layout = bs_new<VulkanDescriptorLayout>(mDevice, key.bindings, numBindings);
  86. mLayouts.insert(key);
  87. return key.layout;
  88. }
  89. VulkanDescriptorSet* VulkanDescriptorManager::createSet(VulkanDescriptorLayout* layout)
  90. {
  91. // Note: We always retrieve the last created pool, even though there could be free room in earlier pools. However
  92. // that requires additional tracking. Since the assumption is that the first pool will be large enough for all
  93. // descriptors, and the only reason to create a second pool is fragmentation, this approach should not result in
  94. // a major resource waste.
  95. VkDescriptorSetLayout setLayout = layout->getHandle();
  96. VkDescriptorSetAllocateInfo allocateInfo;
  97. allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  98. allocateInfo.pNext = nullptr;
  99. allocateInfo.descriptorPool = mPools.back()->getHandle();
  100. allocateInfo.descriptorSetCount = 1;
  101. allocateInfo.pSetLayouts = &setLayout;
  102. VkDescriptorSet set;
  103. VkResult result = vkAllocateDescriptorSets(mDevice.getLogical(), &allocateInfo, &set);
  104. if(result < 0) // Possible fragmentation, try in a new pool
  105. {
  106. mPools.push_back(bs_new<VulkanDescriptorPool>(mDevice));
  107. allocateInfo.descriptorPool = mPools.back()->getHandle();
  108. result = vkAllocateDescriptorSets(mDevice.getLogical(), &allocateInfo, &set);
  109. assert(result == VK_SUCCESS);
  110. }
  111. return mDevice.getResourceManager().create<VulkanDescriptorSet>(set, allocateInfo.descriptorPool);
  112. }
  113. VkPipelineLayout VulkanDescriptorManager::getPipelineLayout(VulkanDescriptorLayout** layouts, UINT32 numLayouts)
  114. {
  115. VulkanPipelineLayoutKey key(layouts, numLayouts);
  116. auto iterFind = mPipelineLayouts.find(key);
  117. if (iterFind != mPipelineLayouts.end())
  118. return iterFind->second;
  119. // Create new
  120. VkDescriptorSetLayout* setLayouts = (VkDescriptorSetLayout*)bs_stack_alloc(sizeof(VkDescriptorSetLayout) * numLayouts);
  121. for(UINT32 i = 0; i < numLayouts; i++)
  122. setLayouts[i] = layouts[i]->getHandle();
  123. VkPipelineLayoutCreateInfo layoutCI;
  124. layoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  125. layoutCI.pNext = nullptr;
  126. layoutCI.flags = 0;
  127. layoutCI.pushConstantRangeCount = 0;
  128. layoutCI.pPushConstantRanges = nullptr;
  129. layoutCI.setLayoutCount = numLayouts;
  130. layoutCI.pSetLayouts = setLayouts;
  131. VkPipelineLayout pipelineLayout;
  132. VkResult result = vkCreatePipelineLayout(mDevice.getLogical(), &layoutCI, gVulkanAllocator, &pipelineLayout);
  133. assert(result == VK_SUCCESS);
  134. bs_stack_free(setLayouts);
  135. key.layouts = (VulkanDescriptorLayout**)bs_alloc(sizeof(VulkanDescriptorLayout*) * numLayouts);
  136. memcpy(key.layouts, layouts, sizeof(VulkanDescriptorLayout*) * numLayouts);
  137. mPipelineLayouts.insert(std::make_pair(key, pipelineLayout));
  138. return pipelineLayout;
  139. }
  140. }}