From 256b1dc346e19bc60c2884d4af875fc53ef0a99a Mon Sep 17 00:00:00 2001 From: Sssnowyyy <78863999+Sssnowyyy@users.noreply.github.com> Date: Mon, 2 Nov 2026 11:34:40 -0500 Subject: video_core: don't execute command lists copied before their channel waited cce6d44af2 executes each command list entry from a copy of its words taken at submit. Games submit command lists before writing them: the lists wait behind a semaphore acquire, and the game writes their commands just before it releases the acquire (Mario Kart World after present). The copies of those lists were stale. Pokopia stopped after its first frame on macOS: its GPU never reached the fence the game spun on (EDEN_NX2_PB_SNAPSHOT=0 made it run again). Count each channel's suspensions on an acquire and the resumes after them, and record the count with each copy. A list copied while its channel was suspended, or whose channel suspended since, reads guest memory instead. Lists submitted and run without a wait in between keep the copy. EDEN_NX2_PB_SNAPSHOT=0 still disables it altogether. Assisted-by: Claude Sonnet 5.5 (first version); Claude Opus 5.5 (bisect, suspension count, testing and commit message) --- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 848c15d6f8..79586446d5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -445,7 +445,10 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL const char* value = std::getenv("EDEN_NX2_PB_SNAPSHOT"); return value == nullptr || value[0] != '0'; }(); - if (snapshot && channel_state->memory_manager) { + if (snapshot && channel_state->memory_manager && channel_state->payload) { + // Before the copy: a suspension during it must count as one after it. + entries.snapshot_suspensions = + channel_state->payload->dma_pusher.suspensions.load(std::memory_order_acquire); size_t words = 0; for (const auto& entry : entries.command_lists) { words += entry.size; -- cgit v1.2.3