Compare commits

...

3 Commits

Author SHA1 Message Date
Caio Oliveira
513b81b965 [DONOTMERGE] add debug knobs for faster testing
* should work?

Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-12-16 20:52:03 +01:00
Caio Oliveira
955cc70796 Fix license headers 2025-12-16 20:52:03 +01:00
wildcard
b55c8bb2e7 [Vulkan] speed up bank lookup with LRU cache, batch growth to 32
Adds a tiny 8 entry LRU cache(should be tested for optimal number)
Increase batch growth to 32 (should be tested to determine the difference between 16 and 32)
2025-12-16 20:52:03 +01:00
2 changed files with 107 additions and 11 deletions

View File

@@ -20,7 +20,7 @@
namespace Vulkan {
// 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;
struct DescriptorBank {
@@ -29,9 +29,12 @@ struct DescriptorBank {
};
bool DescriptorBankInfo::IsSuperset(const DescriptorBankInfo& subset) const noexcept {
return uniform_buffers >= subset.uniform_buffers && storage_buffers >= subset.storage_buffers &&
texture_buffers >= subset.texture_buffers && image_buffers >= subset.image_buffers &&
textures >= subset.textures && images >= subset.images;
return uniform_buffers >= subset.uniform_buffers &&
storage_buffers >= subset.storage_buffers &&
texture_buffers >= subset.texture_buffers &&
image_buffers >= subset.image_buffers &&
textures >= subset.textures &&
images >= subset.images;
}
template <typename Descriptors>
@@ -45,6 +48,19 @@ static u32 Accumulate(const Descriptors& descriptors) {
static DescriptorBankInfo MakeBankInfo(std::span<const Shader::Info> infos) {
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) {
bank.uniform_buffers += Accumulate(info.constant_buffer_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_,
DescriptorBank& bank_, VkDescriptorSetLayout layout_)
: ResourcePool(master_semaphore_, SETS_GROW_RATE), device{&device_}, bank{&bank_},
layout{layout_} {}
: ResourcePool(master_semaphore_, /*SETS_GROW_RATE*/ GetGrowRate()), device{&device_}, bank{&bank_},
layout{layout_}, grow_rate{GetGrowRate()} {}
VkDescriptorSet DescriptorAllocator::Commit() {
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) {
@@ -102,13 +139,22 @@ void DescriptorAllocator::Allocate(size_t begin, size_t end) {
}
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{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.pNext = nullptr,
.descriptorPool = *bank->pools.back(),
.descriptorSetCount = static_cast<u32>(count),
.pSetLayouts = layouts.data(),
.pSetLayouts = p_layouts,
};
vk::DescriptorSets new_sets = bank->pools.back().Allocate(allocate_info);
if (!new_sets.IsOutOfPoolMemory()) {
@@ -146,21 +192,58 @@ DescriptorAllocator DescriptorPool::Allocator(VkDescriptorSetLayout layout,
}
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};
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);
});
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();
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);
auto& bank = *banks.emplace_back(std::make_unique<DescriptorBank>());
bank.info = reqs;
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;
}

View File

@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -6,7 +9,8 @@
#include <shared_mutex>
#include <span>
#include <vector>
#include <array>
#include <mutex>
#include "shader_recompiler/shader_info.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -58,6 +62,7 @@ private:
VkDescriptorSetLayout layout{};
std::vector<vk::DescriptorSets> sets;
size_t grow_rate = 32;
};
class DescriptorPool {
@@ -75,6 +80,14 @@ public:
private:
DescriptorBank& Bank(const DescriptorBankInfo& reqs);
struct CacheEntry {
DescriptorBankInfo info{};
DescriptorBank* bank{nullptr};
u64 stamp{0};
};
std::mutex cache_mutex{};
std::array<CacheEntry, 8> cache_{}; //test and then adjust
u64 cache_tick_{0};
const Device& device;
MasterSemaphore& master_semaphore;