|
|
|
@@ -20,7 +20,7 @@
|
|
|
|
namespace Vulkan {
|
|
|
|
namespace Vulkan {
|
|
|
|
|
|
|
|
|
|
|
|
// Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines
|
|
|
|
// Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines
|
|
|
|
constexpr size_t SETS_GROW_RATE = 16;
|
|
|
|
//constexpr size_t SETS_GROW_RATE = 32; //test difference between 16 and 32
|
|
|
|
constexpr s32 SCORE_THRESHOLD = 3;
|
|
|
|
constexpr s32 SCORE_THRESHOLD = 3;
|
|
|
|
|
|
|
|
|
|
|
|
struct DescriptorBank {
|
|
|
|
struct DescriptorBank {
|
|
|
|
@@ -29,9 +29,12 @@ struct DescriptorBank {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
bool DescriptorBankInfo::IsSuperset(const DescriptorBankInfo& subset) const noexcept {
|
|
|
|
bool DescriptorBankInfo::IsSuperset(const DescriptorBankInfo& subset) const noexcept {
|
|
|
|
return uniform_buffers >= subset.uniform_buffers && storage_buffers >= subset.storage_buffers &&
|
|
|
|
return uniform_buffers >= subset.uniform_buffers &&
|
|
|
|
texture_buffers >= subset.texture_buffers && image_buffers >= subset.image_buffers &&
|
|
|
|
storage_buffers >= subset.storage_buffers &&
|
|
|
|
textures >= subset.textures && images >= subset.images;
|
|
|
|
texture_buffers >= subset.texture_buffers &&
|
|
|
|
|
|
|
|
image_buffers >= subset.image_buffers &&
|
|
|
|
|
|
|
|
textures >= subset.textures &&
|
|
|
|
|
|
|
|
images >= subset.images;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Descriptors>
|
|
|
|
template <typename Descriptors>
|
|
|
|
@@ -45,6 +48,19 @@ static u32 Accumulate(const Descriptors& descriptors) {
|
|
|
|
|
|
|
|
|
|
|
|
static DescriptorBankInfo MakeBankInfo(std::span<const Shader::Info> infos) {
|
|
|
|
static DescriptorBankInfo MakeBankInfo(std::span<const Shader::Info> infos) {
|
|
|
|
DescriptorBankInfo bank;
|
|
|
|
DescriptorBankInfo bank;
|
|
|
|
|
|
|
|
if (infos.size() == 1) {
|
|
|
|
|
|
|
|
const auto& info = infos.front();
|
|
|
|
|
|
|
|
const auto acc = [](const auto& ds){ u32 c=0; for (const auto& d: ds) c+=d.count; return c; };
|
|
|
|
|
|
|
|
bank.uniform_buffers += acc(info.constant_buffer_descriptors);
|
|
|
|
|
|
|
|
bank.storage_buffers += acc(info.storage_buffers_descriptors);
|
|
|
|
|
|
|
|
bank.texture_buffers += acc(info.texture_buffer_descriptors);
|
|
|
|
|
|
|
|
bank.image_buffers += acc(info.image_buffer_descriptors);
|
|
|
|
|
|
|
|
bank.textures += acc(info.texture_descriptors);
|
|
|
|
|
|
|
|
bank.images += acc(info.image_descriptors);
|
|
|
|
|
|
|
|
bank.score = bank.uniform_buffers + bank.storage_buffers + bank.texture_buffers +
|
|
|
|
|
|
|
|
bank.image_buffers + bank.textures + bank.images;
|
|
|
|
|
|
|
|
return bank;
|
|
|
|
|
|
|
|
}
|
|
|
|
for (const Shader::Info& info : infos) {
|
|
|
|
for (const Shader::Info& info : infos) {
|
|
|
|
bank.uniform_buffers += Accumulate(info.constant_buffer_descriptors);
|
|
|
|
bank.uniform_buffers += Accumulate(info.constant_buffer_descriptors);
|
|
|
|
bank.storage_buffers += Accumulate(info.storage_buffers_descriptors);
|
|
|
|
bank.storage_buffers += Accumulate(info.storage_buffers_descriptors);
|
|
|
|
@@ -87,14 +103,35 @@ static void AllocatePool(const Device& device, DescriptorBank& bank) {
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static size_t GetGrowRate() {
|
|
|
|
|
|
|
|
if (Settings::getDebugKnobAt(0))
|
|
|
|
|
|
|
|
return 8;
|
|
|
|
|
|
|
|
else if (Settings::getDebugKnobAt(1))
|
|
|
|
|
|
|
|
return 16;
|
|
|
|
|
|
|
|
else if (Settings::getDebugKnobAt(2))
|
|
|
|
|
|
|
|
return 24;
|
|
|
|
|
|
|
|
else if (Settings::getDebugKnobAt(3))
|
|
|
|
|
|
|
|
return 32;
|
|
|
|
|
|
|
|
else if (Settings::getDebugKnobAt(4))
|
|
|
|
|
|
|
|
return 40;
|
|
|
|
|
|
|
|
else if (Settings::getDebugKnobAt(5))
|
|
|
|
|
|
|
|
return 48;
|
|
|
|
|
|
|
|
else if (Settings::getDebugKnobAt(6))
|
|
|
|
|
|
|
|
return 56;
|
|
|
|
|
|
|
|
else if (Settings::getDebugKnobAt(7))
|
|
|
|
|
|
|
|
return 64;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
return 16;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DescriptorAllocator::DescriptorAllocator(const Device& device_, MasterSemaphore& master_semaphore_,
|
|
|
|
DescriptorAllocator::DescriptorAllocator(const Device& device_, MasterSemaphore& master_semaphore_,
|
|
|
|
DescriptorBank& bank_, VkDescriptorSetLayout layout_)
|
|
|
|
DescriptorBank& bank_, VkDescriptorSetLayout layout_)
|
|
|
|
: ResourcePool(master_semaphore_, SETS_GROW_RATE), device{&device_}, bank{&bank_},
|
|
|
|
: ResourcePool(master_semaphore_, /*SETS_GROW_RATE*/ GetGrowRate()), device{&device_}, bank{&bank_},
|
|
|
|
layout{layout_} {}
|
|
|
|
layout{layout_}, grow_rate{GetGrowRate()} {}
|
|
|
|
|
|
|
|
|
|
|
|
VkDescriptorSet DescriptorAllocator::Commit() {
|
|
|
|
VkDescriptorSet DescriptorAllocator::Commit() {
|
|
|
|
const size_t index = CommitResource();
|
|
|
|
const size_t index = CommitResource();
|
|
|
|
return sets[index / SETS_GROW_RATE][index % SETS_GROW_RATE];
|
|
|
|
return sets[index / grow_rate][index % grow_rate];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DescriptorAllocator::Allocate(size_t begin, size_t end) {
|
|
|
|
void DescriptorAllocator::Allocate(size_t begin, size_t end) {
|
|
|
|
@@ -102,13 +139,22 @@ void DescriptorAllocator::Allocate(size_t begin, size_t end) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) {
|
|
|
|
vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) {
|
|
|
|
const std::vector<VkDescriptorSetLayout> layouts(count, layout);
|
|
|
|
std::array<VkDescriptorSetLayout, 64> stack{};
|
|
|
|
|
|
|
|
const VkDescriptorSetLayout* p_layouts = nullptr;
|
|
|
|
|
|
|
|
std::vector<VkDescriptorSetLayout> heap;
|
|
|
|
|
|
|
|
if (count <= stack.size()) {
|
|
|
|
|
|
|
|
stack.fill(layout);
|
|
|
|
|
|
|
|
p_layouts = stack.data();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
heap.assign(count, layout);
|
|
|
|
|
|
|
|
p_layouts = heap.data();
|
|
|
|
|
|
|
|
}
|
|
|
|
VkDescriptorSetAllocateInfo allocate_info{
|
|
|
|
VkDescriptorSetAllocateInfo allocate_info{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.descriptorPool = *bank->pools.back(),
|
|
|
|
.descriptorPool = *bank->pools.back(),
|
|
|
|
.descriptorSetCount = static_cast<u32>(count),
|
|
|
|
.descriptorSetCount = static_cast<u32>(count),
|
|
|
|
.pSetLayouts = layouts.data(),
|
|
|
|
.pSetLayouts = p_layouts,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
vk::DescriptorSets new_sets = bank->pools.back().Allocate(allocate_info);
|
|
|
|
vk::DescriptorSets new_sets = bank->pools.back().Allocate(allocate_info);
|
|
|
|
if (!new_sets.IsOutOfPoolMemory()) {
|
|
|
|
if (!new_sets.IsOutOfPoolMemory()) {
|
|
|
|
@@ -146,21 +192,58 @@ DescriptorAllocator DescriptorPool::Allocator(VkDescriptorSetLayout layout,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DescriptorBank& DescriptorPool::Bank(const DescriptorBankInfo& reqs) {
|
|
|
|
DescriptorBank& DescriptorPool::Bank(const DescriptorBankInfo& reqs) {
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::scoped_lock lk(cache_mutex);
|
|
|
|
|
|
|
|
DescriptorBank* best = nullptr; u64 best_stamp = 0;
|
|
|
|
|
|
|
|
for (const auto& e : cache_) {
|
|
|
|
|
|
|
|
if (!e.bank) continue;
|
|
|
|
|
|
|
|
if (std::abs(e.info.score - reqs.score) < SCORE_THRESHOLD && e.info.IsSuperset(reqs)) {
|
|
|
|
|
|
|
|
if (e.stamp >= best_stamp) { best_stamp = e.stamp; best = e.bank; }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (best) return *best;
|
|
|
|
|
|
|
|
}
|
|
|
|
std::shared_lock read_lock{banks_mutex};
|
|
|
|
std::shared_lock read_lock{banks_mutex};
|
|
|
|
const auto it = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
|
|
|
|
const auto it = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
|
|
|
|
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
|
|
|
|
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
if (it != bank_infos.end()) {
|
|
|
|
if (it != bank_infos.end()) {
|
|
|
|
return *banks[std::distance(bank_infos.begin(), it)].get();
|
|
|
|
DescriptorBank& found = *banks[std::distance(bank_infos.begin(), it)].get();
|
|
|
|
|
|
|
|
read_lock.unlock();
|
|
|
|
|
|
|
|
// update cache
|
|
|
|
|
|
|
|
std::scoped_lock lk(cache_mutex);
|
|
|
|
|
|
|
|
size_t victim = 0; u64 oldest = UINT64_MAX;
|
|
|
|
|
|
|
|
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
|
|
|
|
|
|
|
|
cache_[victim] = CacheEntry{found.info, &found, ++cache_tick_};
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
read_lock.unlock();
|
|
|
|
read_lock.unlock();
|
|
|
|
|
|
|
|
|
|
|
|
std::unique_lock write_lock{banks_mutex};
|
|
|
|
std::unique_lock write_lock{banks_mutex};
|
|
|
|
|
|
|
|
auto it2 = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
|
|
|
|
|
|
|
|
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
if (it2 != bank_infos.end()) {
|
|
|
|
|
|
|
|
DescriptorBank& found = *banks[std::distance(bank_infos.begin(), it2)].get();
|
|
|
|
|
|
|
|
// update cache
|
|
|
|
|
|
|
|
std::scoped_lock lk(cache_mutex);
|
|
|
|
|
|
|
|
size_t victim = 0; u64 oldest = UINT64_MAX;
|
|
|
|
|
|
|
|
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
|
|
|
|
|
|
|
|
cache_[victim] = CacheEntry{found.info, &found, ++cache_tick_};
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
|
|
|
}
|
|
|
|
bank_infos.push_back(reqs);
|
|
|
|
bank_infos.push_back(reqs);
|
|
|
|
|
|
|
|
|
|
|
|
auto& bank = *banks.emplace_back(std::make_unique<DescriptorBank>());
|
|
|
|
auto& bank = *banks.emplace_back(std::make_unique<DescriptorBank>());
|
|
|
|
bank.info = reqs;
|
|
|
|
bank.info = reqs;
|
|
|
|
AllocatePool(device, bank);
|
|
|
|
AllocatePool(device, bank);
|
|
|
|
|
|
|
|
// update cache
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::scoped_lock lk(cache_mutex);
|
|
|
|
|
|
|
|
size_t victim = 0; u64 oldest = UINT64_MAX;
|
|
|
|
|
|
|
|
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
|
|
|
|
|
|
|
|
cache_[victim] = CacheEntry{bank.info, &bank, ++cache_tick_};
|
|
|
|
|
|
|
|
}
|
|
|
|
return bank;
|
|
|
|
return bank;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|