aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkraibse <33869366+kraibse@users.noreply.github.com>2026-11-02 01:06:48 +0100
committerkraibse <33869366+kraibse@users.noreply.github.com>2026-11-02 01:06:48 +0100
commit6612817cb4b6da97c4fc88e232a8efa07a3704db (patch)
treeb77297449d71ef9b8c006d3d909f4c6afc951768 /src
parent51d798ff0373a40098aa77ef13d54307f39e44ac (diff)
dma_pusher: restores the trees as the lorax wouldn't be happy without them (add IsGpuWrittenCommands method to check GPU-written entries)
Diffstat (limited to 'src')
-rw-r--r--src/video_core/dma_pusher.cpp25
-rw-r--r--src/video_core/dma_pusher.h2
2 files changed, 17 insertions, 10 deletions
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index cbbc7f26eb..1144488c91 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -157,9 +157,12 @@ bool DmaPusher::Step() {
(Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe());
// 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).
+ // unflushed anyway). Entries on pages the GPU writes (culling) always take the flushing
+ // 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() &&
+ !IsGpuWrittenCommands(dma_state.dma_get,
+ size_t{header.size} * sizeof(u32)) &&
!(use_safe && memory_manager.IsMemoryDirty(dma_state.dma_get,
header.size * sizeof(u32)));
if (submitted) {
@@ -460,22 +463,24 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) {
}
}
-void DmaPusher::FlushGpuWrittenCommands(GPUVAddr address, size_t size) {
- // Title 1 runs small command lists its culling dispatches fill in each frame. Accurate GPU
- // mode reads every command list through the caches (safe reads); here only the ones on pages
- // the GPU has written are, or their draws run with an older frame's words (trees vanish).
+bool DmaPusher::IsGpuWrittenCommands(GPUVAddr address, size_t size) {
if (!Tegra::g_nx2_ampere.load(std::memory_order_relaxed) || size == 0) {
- return;
+ return false;
}
- bool written = false;
for (GPUVAddr page = address & ~GPUVAddr{0xfff}; page < address + size; page += 0x1000) {
if (const auto device = memory_manager.GpuToCpuAddress(page);
device && Tegra::Nx2IsGpuWritten(*device)) {
- written = true;
- break;
+ return true;
}
}
- if (!written) {
+ return false;
+}
+
+void DmaPusher::FlushGpuWrittenCommands(GPUVAddr address, size_t size) {
+ // Title 1 runs small command lists its culling dispatches fill in each frame. Accurate GPU
+ // mode reads every command list through the caches (safe reads); here only the ones on pages
+ // the GPU has written are, or their draws run with an older frame's words (trees vanish).
+ if (!IsGpuWrittenCommands(address, size)) {
return;
}
// The caches belong to the split's back: it first runs what the front queued (the dispatch
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h
index d52aef821a..e9dd5e2b6b 100644
--- a/src/video_core/dma_pusher.h
+++ b/src/video_core/dma_pusher.h
@@ -186,6 +186,8 @@ public:
void DumpCurrentEntry(const char* reason);
void CheckSubmitHash(const CommandListHeader& header, u64 submit_hash);
void RecordParsedEntry(const CommandListHeader& header, std::span<const CommandHeader> commands);
+ /// Whether the entry lies on device pages the GPU has written (NX2).
+ bool IsGpuWrittenCommands(GPUVAddr address, size_t size);
/// Brings command list words the GPU wrote (still only in host buffers) to guest memory.
void FlushGpuWrittenCommands(GPUVAddr address, size_t size);