aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/macro_turing.h
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 00:27:35 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 00:27:35 -0400
commit863d3afa90f2dfde8e715b45f28fc75c1b472739 (patch)
tree95e9e5dfbafbd758da1d2d8f121478c424c0af7d /src/video_core/macro_turing.h
parente6bd4a0ddd93b8d1640fd9369f66581f882f2431 (diff)
nx2: replay repeated native macro calls instead of interpreting them
Title 1 makes ~1,000,000 native macro calls a second in 3D scenes, 7 instructions each on average, and 96% repeat an earlier call exactly. A call whose effects depend only on its start, its parameters and the data RAM words it read (no MME_READ, no memory reads, no re-read of its own data RAM writes, no code upload while it ran) is remembered with those reads as guards; a later call with the same start and parameters whose guards still hold replays its data RAM and method writes. Uploading macro code clears the memo. EDEN_NX2_MME_MEMO=0 interprets every call. Checked offline against the previous interpreter on 200,000 recorded 3D-scene calls (method writes, registers and data RAM all identical, 94% replayed, 1.9x faster); in the game the macro zone fell from ~0.26 to ~0.20 us per call.
Diffstat (limited to 'src/video_core/macro_turing.h')
-rw-r--r--src/video_core/macro_turing.h25
1 files changed, 22 insertions, 3 deletions
diff --git a/src/video_core/macro_turing.h b/src/video_core/macro_turing.h
index b7032eb4a4..600db48119 100644
--- a/src/video_core/macro_turing.h
+++ b/src/video_core/macro_turing.h
@@ -87,6 +87,10 @@ public:
std::string_view error;
const auto fail = [&](std::string_view message) { if (error.empty()) error = message; };
if (decoded.size() < code.size() / 3) decoded.resize(code.size() / 3);
+ read_registers = false;
+ reread_data_ram = false;
+ data_ram_reads.clear();
+ data_ram_writes.clear();
for (Word steps = 0; steps < 1000000; ++steps) {
if (static_cast<std::size_t>(pc) * 3 + 2 >= code.size()) {
fail("instruction outside uploaded RAM");
@@ -178,7 +182,7 @@ public:
}
case 17: case 18: case 19: case 20: case 21:
value = condition(d.op[lane]) ? ~0U : 0; break;
- case 22: value = read((x + y) & 0xffff); break;
+ case 22: value = read((x + y) & 0xffff); read_registers = true; break;
case 23:
if (loop_count || imm < 2) { fail("invalid loop"); break; }
// The native SDK emits zero-count loops around FIFO reads.
@@ -201,10 +205,17 @@ public:
break;
case 30:
if (x >= active_dram->size()) { fail("data RAM read out of bounds"); break; }
- value = (*active_dram)[x]; break;
+ value = (*active_dram)[x];
+ if (std::ranges::find(data_ram_writes, x, &DataRamAccess::first) != data_ram_writes.end()) {
+ reread_data_ram = true;
+ }
+ data_ram_reads.emplace_back(x, value);
+ break;
case 31:
if (x >= active_dram->size()) { fail("data RAM write out of bounds"); break; }
- (*active_dram)[x] = y; break;
+ (*active_dram)[x] = y;
+ data_ram_writes.emplace_back(x, y);
+ break;
}
alu[lane] = value;
if (d.dst[lane] < 24) { regs[d.dst[lane]] = value; initialized |= 1U << d.dst[lane]; }
@@ -250,6 +261,14 @@ public:
DataRam* active_dram{&dram};
// Decoded instructions by PC, re-decoded whenever their words differ.
std::vector<Decoded> decoded;
+ // What the last Execute read besides its parameters, for the macro memo: whether it read a
+ // register (MME_READ), the data RAM words it read and wrote (address, value) in order, and
+ // whether it read a word it had written itself.
+ using DataRamAccess = std::pair<Word, Word>;
+ bool read_registers{};
+ bool reread_data_ram{};
+ std::vector<DataRamAccess> data_ram_reads;
+ std::vector<DataRamAccess> data_ram_writes;
};
} // namespace Tegra