From 7c9bd08df9bed2f364acf234c1371c6065c75924 Mon Sep 17 00:00:00 2001 From: psucien Date: Sun, 9 Feb 2025 17:57:37 +0100 Subject: [PATCH] fix: lower UBO max size to account buffer cache offset --- .../backend/spirv/spirv_emit_context.cpp | 2 +- src/shader_recompiler/info.h | 8 +++++--- src/video_core/renderer_vulkan/vk_instance.cpp | 8 ++++++++ src/video_core/renderer_vulkan/vk_rasterizer.cpp | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 13d727c72..b08c5108b 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -634,7 +634,7 @@ void EmitContext::DefineBuffers() { for (const auto& desc : info.buffers) { const auto sharp = desc.GetSharp(info); const bool is_storage = desc.IsStorage(sharp); - const u32 array_size = sharp.NumDwords() != 0 ? sharp.NumDwords() : MaxUboDwords; + const u32 array_size = sharp.NumDwords() != 0 ? sharp.NumDwords() : Vulkan::MaxUboSize >> 2; const auto* data_types = True(desc.used_types & IR::Type::F32) ? &F32 : &U32; const Id data_type = (*data_types)[1]; const Id record_array_type{is_storage ? TypeRuntimeArray(data_type) diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index 498752607..9516d9917 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -21,11 +21,13 @@ #include "video_core/amdgpu/liverpool.h" #include "video_core/amdgpu/resource.h" +namespace Vulkan { +extern size_t MaxUboSize; +} + namespace Shader { static constexpr size_t NumUserDataRegs = 16; -static constexpr size_t MaxUboSize = 65536; -static constexpr size_t MaxUboDwords = MaxUboSize >> 2; enum class TextureType : u32 { Color1D, @@ -51,7 +53,7 @@ struct BufferResource { bool is_formatted{}; [[nodiscard]] bool IsStorage(const AmdGpu::Buffer& buffer) const noexcept { - return buffer.GetSize() > MaxUboSize || is_written || is_gds_buffer; + return buffer.GetSize() > Vulkan::MaxUboSize || is_written || is_gds_buffer; } [[nodiscard]] constexpr AmdGpu::Buffer GetSharp(const Info& info) const noexcept; diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index e64cae87d..db7ec86a7 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -19,6 +19,8 @@ namespace Vulkan { +size_t MaxUboSize = 64_KB; + namespace { std::vector EnumeratePhysicalDevices(vk::UniqueInstance& instance) { @@ -180,6 +182,12 @@ Instance::Instance(Frontend::WindowSDL& window, s32 physical_device_index, vk::to_string(format.flags & ~GetFormatFeatureFlags(format.vk_format))); } } + + // When binding a UBO, we calculate its size considering the offset in the larger buffer cache + // underlying resource. In some cases, it may produce sizes exceeding the system maximum + // allowed UBO range, so we need to reduce the threshold to prevent issues. + MaxUboSize = + properties.limits.maxUniformBufferRange - properties.limits.minUniformBufferOffsetAlignment; } Instance::~Instance() { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 6f979a734..ffd9f4823 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -554,7 +554,6 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding } // Second pass to re-bind buffers that were updated after binding - auto& null_buffer = buffer_cache.GetBuffer(VideoCore::NULL_BUFFER_ID); for (u32 i = 0; i < buffer_bindings.size(); i++) { const auto& [buffer_id, vsharp] = buffer_bindings[i]; const auto& desc = stage.buffers[i]; @@ -566,6 +565,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding } else if (instance.IsNullDescriptorSupported()) { buffer_infos.emplace_back(VK_NULL_HANDLE, 0, VK_WHOLE_SIZE); } else { + auto& null_buffer = buffer_cache.GetBuffer(VideoCore::NULL_BUFFER_ID); buffer_infos.emplace_back(null_buffer.Handle(), 0, VK_WHOLE_SIZE); } } else {