From edabc3e61486d59d67f33dfd992154927197450f Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Sun, 1 Nov 2026 00:11:02 -0400 Subject: memory_manager: copy big pages without host memory page by page GPU reads and writes of a continuous big page copied through GetPointer() without checking it; the small-page path checks. A big page whose host memory is not there yet (a Switch 2 region backed as it is written, with its backing pending) made that memcpy fault: Mario Kart World crashed in WriteBlockImpl (access violation) on its title screen in two runs of a build on the 10-31 nx2. Such a page now takes the per-page copy, which reports and skips missing pages, as non-continuous big pages already did. Three 10-minute runs after the change, no crash. --- src/video_core/memory_manager.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/video_core/memory_manager.cpp') diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 9111ba10d2..a7d8aec382 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -431,11 +431,14 @@ void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std: if (!unsafe) { rasterizer->FlushRegion(dev_addr_base, copy_amount, which); } - if (!IsBigPageContinuous(page_index)) [[unlikely]] { - memory.ReadBlockUnsafe(dev_addr_base, dest_buffer, copy_amount); - } else { - u8* physical = memory.GetPointer(dev_addr_base); + // A continuous big page may still have no host memory (a Switch 2 region backed as it is + // written, while its backing is pending): the per-page copy handles that. + u8* const physical = IsBigPageContinuous(page_index) ? memory.GetPointer(dev_addr_base) + : nullptr; + if (physical != nullptr) [[likely]] { std::memcpy(dest_buffer, physical, copy_amount); + } else { + memory.ReadBlockUnsafe(dev_addr_base, dest_buffer, copy_amount); } dest_buffer = static_cast(dest_buffer) + copy_amount; }; @@ -485,11 +488,12 @@ void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffe if (!unsafe) { rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which); } - if (!IsBigPageContinuous(page_index)) [[unlikely]] { - memory.WriteBlockUnsafe(dev_addr_base, src_buffer, copy_amount); - } else { - u8* physical = memory.GetPointer(dev_addr_base); + u8* const physical = IsBigPageContinuous(page_index) ? memory.GetPointer(dev_addr_base) + : nullptr; + if (physical != nullptr) [[likely]] { std::memcpy(physical, src_buffer, copy_amount); + } else { + memory.WriteBlockUnsafe(dev_addr_base, src_buffer, copy_amount); } src_buffer = static_cast(src_buffer) + copy_amount; }; -- cgit v1.2.3