From 12f709de65daeea39d0f68bd05ac68169703a086 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Tue, 25 Nov 2025 17:53:06 -0400 Subject: [PATCH] [vk, qcom] Binding buffer limits --- src/video_core/buffer_cache/buffer_cache.h | 48 +++++++++++++++++++ .../buffer_cache/buffer_cache_base.h | 4 ++ .../renderer_vulkan/vk_buffer_cache.cpp | 7 +++ .../renderer_vulkan/vk_buffer_cache.h | 13 +++++ src/video_core/vulkan_common/vulkan_device.h | 10 ++++ 5 files changed, 82 insertions(+) diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index ddd940c6d2..779d6a1822 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -433,6 +433,12 @@ void BufferCache

::SetComputeUniformBufferState(u32 mask, template void BufferCache

::UnbindGraphicsStorageBuffers(size_t stage) { + if constexpr (requires { runtime.ShouldLimitDynamicStorageBuffers(); }) { + if (runtime.ShouldLimitDynamicStorageBuffers()) { + channel_state->total_graphics_storage_buffers -= + static_cast(std::popcount(channel_state->enabled_storage_buffers[stage])); + } + } channel_state->enabled_storage_buffers[stage] = 0; channel_state->written_storage_buffers[stage] = 0; } @@ -440,8 +446,26 @@ void BufferCache

::UnbindGraphicsStorageBuffers(size_t stage) { template bool BufferCache

::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset, bool is_written) { + const bool already_enabled = + ((channel_state->enabled_storage_buffers[stage] >> ssbo_index) & 1U) != 0; + if constexpr (requires { runtime.ShouldLimitDynamicStorageBuffers(); }) { + if (runtime.ShouldLimitDynamicStorageBuffers() && !already_enabled) { + const u32 max_bindings = runtime.GetMaxDynamicStorageBuffers(); + if (channel_state->total_graphics_storage_buffers >= max_bindings) { + LOG_WARNING(HW_GPU, + "Skipping graphics storage buffer {} due to driver limit {}", + ssbo_index, max_bindings); + return false; + } + } + } channel_state->enabled_storage_buffers[stage] |= 1U << ssbo_index; channel_state->written_storage_buffers[stage] |= (is_written ? 1U : 0U) << ssbo_index; + if constexpr (requires { runtime.ShouldLimitDynamicStorageBuffers(); }) { + if (runtime.ShouldLimitDynamicStorageBuffers() && !already_enabled) { + ++channel_state->total_graphics_storage_buffers; + } + } const auto& cbufs = maxwell3d->state.shader_stages[stage]; const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset; @@ -472,6 +496,12 @@ void BufferCache

::BindGraphicsTextureBuffer(size_t stage, size_t tbo_index, G template void BufferCache

::UnbindComputeStorageBuffers() { + if constexpr (requires { runtime.ShouldLimitDynamicStorageBuffers(); }) { + if (runtime.ShouldLimitDynamicStorageBuffers()) { + channel_state->total_compute_storage_buffers -= + static_cast(std::popcount(channel_state->enabled_compute_storage_buffers)); + } + } channel_state->enabled_compute_storage_buffers = 0; channel_state->written_compute_storage_buffers = 0; channel_state->image_compute_texture_buffers = 0; @@ -485,8 +515,26 @@ void BufferCache

::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, ssbo_index); return; } + const bool already_enabled = + ((channel_state->enabled_compute_storage_buffers >> ssbo_index) & 1U) != 0; + if constexpr (requires { runtime.ShouldLimitDynamicStorageBuffers(); }) { + if (runtime.ShouldLimitDynamicStorageBuffers() && !already_enabled) { + const u32 max_bindings = runtime.GetMaxDynamicStorageBuffers(); + if (channel_state->total_compute_storage_buffers >= max_bindings) { + LOG_WARNING(HW_GPU, + "Skipping compute storage buffer {} due to driver limit {}", + ssbo_index, max_bindings); + return; + } + } + } channel_state->enabled_compute_storage_buffers |= 1U << ssbo_index; channel_state->written_compute_storage_buffers |= (is_written ? 1U : 0U) << ssbo_index; + if constexpr (requires { runtime.ShouldLimitDynamicStorageBuffers(); }) { + if (runtime.ShouldLimitDynamicStorageBuffers() && !already_enabled) { + ++channel_state->total_compute_storage_buffers; + } + } const auto& launch_desc = kepler_compute->launch_description; if (((launch_desc.const_buffer_enable_mask >> cbuf_index) & 1) == 0) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 1b551931a4..ed50634683 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -132,6 +133,9 @@ public: u32 enabled_compute_storage_buffers = 0; u32 written_compute_storage_buffers = 0; + u32 total_graphics_storage_buffers = 0; + u32 total_compute_storage_buffers = 0; + std::array enabled_texture_buffers{}; std::array written_texture_buffers{}; std::array image_texture_buffers{}; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 1aec92aae4..821ad82562 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -333,6 +333,13 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m staging_pool{staging_pool_}, guest_descriptor_queue{guest_descriptor_queue_}, quad_index_pass(device, scheduler, descriptor_pool, staging_pool, compute_pass_descriptor_queue) { + const VkDriverIdKHR driver_id = device.GetDriverID(); + limit_dynamic_storage_buffers = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || + driver_id == VK_DRIVER_ID_MESA_TURNIP || + driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; + if (limit_dynamic_storage_buffers) { + max_dynamic_storage_buffers = device.GetMaxDescriptorSetStorageBuffersDynamic(); + } if (device.GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY) { // TODO: FixMe: Uint8Pass compute shader does not build on some Qualcomm drivers. uint8_pass = std::make_unique(device, scheduler, descriptor_pool, staging_pool, diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index dd85ad7c0d..4cf2510124 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "video_core/buffer_cache/buffer_cache_base.h" #include "video_core/buffer_cache/memory_tracker_base.h" #include "video_core/buffer_cache/usage_tracker.h" @@ -155,6 +157,14 @@ public: guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format)); } + bool ShouldLimitDynamicStorageBuffers() const { + return limit_dynamic_storage_buffers; + } + + u32 GetMaxDynamicStorageBuffers() const { + return max_dynamic_storage_buffers; + } + private: void BindBuffer(VkBuffer buffer, u32 offset, u32 size) { guest_descriptor_queue.AddBuffer(buffer, offset, size); @@ -194,6 +204,9 @@ private: std::unique_ptr uint8_pass; QuadIndexedPass quad_index_pass; + + bool limit_dynamic_storage_buffers = false; + u32 max_dynamic_storage_buffers = std::numeric_limits::max(); }; struct BufferCacheParams { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index f572f08241..bf88791f90 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -326,6 +326,16 @@ public: return properties.properties.limits.maxComputeSharedMemorySize; } + /// Returns the maximum number of dynamic storage buffer descriptors per set. + u32 GetMaxDescriptorSetStorageBuffersDynamic() const { + return properties.properties.limits.maxDescriptorSetStorageBuffersDynamic; + } + + /// Returns the maximum number of dynamic uniform buffer descriptors per set. + u32 GetMaxDescriptorSetUniformBuffersDynamic() const { + return properties.properties.limits.maxDescriptorSetUniformBuffersDynamic; + } + /// Returns float control properties of the device. const VkPhysicalDeviceFloatControlsPropertiesKHR& FloatControlProperties() const { return properties.float_controls;