diff options
| -rw-r--r-- | src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 24 |
2 files changed, 27 insertions, 5 deletions
diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index 336338e62..d1e59f22e 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp | |||
| @@ -35,6 +35,7 @@ struct Bias { | |||
| 35 | u32 index; | 35 | u32 index; |
| 36 | u32 offset_begin; | 36 | u32 offset_begin; |
| 37 | u32 offset_end; | 37 | u32 offset_end; |
| 38 | u32 alignment; | ||
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | using boost::container::flat_set; | 41 | using boost::container::flat_set; |
| @@ -349,7 +350,8 @@ std::optional<StorageBufferAddr> Track(const IR::Value& value, const Bias* bias) | |||
| 349 | .index = index.U32(), | 350 | .index = index.U32(), |
| 350 | .offset = offset.U32(), | 351 | .offset = offset.U32(), |
| 351 | }; | 352 | }; |
| 352 | if (!Common::IsAligned(storage_buffer.offset, 16)) { | 353 | const u32 alignment{bias ? bias->alignment : 8U}; |
| 354 | if (!Common::IsAligned(storage_buffer.offset, alignment)) { | ||
| 353 | // The SSBO pointer has to be aligned | 355 | // The SSBO pointer has to be aligned |
| 354 | return std::nullopt; | 356 | return std::nullopt; |
| 355 | } | 357 | } |
| @@ -371,6 +373,7 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageInfo& info) | |||
| 371 | .index = 0, | 373 | .index = 0, |
| 372 | .offset_begin = 0x110, | 374 | .offset_begin = 0x110, |
| 373 | .offset_end = 0x610, | 375 | .offset_end = 0x610, |
| 376 | .alignment = 16, | ||
| 374 | }; | 377 | }; |
| 375 | // Track the low address of the instruction | 378 | // Track the low address of the instruction |
| 376 | const std::optional<LowAddrInfo> low_addr_info{TrackLowAddress(&inst)}; | 379 | const std::optional<LowAddrInfo> low_addr_info{TrackLowAddress(&inst)}; |
| @@ -386,8 +389,11 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageInfo& info) | |||
| 386 | storage_buffer = Track(low_addr, nullptr); | 389 | storage_buffer = Track(low_addr, nullptr); |
| 387 | if (!storage_buffer) { | 390 | if (!storage_buffer) { |
| 388 | // If that also fails, use NVN fallbacks | 391 | // If that also fails, use NVN fallbacks |
| 392 | LOG_WARNING(Shader, "Storage buffer failed to track, using global memory fallbacks"); | ||
| 389 | return; | 393 | return; |
| 390 | } | 394 | } |
| 395 | LOG_WARNING(Shader, "Storage buffer tracked without bias, index {} offset {}", | ||
| 396 | storage_buffer->index, storage_buffer->offset); | ||
| 391 | } | 397 | } |
| 392 | // Collect storage buffer and the instruction | 398 | // Collect storage buffer and the instruction |
| 393 | if (IsGlobalMemoryWrite(inst)) { | 399 | if (IsGlobalMemoryWrite(inst)) { |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 2a150ccdc..1f656ffa8 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -383,7 +383,8 @@ private: | |||
| 383 | 383 | ||
| 384 | void NotifyBufferDeletion(); | 384 | void NotifyBufferDeletion(); |
| 385 | 385 | ||
| 386 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, bool is_written = false) const; | 386 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index, |
| 387 | bool is_written = false) const; | ||
| 387 | 388 | ||
| 388 | [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size, | 389 | [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size, |
| 389 | PixelFormat format); | 390 | PixelFormat format); |
| @@ -802,7 +803,7 @@ void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, | |||
| 802 | 803 | ||
| 803 | const auto& cbufs = maxwell3d->state.shader_stages[stage]; | 804 | const auto& cbufs = maxwell3d->state.shader_stages[stage]; |
| 804 | const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset; | 805 | const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset; |
| 805 | storage_buffers[stage][ssbo_index] = StorageBufferBinding(ssbo_addr, is_written); | 806 | storage_buffers[stage][ssbo_index] = StorageBufferBinding(ssbo_addr, cbuf_index, is_written); |
| 806 | } | 807 | } |
| 807 | 808 | ||
| 808 | template <class P> | 809 | template <class P> |
| @@ -842,7 +843,7 @@ void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, | |||
| 842 | 843 | ||
| 843 | const auto& cbufs = launch_desc.const_buffer_config; | 844 | const auto& cbufs = launch_desc.const_buffer_config; |
| 844 | const GPUVAddr ssbo_addr = cbufs[cbuf_index].Address() + cbuf_offset; | 845 | const GPUVAddr ssbo_addr = cbufs[cbuf_index].Address() + cbuf_offset; |
| 845 | compute_storage_buffers[ssbo_index] = StorageBufferBinding(ssbo_addr, is_written); | 846 | compute_storage_buffers[ssbo_index] = StorageBufferBinding(ssbo_addr, cbuf_index, is_written); |
| 846 | } | 847 | } |
| 847 | 848 | ||
| 848 | template <class P> | 849 | template <class P> |
| @@ -1988,11 +1989,26 @@ void BufferCache<P>::NotifyBufferDeletion() { | |||
| 1988 | 1989 | ||
| 1989 | template <class P> | 1990 | template <class P> |
| 1990 | typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, | 1991 | typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, |
| 1992 | u32 cbuf_index, | ||
| 1991 | bool is_written) const { | 1993 | bool is_written) const { |
| 1992 | const GPUVAddr gpu_addr = gpu_memory->Read<u64>(ssbo_addr); | 1994 | const GPUVAddr gpu_addr = gpu_memory->Read<u64>(ssbo_addr); |
| 1993 | const u32 size = gpu_memory->Read<u32>(ssbo_addr + 8); | 1995 | const auto size = [&]() { |
| 1996 | const bool is_nvn_cbuf = cbuf_index == 0; | ||
| 1997 | // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size. | ||
| 1998 | if (is_nvn_cbuf) { | ||
| 1999 | return gpu_memory->Read<u32>(ssbo_addr + 8); | ||
| 2000 | } | ||
| 2001 | // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined | ||
| 2002 | // cbufs, which do not store the sizes adjacent to the addresses, so use the fully | ||
| 2003 | // mapped buffer size for now. | ||
| 2004 | const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr)); | ||
| 2005 | LOG_INFO(HW_GPU, "Binding storage buffer for cbuf index {}, MemoryLayoutSize 0x{:X}", | ||
| 2006 | cbuf_index, memory_layout_size); | ||
| 2007 | return memory_layout_size; | ||
| 2008 | }(); | ||
| 1994 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); | 2009 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); |
| 1995 | if (!cpu_addr || size == 0) { | 2010 | if (!cpu_addr || size == 0) { |
| 2011 | LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index); | ||
| 1996 | return NULL_BINDING; | 2012 | return NULL_BINDING; |
| 1997 | } | 2013 | } |
| 1998 | const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, Core::Memory::YUZU_PAGESIZE); | 2014 | const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, Core::Memory::YUZU_PAGESIZE); |