From cfae726289e38008ace558ab8bd42fd5189a3ab6 Mon Sep 17 00:00:00 2001 From: xbzk Date: Fri, 26 Dec 2025 04:54:14 +0100 Subject: [PATCH] [video_core] nvn descriptor layout fix (#3206) Yxzx presumes this: // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size. But in MCI i`ve discovered that there are no sizes, both registers are GPU addresses (hence the 2.8gb allocation, it was an address actually) Method could be much simpler but for safety i`ve routed both old and new worlds. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3206 Reviewed-by: Caio Oliveira Reviewed-by: Lizzie Co-authored-by: xbzk Co-committed-by: xbzk --- src/video_core/buffer_cache/buffer_cache.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 39c56fb33f..5b5dc1c219 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -1705,21 +1705,26 @@ Binding BufferCache

::StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index, return NULL_BINDING; } + // xbzk: New size logic. Fixes MCI. + // If ever the * comment below prove wrong, the 'if' block may be removed. const auto size = [&]() { const bool is_nvn_cbuf = cbuf_index == 0; - // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size. if (is_nvn_cbuf) { - const u32 ssbo_size = gpu_memory->Read(ssbo_addr + 8); - if (ssbo_size != 0) { - return ssbo_size; + // * The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size. + const u64 next_qword = gpu_memory->Read(ssbo_addr + 8); + const u32 upper_32 = static_cast(next_qword >> 32); + // Hardware-based detection: GPU addresses have non-zero upper bits + if (upper_32 == 0) { + // This is a size field, not a GPU address + return static_cast(next_qword); // Return lower_32 } } - // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined - // cbufs, which do not store the sizes adjacent to the addresses, so use the fully - // mapped buffer size for now. + // Fall through: either not NVN cbuf (Doom Eternal & +), or NVN but ssbo_addr+8 is a GPU address (MCI) const u32 memory_layout_size = static_cast(gpu_memory->GetMemoryLayoutSize(gpu_addr)); + // Cap at 8MB to prevent allocator overflow from misinterpreted addresses return (std::min)(memory_layout_size, static_cast(8_MiB)); }(); + // Alignment only applies to the offset of the buffer const u32 alignment = runtime.GetStorageBufferAlignment(); const GPUVAddr aligned_gpu_addr = Common::AlignDown(gpu_addr, alignment);