aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/macro.cpp
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 09:39:25 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 20:49:48 -0400
commitc0643a675b1382cfa7357626a63a623b56a72666 (patch)
treefb19a274b962c118c5397800c1d1e0aabb91a0b9 /src/video_core/macro.cpp
parente2847fa5dd87d64f86d0c2a580f47fe9e8f4fceb (diff)
video_core: compile Turing MME macro code to x86-64
Title 1 calls macros ~1.3 million times a second; most were replayed from the macro memo, whose lookups missed the CPU caches inside the GPU thread (~8%), and the rest interpreted. macro_turing_jit.h compiles all of the uploaded macro memory with Xbyak: each instruction a block falling through to the next, branches and loops through a jump table, with the interpreter's semantics (lanes reading operands before either writes, predication as two variants, the END delay slot, loops, carry). Loop checks only where a loop can end, END checks only after an END, the instruction limit counted on indirect jumps. Emits and register reads call back into C++. It is recompiled when the macro code changes and used for 3D and compute macros on x86-64; EDEN_NX2_MME_JIT=0 goes back to the memo and the interpreter. Checked against the interpreter on 200,000 recorded calls (registers, data RAM, every method write, FIFO use): identical. In the game: macro calls 148 ns instead of 174 (two profiled runs each), no failures, 0 crashes in 3 runs. NX2_GPU_THREAD_SPLIT.md describes the next step, splitting the GPU thread.
Diffstat (limited to 'src/video_core/macro.cpp')
-rw-r--r--src/video_core/macro.cpp28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp
index 50e32ce999..74e25da067 100644
--- a/src/video_core/macro.cpp
+++ b/src/video_core/macro.cpp
@@ -17,6 +17,7 @@
#ifdef ARCHITECTURE_x86_64
#include "common/x64/xbyak.h"
+#include "video_core/macro_turing_jit.h"
#endif
#include "common/assert.h"
@@ -1459,6 +1460,33 @@ void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u
}
return true;
};
+#ifdef ARCHITECTURE_x86_64
+ // Macro code runs compiled to x86-64 (macro_turing_jit.h) instead of through the memo
+ // and the interpreter; EDEN_NX2_MME_JIT=0 goes back to those.
+ static const bool use_jit = [] {
+ const char* value = std::getenv("EDEN_NX2_MME_JIT");
+ return value == nullptr || value[0] != '0';
+ }();
+ if (use_jit) {
+ if (!native_jit) {
+ native_jit = std::make_shared<TuringMacroJit>();
+ }
+ native_jit->Prepare(native_code, native_code_generation);
+ fifo.assign(parameters.begin(), parameters.end());
+ const auto result = native_jit->Execute(
+ method, fifo, std::span<u32>{*native_interpreter.active_dram},
+ [&](u32 address) {
+ return address < Maxwell3D::Regs::NUM_REGS ? maxwell3d.GetRegisterValue(address) : 0U;
+ },
+ emit);
+ if (!result.success) {
+ native_execution_failed = true;
+ LOG_ERROR(HW_GPU, "Native MME (JIT) failed: start={:#x}, consumed={}/{}, error={}",
+ method, result.consumed, parameters.size(), result.error);
+ }
+ return;
+ }
+#endif
// EDEN_NX2_MME_MEMO=0: interpret every call (see macro_memo.h).
static const bool use_memo = [] {
const char* value = std::getenv("EDEN_NX2_MME_MEMO");