[Vulkan] Phase 1: Descriptor Set caching
Some checks failed
eden-license / license-header (pull_request) Failing after 24s

wip
This commit is contained in:
wildcard 2025-10-05 23:12:55 +02:00
parent f6d99e5032
commit 7435d70e1e
6 changed files with 58 additions and 11 deletions

View file

@ -96,9 +96,30 @@ VkDescriptorSet DescriptorAllocator::Commit() {
const size_t index = CommitResource();
return sets[index / SETS_GROW_RATE][index % SETS_GROW_RATE];
}
VkDescriptorSet DescriptorAllocator::CommitWithTracking(u64 current_frame, const void* descriptor_data) {
const size_t index = CommitResource();
const size_t group = index / SETS_GROW_RATE;
const size_t slot = index % SETS_GROW_RATE;
set_states[group][slot].set = sets[group][slot];
set_states[group][slot].last_update_frame = current_frame;
set_states[group][slot].last_data_ptr = descriptor_data;
return set_states[group][slot].set;
}
bool DescriptorAllocator::NeedsUpdate(VkDescriptorSet set, u64 current_frame, const void* descriptor_data) const {
for (const auto& group : set_states) {
for (const auto& st : group) {
if (st.set == set) {
// Update if pointer changed or the set hasn't been updated this frame
return st.last_data_ptr != descriptor_data || st.last_update_frame != current_frame;
}
}
}
return true;
}
void DescriptorAllocator::Allocate(size_t begin, size_t end) {
sets.push_back(AllocateDescriptors(end - begin));
const size_t count = end - begin;
sets.push_back(AllocateDescriptors(count));
set_states.emplace_back(count); // create parallel state storage
}
vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) {

View file

@ -6,7 +6,7 @@
#include <shared_mutex>
#include <span>
#include <vector>
#include "common/common_types.h"
#include "shader_recompiler/shader_info.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
@ -44,7 +44,15 @@ public:
DescriptorAllocator(const DescriptorAllocator&) = delete;
VkDescriptorSet Commit();
// commit + remember when/with what we last updated this set
struct DescriptorSetState {
VkDescriptorSet set = VK_NULL_HANDLE;
u64 last_update_frame = 0;
const void* last_data_ptr = nullptr; // fast pointer compare
};
VkDescriptorSet CommitWithTracking(u64 current_frame, const void* descriptor_data);
bool NeedsUpdate(VkDescriptorSet set, u64 current_frame, const void* descriptor_data) const;
private:
explicit DescriptorAllocator(const Device& device_, MasterSemaphore& master_semaphore_,
DescriptorBank& bank_, VkDescriptorSetLayout layout_);
@ -58,6 +66,7 @@ private:
VkDescriptorSetLayout layout{};
std::vector<vk::DescriptorSets> sets;
std::vector<std::vector<DescriptorSetState>> set_states;
};
class DescriptorPool {

View file

@ -513,7 +513,25 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
const bool update_rescaling{scheduler.UpdateRescaling(is_rescaling)};
const bool bind_pipeline{scheduler.UpdateGraphicsPipeline(this)};
const void* const descriptor_data{guest_descriptor_queue.UpdateData()};
scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(),
// allocate/bind descriptor set and only update if needed
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
bool needs_update = false;
if (descriptor_set_layout) {
if (uses_push_descriptor) {
// handled below via push descriptor
} else {
descriptor_set = descriptor_allocator.CommitWithTracking(current_frame_number, descriptor_data);
needs_update = descriptor_allocator.NeedsUpdate(descriptor_set, current_frame_number, descriptor_data);
if (needs_update) {
const vk::Device& dev{device.GetLogical()};
dev.UpdateDescriptorSet(descriptor_set, *descriptor_update_template, descriptor_data);
} else {
}
}
}
scheduler.Record([this, descriptor_data, descriptor_set, bind_pipeline, rescaling_data = rescaling.Data(),
is_rescaling, update_rescaling,
uses_render_area = render_area.uses_render_area,
render_area_data = render_area.words](vk::CommandBuffer cmdbuf) {
@ -539,12 +557,8 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
return;
}
if (uses_push_descriptor) {
cmdbuf.PushDescriptorSetWithTemplateKHR(*descriptor_update_template, *pipeline_layout,
0, descriptor_data);
cmdbuf.PushDescriptorSetWithTemplateKHR(*descriptor_update_template, *pipeline_layout, 0, descriptor_data);
} else {
const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()};
const vk::Device& dev{device.GetLogical()};
dev.UpdateDescriptorSet(descriptor_set, *descriptor_update_template, descriptor_data);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0,
descriptor_set, nullptr);
}

View file

@ -116,7 +116,7 @@ public:
maxwell3d = maxwell3d_;
gpu_memory = gpu_memory_;
}
void SetFrameNumber(u64 frame) { current_frame_number = frame; }
private:
template <typename Spec>
bool ConfigureImpl(bool is_indexed);
@ -160,6 +160,7 @@ private:
std::mutex build_mutex;
std::atomic_bool is_built{false};
bool uses_push_descriptor{false};
u64 current_frame_number{0};
};
} // namespace Vulkan

View file

@ -217,6 +217,7 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
// update engine as channel may be different.
pipeline->SetEngine(maxwell3d, gpu_memory);
pipeline->SetFrameNumber(current_frame_number);
if (!pipeline->Configure(is_indexed))
return;
@ -759,6 +760,7 @@ void RasterizerVulkan::FlushCommands() {
}
void RasterizerVulkan::TickFrame() {
current_frame_number++;
draw_counter = 0;
guest_descriptor_queue.TickFrame();
compute_pass_descriptor_queue.TickFrame();

View file

@ -160,7 +160,7 @@ private:
void UpdateDynamicStates();
void HandleTransformFeedback();
u64 current_frame_number{0};
void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs);