aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/dma_pusher.cpp
diff options
context:
space:
mode:
authorkraibse <33869366+kraibse@users.noreply.github.com>2026-11-01 03:20:42 +0100
committerkraibse <33869366+kraibse@users.noreply.github.com>2026-11-02 00:11:25 +0100
commitcce6d44af23f08a7287a66d745fec34e38c9eb25 (patch)
tree6d26989c997978d71a2ea771be4dba28155b0845 /src/video_core/dma_pusher.cpp
parent803ece5f90bbdc5ef9751f559cbe8b2ecbdb2aac (diff)
nx2: execute command lists as submitted
With the present waiting for the previous frame's fence, the game refills command memory it already submitted while the GPU thread is still running that frame, so some frames rendered into the wrong image. Copy each entry's words at submit and execute the copy. Resumed entries and ranges the GPU has newer words for still read memory. EDEN_NX2_PB_SNAPSHOT=0 executes from memory. Ported from Wael3rd/Eglantine-MKW (bd3119a86f). Assisted-by: Claude Sonnet 5.5 (porting the fix) (cherry picked from commit 408bb84d06ae0729697ef9bed2c2ba76ce6dff42)
Diffstat (limited to 'src/video_core/dma_pusher.cpp')
-rw-r--r--src/video_core/dma_pusher.cpp16
1 files changed, 15 insertions, 1 deletions
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 8c142b36db..cbbc7f26eb 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -155,7 +155,21 @@ bool DmaPusher::Step() {
// (the split only starts with unsafe reads; the settings can change mid-game).
const bool use_safe = !VideoCommon::GpuSplit::Get().Active() &&
(Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe());
- if (use_safe) {
+ // The words as submitted, unless this is a resumed entry or the GPU has newer ones the
+ // safe read below would flush (with the split, the front can't tell: it reads memory
+ // unflushed anyway).
+ const bool submitted = command_resume_offset == 0 &&
+ dma_pushbuffer_subindex < command_list.submitted_offsets.size() &&
+ !(use_safe && memory_manager.IsMemoryDirty(dma_state.dma_get,
+ header.size * sizeof(u32)));
+ if (submitted) {
+ const std::span<const CommandHeader> commands{
+ command_list.submitted_words.data() +
+ command_list.submitted_offsets[dma_pushbuffer_subindex],
+ header.size};
+ RecordParsedEntry(header, commands);
+ command_resume_offset += ProcessCommands(commands, 0);
+ } else if (use_safe) {
Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader, Tegra::Memory::GuestMemoryFlags::SafeRead>headers(memory_manager, dma_state.dma_get, header.size, &command_headers);
const std::span<const CommandHeader> commands{headers.data(), headers.size()};
RecordParsedEntry(header, commands);