aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/dma_pusher.cpp
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 00:24:14 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 00:24:14 -0400
commita5e528e2d0bc784ebf24850e5913cece912c685e (patch)
tree8a0323e46528f768dc9fd0b0843419be2892de95 /src/video_core/dma_pusher.cpp
parentf8c8b809e64c57d34837b09cce3b6a7fd8e5295a (diff)
nx2: get title 4 past the difficulty confirm
- MME: implement MME_DMA_READ / MME_DMA_READ_FIFOED (Turing macros read query results into their load FIFO; the conditional-render macro at 0x142 needs it). - vi2 present waits up to 4 s for the frame fence (was 250 ms) so shader compile stalls don't let the game lap its equal-value gate semaphores. - Native QMD: fire the third release slot at word 52, which NVN2 patches for queue-to-queue syncs (compute queue releasing a gate the 3D queue waits on). - Compute class SET_REPORT_SEMAPHORE (0x6c0-0x6c3) releases. - Ampere lowering: AOFFI, any LOP3 truth table, STG RZ, LDG 0x981, IABS, I2FP rounding, IMAD negated addend, SHFL 0x989 (all 77 title-4 shaders lower). - Debug: EDEN_NX2_SEM_WATCH=<addr> traces acquires, releases, method arguments and compute macro emits for one semaphore block; EDEN_NX2_KEY_SCRIPT scripted key presses; per-submit logs moved to TRACE.
Diffstat (limited to 'src/video_core/dma_pusher.cpp')
-rw-r--r--src/video_core/dma_pusher.cpp28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 2c95b6de03..040bf18362 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -13,6 +13,7 @@
#include "core/core.h"
#include "core/memory.h"
#include "video_core/dma_pusher.h"
+#include "video_core/control/channel_state.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h"
#include "video_core/guest_memory.h"
@@ -134,6 +135,16 @@ bool DmaPusher::Step() {
if (++dma_pushbuffer_subindex >= command_list_size) {
// A split method resumes within the submission that split it; ring addresses repeat
// every frame, so a stale one could otherwise swallow the headers of a later entry.
+ for (const auto& parked : parked_methods) {
+ static std::atomic<u32> reported{};
+ if (reported.fetch_add(1) < 16) {
+ LOG_WARNING(HW_GPU,
+ "Submission ended with parked method {:#x} (sub {}, {} words left, "
+ "resume {:#x})",
+ parked.method, parked.subchannel, parked.method_count,
+ parked.resume_address);
+ }
+ }
parked_methods.clear();
dma_pushbuffer.pop();
dma_pushbuffer_subindex = 0;
@@ -264,7 +275,21 @@ void DmaPusher::SetState(const CommandHeader& command_header) {
dma_state.method_count = command_header.method_count;
}
+// EDEN_NX2_SEM_WATCH=<gpu address>: log every method whose argument is the low word of an
+// address in the 16 bytes there (finds the engine and method that release a semaphore).
+void DmaPusher::WatchArgument(u32 method, u32 argument) const {
+ static const u32 watch = [] {
+ const char* value = std::getenv("EDEN_NX2_SEM_WATCH");
+ return value ? static_cast<u32>(std::strtoull(value, nullptr, 16)) : 0U;
+ }();
+ if (watch != 0 && (argument & ~0xfU) == watch) {
+ LOG_INFO(HW_GPU, "Semaphore watch: channel {} subchannel {} method {:#x} argument {:#x}",
+ channel_state.bind_id, dma_state.subchannel, method, argument);
+ }
+}
+
void DmaPusher::CallMethod(u32 argument) {
+ WatchArgument(dma_state.method, argument);
if (dma_state.method < non_puller_methods) {
puller.CallPullerMethod(*this, Engines::Puller::MethodCall{
dma_state.method,
@@ -289,6 +314,9 @@ void DmaPusher::CallMethod(u32 argument) {
}
void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) {
+ for (u32 i = 0; i < num_methods; ++i) {
+ WatchArgument(dma_state.method + (dma_state.non_incrementing ? 0 : i), base_start[i]);
+ }
if (dma_state.method < non_puller_methods) {
puller.CallMultiMethod(*this, dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count);
} else {