diff options
Diffstat (limited to 'src')
| -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 06fd40851..20faa65da 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -366,7 +366,8 @@ private: | |||
| 366 | 366 | ||
| 367 | void NotifyBufferDeletion(); | 367 | void NotifyBufferDeletion(); |
| 368 | 368 | ||
| 369 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, bool is_written = false) const; | 369 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index, |
| 370 | bool is_written = false) const; | ||
| 370 | 371 | ||
| 371 | [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size, | 372 | [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size, |
| 372 | PixelFormat format); | 373 | PixelFormat format); |
| @@ -749,7 +750,7 @@ void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, | |||
| 749 | 750 | ||
| 750 | const auto& cbufs = maxwell3d->state.shader_stages[stage]; | 751 | const auto& cbufs = maxwell3d->state.shader_stages[stage]; |
| 751 | const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset; | 752 | const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset; |
| 752 | storage_buffers[stage][ssbo_index] = StorageBufferBinding(ssbo_addr, is_written); | 753 | storage_buffers[stage][ssbo_index] = StorageBufferBinding(ssbo_addr, cbuf_index, is_written); |
| 753 | } | 754 | } |
| 754 | 755 | ||
| 755 | template <class P> | 756 | template <class P> |
| @@ -789,7 +790,7 @@ void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, | |||
| 789 | 790 | ||
| 790 | const auto& cbufs = launch_desc.const_buffer_config; | 791 | const auto& cbufs = launch_desc.const_buffer_config; |
| 791 | const GPUVAddr ssbo_addr = cbufs[cbuf_index].Address() + cbuf_offset; | 792 | const GPUVAddr ssbo_addr = cbufs[cbuf_index].Address() + cbuf_offset; |
| 792 | compute_storage_buffers[ssbo_index] = StorageBufferBinding(ssbo_addr, is_written); | 793 | compute_storage_buffers[ssbo_index] = StorageBufferBinding(ssbo_addr, cbuf_index, is_written); |
| 793 | } | 794 | } |
| 794 | 795 | ||
| 795 | template <class P> | 796 | template <class P> |
| @@ -1935,11 +1936,26 @@ void BufferCache<P>::NotifyBufferDeletion() { | |||
| 1935 | 1936 | ||
| 1936 | template <class P> | 1937 | template <class P> |
| 1937 | typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, | 1938 | typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, |
| 1939 | u32 cbuf_index, | ||
| 1938 | bool is_written) const { | 1940 | bool is_written) const { |
| 1939 | const GPUVAddr gpu_addr = gpu_memory->Read<u64>(ssbo_addr); | 1941 | const GPUVAddr gpu_addr = gpu_memory->Read<u64>(ssbo_addr); |
| 1940 | const u32 size = gpu_memory->Read<u32>(ssbo_addr + 8); | 1942 | const auto size = [&]() { |
| 1943 | const bool is_nvn_cbuf = cbuf_index == 0; | ||
| 1944 | // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size. | ||
| 1945 | if (is_nvn_cbuf) { | ||
| 1946 | return gpu_memory->Read<u32>(ssbo_addr + 8); | ||
| 1947 | } | ||
| 1948 | // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined | ||
| 1949 | // cbufs, which do not store the sizes adjacent to the addresses, so use the fully | ||
| 1950 | // mapped buffer size for now. | ||
| 1951 | const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr)); | ||
| 1952 | LOG_INFO(HW_GPU, "Binding storage buffer for cbuf index {}, MemoryLayoutSize 0x{:X}", | ||
| 1953 | cbuf_index, memory_layout_size); | ||
| 1954 | return memory_layout_size; | ||
| 1955 | }(); | ||
| 1941 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); | 1956 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); |
| 1942 | if (!cpu_addr || size == 0) { | 1957 | if (!cpu_addr || size == 0) { |
| 1958 | LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index); | ||
| 1943 | return NULL_BINDING; | 1959 | return NULL_BINDING; |
| 1944 | } | 1960 | } |
| 1945 | const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, Core::Memory::YUZU_PAGESIZE); | 1961 | const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, Core::Memory::YUZU_PAGESIZE); |