diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/dma_pusher.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/dma_pusher.h | 9 | ||||
| -rw-r--r-- | src/video_core/engines/puller.cpp | 2 |
4 files changed, 18 insertions, 1 deletions
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; diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index 6b93bb7f60..6a79e0570e 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp @@ -162,6 +162,9 @@ bool DmaPusher::Step() { // read: their words at submit time are an older frame's. const bool submitted = command_resume_offset == 0 && dma_pushbuffer_subindex < command_list.submitted_offsets.size() && + (command_list.snapshot_suspensions & 1) == 0 && + command_list.snapshot_suspensions == + suspensions.load(std::memory_order_acquire) && !IsGpuWrittenCommands(dma_state.dma_get, size_t{header.size} * sizeof(u32)) && !(use_safe && memory_manager.IsMemoryDirty(dma_state.dma_get, diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h index 289786bb9e..feab652bb5 100644 --- a/src/video_core/dma_pusher.h +++ b/src/video_core/dma_pusher.h @@ -7,6 +7,7 @@ #pragma once #include <array> +#include <atomic> #include <condition_variable> #include <optional> #include <span> @@ -121,6 +122,10 @@ struct CommandList final { /// executed instead of the memory, which the game may already be refilling for a later frame. std::vector<CommandHeader> submitted_words; std::vector<u32> submitted_offsets; + /// DmaPusher::suspensions when the words were copied. A list copied during a suspension, or + /// that waited behind one, reads memory instead: games write the commands it runs before they + /// release the acquire. + u64 snapshot_suspensions = 0; }; /// FNV-1a over pushbuffer words (EDEN_NX2_PB_CHECK). @@ -139,6 +144,10 @@ inline u64 HashPushbufferWords(std::span<const u32> words) { /// details on this implementation. class DmaPusher final { public: + /// Counts suspensions on a semaphore acquire and the resumes after them, so it is odd while + /// the channel is suspended (see CommandList::snapshot_suspensions). + std::atomic<u64> suspensions{0}; + explicit DmaPusher(Core::System& system_, MemoryManager& memory_manager_, Control::ChannelState& channel_state_); ~DmaPusher(); diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index 0bb1809aa3..37ac3ec851 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -116,6 +116,7 @@ bool Puller::ResumeAcquire(DmaPusher& dma_pusher) { return false; } pending_acquire.reset(); + dma_pusher.suspensions.fetch_add(1, std::memory_order_release); Nx2SemaphoreWaiters::Get().Remove(this); return true; } @@ -257,6 +258,7 @@ void Puller::ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher) { dma_pusher.rasterizer->ReleaseFences(); if (!waiters.Latched(this) && !acquire.Matches(ReadSemaphoreWord(dma_pusher, acquire.address))) { pending_acquire = acquire; + dma_pusher.suspensions.fetch_add(1, std::memory_order_release); VideoCommon::Nx2Profile::Add(VideoCommon::Nx2Profile::Counter::AcquireWaits, 1); } else { waiters.Remove(this); |
