From a6d49872a14e7dd44f0c94528abec14becfe4832 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 22 Aug 2026 03:34:01 -0400 Subject: [PATCH] [TEST] Adjustments on the pipeline cache + optimized vertex buffer refinement --- src/video_core/buffer_cache/buffer_cache.h | 12 +++++----- .../renderer_vulkan/vk_compute_pipeline.cpp | 5 ++++- .../renderer_vulkan/vk_compute_pipeline.h | 3 +++ .../renderer_vulkan/vk_graphics_pipeline.cpp | 7 ++++-- .../renderer_vulkan/vk_graphics_pipeline.h | 5 ++++- .../renderer_vulkan/vk_pipeline_cache.cpp | 22 +++++++++++++------ .../renderer_vulkan/vk_pipeline_cache.h | 3 +++ 7 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 95c67f865a..127a23637f 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -811,7 +811,7 @@ void BufferCache

::BindHostVertexBuffers() { if (use_optimized_vertex_buffers) { auto& flags = maxwell3d->dirty.flags; const u32 enabled_mask = enabled_vertex_buffers_mask; - bool any_dirty = false; + u32 dirty_mask = 0; u32 pending_mask = enabled_mask; while (pending_mask != 0) { const u32 index = std::countr_zero(pending_mask); @@ -820,13 +820,15 @@ void BufferCache

::BindHostVertexBuffers() { Buffer& buffer = slot_buffers[binding.buffer_id]; TouchBuffer(buffer, binding.buffer_id); SynchronizeBuffer(buffer, binding.device_addr, binding.size); - any_dirty |= flags[Dirty::VertexBuffer0 + index]; + if (flags[Dirty::VertexBuffer0 + index]) { + dirty_mask |= 1u << index; + } } - if (enabled_mask == 0 || !any_dirty) { + if (dirty_mask == 0) { return; } - const u32 min_index = static_cast(std::countr_zero(enabled_mask)); - const u32 max_index = 32u - static_cast(std::countl_zero(enabled_mask)); + const u32 min_index = static_cast(std::countr_zero(dirty_mask)); + const u32 max_index = 32u - static_cast(std::countl_zero(dirty_mask)); HostBindings bindings{}; bindings.min_index = min_index; bindings.max_index = max_index; diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 29356cfcec..6c2ba89026 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -32,6 +32,7 @@ using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET; using Tegra::Texture::TexturePair; ComputePipeline::ComputePipeline(const Device& device_, Scheduler& scheduler, vk::PipelineCache& pipeline_cache_, + std::shared_mutex& pipeline_cache_mutex_, DescriptorPool& descriptor_pool, GuestDescriptorQueue& guest_descriptor_queue_, DescriptorBufferRing& descriptor_buffer_ring_, @@ -40,7 +41,8 @@ ComputePipeline::ComputePipeline(const Device& device_, Scheduler& scheduler, vk VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, vk::ShaderModule spv_module_, u64 shader_hash_) : device{device_}, - pipeline_cache(pipeline_cache_), guest_descriptor_queue{guest_descriptor_queue_}, + pipeline_cache(pipeline_cache_), pipeline_cache_mutex(pipeline_cache_mutex_), + guest_descriptor_queue{guest_descriptor_queue_}, descriptor_buffer_ring{descriptor_buffer_ring_}, info{info_}, shader_hash{shader_hash_}, spv_module(std::move(spv_module_)) { if (shader_notify) { @@ -111,6 +113,7 @@ ComputePipeline::ComputePipeline(const Device& device_, Scheduler& scheduler, vk .basePipelineIndex = 0, }; try { + std::shared_lock cache_lock{pipeline_cache_mutex}; pipeline = device.GetLogical().CreateComputePipeline(compute_ci, *pipeline_cache); } catch (const vk::Exception& exception) { LOG_CRITICAL(Render_Vulkan, "Adreno rejected compute shader {:016X}: {}", shader_hash, diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index fba0519b58..65d4bb1382 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "common/common_types.h" #include "common/thread_worker.h" @@ -34,6 +35,7 @@ class Scheduler; class ComputePipeline { public: explicit ComputePipeline(const Device& device, Scheduler& scheduler, vk::PipelineCache& pipeline_cache, + std::shared_mutex& pipeline_cache_mutex, DescriptorPool& descriptor_pool, GuestDescriptorQueue& guest_descriptor_queue, DescriptorBufferRing& descriptor_buffer_ring, @@ -59,6 +61,7 @@ public: private: const Device& device; vk::PipelineCache& pipeline_cache; + std::shared_mutex& pipeline_cache_mutex; GuestDescriptorQueue& guest_descriptor_queue; DescriptorBufferRing& descriptor_buffer_ring; Shader::Info info; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index a2eee7f16d..554cc038ef 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -251,7 +251,8 @@ ConfigureFuncPtr ConfigureFunc(const std::array& m // TODO(crueter): This is the worst-formatted code I have EVER seen GraphicsPipeline::GraphicsPipeline( Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, - vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify, + vk::PipelineCache& pipeline_cache_, std::shared_mutex& pipeline_cache_mutex_, + VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, GuestDescriptorQueue& guest_descriptor_queue_, DescriptorBufferRing& descriptor_buffer_ring_, Common::ThreadWorker* worker_thread, @@ -259,7 +260,8 @@ GraphicsPipeline::GraphicsPipeline( const GraphicsPipelineCacheKey& key_, std::array stages, const std::array& infos) : key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, - pipeline_cache(pipeline_cache_), scheduler{scheduler_}, + pipeline_cache(pipeline_cache_), pipeline_cache_mutex(pipeline_cache_mutex_), + scheduler{scheduler_}, guest_descriptor_queue{guest_descriptor_queue_}, descriptor_buffer_ring{descriptor_buffer_ring_}, spv_modules{std::move(stages)} { if (shader_notify) { @@ -1081,6 +1083,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; } + std::shared_lock cache_lock{pipeline_cache_mutex}; pipeline = device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index b1ac5a3fcc..ebb92a8f16 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -78,7 +79,8 @@ class GraphicsPipeline { public: explicit GraphicsPipeline( Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, - vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify, + vk::PipelineCache& pipeline_cache, std::shared_mutex& pipeline_cache_mutex, + VideoCore::ShaderNotify* shader_notify, const Device& device, DescriptorPool& descriptor_pool, GuestDescriptorQueue& guest_descriptor_queue, DescriptorBufferRing& descriptor_buffer_ring, Common::ThreadWorker* worker_thread, @@ -151,6 +153,7 @@ private: TextureCache& texture_cache; BufferCache& buffer_cache; vk::PipelineCache& pipeline_cache; + std::shared_mutex& pipeline_cache_mutex; Scheduler& scheduler; GuestDescriptorQueue& guest_descriptor_queue; DescriptorBufferRing& descriptor_buffer_ring; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 96007ec276..d1948fa59b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -553,6 +553,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, PipelineCache::~PipelineCache() { if (use_vulkan_pipeline_cache && !vulkan_pipeline_cache_filename.empty()) { + std::unique_lock lock{vulkan_pipeline_cache_mutex}; SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache, CACHE_VERSION); } @@ -612,6 +613,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading if (use_vulkan_pipeline_cache) { vulkan_pipeline_cache_filename = base_dir / "vulkan_pipelines.bin"; + std::unique_lock lock{vulkan_pipeline_cache_mutex}; vulkan_pipeline_cache = LoadVulkanPipelineCache(vulkan_pipeline_cache_filename, CACHE_VERSION); } @@ -710,6 +712,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading workers.WaitForRequests(stop_loading); if (use_vulkan_pipeline_cache) { + std::unique_lock lock{vulkan_pipeline_cache_mutex}; SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache, CACHE_VERSION); size_t size = 0; @@ -743,11 +746,14 @@ void PipelineCache::QueueVulkanPipelineCacheFlush() { pipelines_since_flush = 0; last_flush = now; serialization_thread.QueueWork([this] { - SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache, - CACHE_VERSION); - size_t size = 0; - vulkan_pipeline_cache.Read(&size, nullptr); - last_cache_size.store(size, std::memory_order_relaxed); + { + std::unique_lock lock{vulkan_pipeline_cache_mutex}; + SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache, + CACHE_VERSION); + size_t size = 0; + vulkan_pipeline_cache.Read(&size, nullptr); + last_cache_size.store(size, std::memory_order_relaxed); + } flush_in_flight.store(false, std::memory_order_release); }); } @@ -890,7 +896,8 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( } Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; return std::make_unique( - scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device, + scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, + vulkan_pipeline_cache_mutex, &shader_notify, device, descriptor_pool, guest_descriptor_queue, descriptor_buffer_ring, thread_worker, statistics, render_pass_cache, key, std::move(modules), infos); @@ -1014,7 +1021,8 @@ std::unique_ptr PipelineCache::CreateComputePipeline( spv_module.SetObjectNameEXT(name.c_str()); } Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; - return std::make_unique(device, scheduler, vulkan_pipeline_cache, descriptor_pool, + return std::make_unique(device, scheduler, vulkan_pipeline_cache, + vulkan_pipeline_cache_mutex, descriptor_pool, guest_descriptor_queue, descriptor_buffer_ring, thread_worker, statistics, &shader_notify, program.info, std::move(spv_module), diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 9d66b663f5..94cf733890 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -175,6 +177,7 @@ private: std::filesystem::path vulkan_pipeline_cache_filename; vk::PipelineCache vulkan_pipeline_cache; + std::shared_mutex vulkan_pipeline_cache_mutex; size_t pipelines_since_flush{}; std::chrono::steady_clock::time_point last_flush{}; std::atomic last_cache_size{};