From 0b4102c4bd4f5d2e95a61c9599377f82ee494b4a Mon Sep 17 00:00:00 2001 From: wildcard Date: Sun, 5 Oct 2025 23:11:40 +0200 Subject: [PATCH] [Vulkan] Phase 1: Descriptor Set caching --- .../renderer_vulkan/vk_descriptor_pool.cpp | 25 ++++++++++++++++-- .../renderer_vulkan/vk_descriptor_pool.h | 11 +++++++- .../renderer_vulkan/vk_graphics_pipeline.cpp | 26 ++++++++++++++----- .../renderer_vulkan/vk_graphics_pipeline.h | 3 ++- .../renderer_vulkan/vk_rasterizer.cpp | 2 ++ .../renderer_vulkan/vk_rasterizer.h | 2 +- 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index 3af9758a31..e6b9662c85 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -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) { diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h index 4aada5a006..0a8d1afaa9 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h @@ -6,7 +6,7 @@ #include #include #include - +#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 sets; + std::vector> set_states; }; class DescriptorPool { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 745389213e..c18571c54e 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -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); } diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 650c8e07ed..e81b2ac1b6 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -116,7 +116,7 @@ public: maxwell3d = maxwell3d_; gpu_memory = gpu_memory_; } - + void SetFrameNumber(u64 frame) { current_frame_number = frame; } private: template 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 diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 70ca9583f9..71533d44e9 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -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(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 30780b9cbd..bcfb3ac450 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -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);