aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/engines
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 13:22:59 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 13:22:59 -0400
commitd0c0cb8906ba99bbe013aaa220887b7b8ab31a7a (patch)
tree6e6998122a908ae5739dbcb239e26570a8f82beb /src/video_core/engines
parentd6bbbf9f23a7e5b6a6ab11e2696085e0482b6fc4 (diff)
Switch 2: per-channel MME data RAM; one QMD table for all channels
Macro code stays shared by the channels of a process, but each channel now has its own MME data RAM. Title 1's channels keep their own QMD ring base in data word 0x27; with one shared RAM every channel used the last channel's ring, QMDs collided, releases came early or never and the GPU waited on semaphores (4 s timeouts per frame). The QMD scheduler state is one table for all channels: a QMD's dependency counter is state of the QMD, scheduled and decremented from different channels. Diagnostics: EDEN_NX2_QMD_TRACE (scheduler loads, counts, launches) and EDEN_NX2_MME_DUMP (compute macro code, calls, data word 0x27 changes).
Diffstat (limited to 'src/video_core/engines')
-rw-r--r--src/video_core/engines/kepler_compute.cpp30
-rw-r--r--src/video_core/engines/kepler_compute.h5
-rw-r--r--src/video_core/engines/maxwell_3d.h3
3 files changed, 38 insertions, 0 deletions
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 4954fe613a..8a3855468f 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -29,6 +29,13 @@ KeplerCompute::KeplerCompute(MemoryManager& memory_manager_)
: memory_manager{memory_manager_}
, upload_state{memory_manager, regs.upload}
{
+ // EDEN_NX2_QMD_TRACE: log the QMD scheduler's loads, dependency counts and launches.
+ if (std::getenv("EDEN_NX2_QMD_TRACE")) {
+ native_qmd.trace = [this](std::string_view event, u64 address, s32 value) {
+ LOG_INFO(HW_GPU, "QMD trace {} {:#x} {} (engine {} as {})", event, address, value,
+ fmt::ptr(this), memory_manager.GetID());
+ };
+ }
execution_mask.reset();
execution_mask[KEPLER_COMPUTE_REG_INDEX(exec_upload)] = true;
execution_mask[KEPLER_COMPUTE_REG_INDEX(data_upload)] = true;
@@ -109,6 +116,7 @@ bool KeplerCompute::ProcessNativeMethod(Core::System& system, u32 method, u32 ar
native_parameters.push_back(argument);
if (!is_last_call) return true;
const u32 entry = ((*native_executing_macro - 0xe00) / 2) % native_macro_positions.size();
+ native_executing_macro_logged = native_executing_macro;
native_executing_macro.reset();
static const u32 watch = [] {
const char* value = std::getenv("EDEN_NX2_SEM_WATCH");
@@ -120,6 +128,22 @@ bool KeplerCompute::ProcessNativeMethod(Core::System& system, u32 method, u32 ar
LOG_INFO(HW_GPU, "Semaphore watch: compute macro start={:#x} parameters={:08x}",
native_macro_positions[entry], fmt::join(native_parameters, ","));
}
+ // EDEN_NX2_MME_DUMP: write the compute macro code once per engine, and log each macro
+ // call with its entry and parameters (diagnostics).
+ if (static const bool mme_dump = std::getenv("EDEN_NX2_MME_DUMP") != nullptr; mme_dump) {
+ if (!native_mme_dumped && native_macro_positions[entry] == 0xda) {
+ native_mme_dumped = true;
+ std::ofstream dump(fmt::format("native-compute-mme-{}.bin", fmt::ptr(this)),
+ std::ios::binary);
+ dump.write(reinterpret_cast<const char*>(native_macro->native_code.data()),
+ sizeof(native_macro->native_code));
+ }
+ LOG_INFO(HW_GPU, "MME call engine {} method {:#x} start={:#x} parameters={:08x}",
+ fmt::ptr(this), *native_executing_macro_logged, native_macro_positions[entry],
+ fmt::join(native_parameters, ","));
+ }
+ if (native_data_ram) native_macro->native_interpreter.active_dram = native_data_ram;
+ const u32 dram0_before = (*native_macro->native_interpreter.active_dram)[0x27];
const auto result = native_macro->native_interpreter.Execute(native_macro->native_code,
native_macro_positions[entry], native_parameters,
[&](u32 address) { return address < native_registers.size() ? native_registers[address] : 0U; },
@@ -132,6 +156,12 @@ bool KeplerCompute::ProcessNativeMethod(Core::System& system, u32 method, u32 ar
CallMethod(system, address, value, true);
return true;
});
+ if (static const bool mme_dump = std::getenv("EDEN_NX2_MME_DUMP") != nullptr;
+ mme_dump && (*native_macro->native_interpreter.active_dram)[0x27] != dram0_before) {
+ LOG_INFO(HW_GPU, "MME data RAM[0x27] {:#x} -> {:#x} by engine {} macro start={:#x}",
+ dram0_before, (*native_macro->native_interpreter.active_dram)[0x27], fmt::ptr(this),
+ native_macro_positions[entry]);
+ }
if (!result.success) {
native_macro->native_execution_failed = true;
if (static const bool diagnostics = std::getenv("EDEN_NATIVE_DRAW_DIAGNOSTICS") != nullptr;
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index dd69211f7b..7cecab378b 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -57,6 +57,8 @@ public:
/// Binds a rasterizer to this engine.
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
+ /// The channel's MME data RAM, shared with its 3D engine.
+ void SetNativeDataRam(std::array<u32, 0xc00>* data_ram) { native_data_ram = data_ram; }
void SetNativeMacroMode(MacroEngine* shared_macro, std::span<u32> positions, NativeMacroContext* context = nullptr) {
if (native_context != context) native_compute_uploaded = false;
native_context = context;
@@ -242,6 +244,9 @@ private:
bool UpscaleInsteadOfNativeProgram();
bool ProcessNativeMethod(Core::System& system, u32 method, u32 argument, bool is_last_call);
NativeQmdScheduler native_qmd;
+ std::array<u32, 0xc00>* native_data_ram{};
+ bool native_mme_dumped{};
+ std::optional<u32> native_executing_macro_logged;
bool native_mode{};
NativeMacroContext* native_context{};
bool native_compute_uploaded{};
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 2a10795a4e..82e716b822 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -3150,6 +3150,8 @@ public:
native_macro_context = std::move(context);
}
MacroEngine& GetNativeMacroEngine() { return native_macro_context ? native_macro_context->engine : macro_engine; }
+ /// This channel's MME data RAM (shared with its compute engine).
+ std::array<u32, 0xc00>& GetNativeDataRam() { return native_data_ram; }
std::span<u32> GetNativeMacroPositions() { return native_macro_context ? std::span<u32>{native_macro_context->positions} : std::span<u32>{macro_positions}; }
@@ -3302,6 +3304,7 @@ private:
/// Interpreter for the macro codes uploaded to the GPU.
std::shared_ptr<NativeMacroContext> native_macro_context;
+ std::array<u32, 0xc00> native_data_ram{};
MacroEngine macro_engine;
Upload::State upload_state;