From dd790abab00379c232ea508fc43e87bd05d003f6 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 21 Jan 2021 19:08:15 -0300 Subject: [PATCH 1/3] video_core/memory_manager: Add GPU address based flush method Allow flushing rasterizer contents based on a GPU address. --- src/video_core/memory_manager.cpp | 15 +++++++++++++++ src/video_core/memory_manager.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 65feff588d..1926bb025c 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -314,6 +314,21 @@ void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buf } } +void MemoryManager::FlushRegion(GPUVAddr gpu_addr, size_t size) const { + size_t remaining_size{size}; + size_t page_index{gpu_addr >> page_bits}; + size_t page_offset{gpu_addr & page_mask}; + while (remaining_size > 0) { + const size_t num_bytes{std::min(page_size - page_offset, remaining_size)}; + if (const auto page_addr{GpuToCpuAddress(page_index << page_bits)}; page_addr) { + rasterizer->FlushRegion(*page_addr + page_offset, num_bytes); + } + ++page_index; + page_offset = 0; + remaining_size -= num_bytes; + } +} + void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size) { std::vector tmp_buffer(size); ReadBlock(gpu_src_addr, tmp_buffer.data(), size); diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index c35e576894..e3c0c53a90 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -131,6 +131,8 @@ private: void TryLockPage(PageEntry page_entry, std::size_t size); void TryUnlockPage(PageEntry page_entry, std::size_t size); + void FlushRegion(GPUVAddr gpu_addr, size_t size) const; + [[nodiscard]] static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) { return (gpu_addr >> page_bits) & page_table_mask; } From 0e9a6759f90cd45ef708c17b2fb1f74db5c8fce7 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 21 Jan 2021 19:08:43 -0300 Subject: [PATCH 2/3] video_core/memory_manager: Flush destination buffer on CopyBlock When we copy into a buffer, it might contain data modified from the GPU on the same pages. Because of this, we have to flush the contents before writing new data. An alternative approach would be to write the data in place, but games can also write data in other ways, invalidating our contents. Fixes geometry in Zombie Panic in Wonderland DX. --- src/video_core/memory_manager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 1926bb025c..e5d357773e 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -332,6 +332,10 @@ void MemoryManager::FlushRegion(GPUVAddr gpu_addr, size_t size) const { void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size) { std::vector tmp_buffer(size); ReadBlock(gpu_src_addr, tmp_buffer.data(), size); + + // The output block must be flushed in case it has data modified from the GPU. + // Fixes NPC geometry in Zombie Panic in Wonderland DX + FlushRegion(gpu_dest_addr, size); WriteBlock(gpu_dest_addr, tmp_buffer.data(), size); } From b7febb5625380d693a2dbae14490a586b699ddc2 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 21 Jan 2021 19:14:49 -0300 Subject: [PATCH 3/3] video_core/memory_manager: Remove unused CopyBlockUnsafe This function was not being used. --- src/video_core/memory_manager.cpp | 7 ------- src/video_core/memory_manager.h | 1 - 2 files changed, 8 deletions(-) diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index e5d357773e..f5cdf548e5 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -339,13 +339,6 @@ void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std WriteBlock(gpu_dest_addr, tmp_buffer.data(), size); } -void MemoryManager::CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, - std::size_t size) { - std::vector tmp_buffer(size); - ReadBlockUnsafe(gpu_src_addr, tmp_buffer.data(), size); - WriteBlockUnsafe(gpu_dest_addr, tmp_buffer.data(), size); -} - bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { const auto cpu_addr{GpuToCpuAddress(gpu_addr)}; if (!cpu_addr) { diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index e3c0c53a90..a52fbbd8c4 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -107,7 +107,6 @@ public: */ void ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const; void WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size); - void CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size); /** * IsGranularRange checks if a gpu region can be simply read with a pointer.