diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 07:49:09 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 20:49:47 -0400 |
| commit | 15eef40dd12c2b751d5b1cac57dd8f3602e2d133 (patch) | |
| tree | 44b191586781c8c11e0e0279983ef9b45abe6c34 /src/video_core/engines | |
| parent | 4d7558e25bb0a59d90153bc8dfdca4b4e1fc2f48 (diff) | |
maxwell_3d: drop state register writes that keep the register's value
Title 1 makes ~6 million 3D register writes a second and ~60% of them write the value
the register already holds (counted with EDEN_NX2_GPU_PROFILE), most from macro memo
replays. For registers without side effects (not in execution_mask: draws, clears,
constant buffer data and binds, semaphores, ...) such a write changes nothing, but it
set dirty flags that made the next draw re-check that state. CallMethod and the sunk
writes now skip them after shadow RAM processing. Two profiled runs each: macro calls
169 ns instead of 185, draw setup 5.80 us instead of 5.95. EDEN_NX2_SKIP_SAME=0 turns it
off.
Diffstat (limited to 'src/video_core/engines')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 29 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 10 |
2 files changed, 36 insertions, 3 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 20a973bb6b..f958b025bc 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -20,6 +20,7 @@ #include "video_core/engines/maxwell_3d.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" +#include "video_core/nx2_profile.h" #include "video_core/rasterizer_interface.h" #include "video_core/textures/texture.h" @@ -307,17 +308,25 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) { void Maxwell3D::ConsumeSinkImpl(Core::System& system) { const auto control = shadow_state.shadow_ram_control; + // Sunk methods are state writes only (not in execution_mask): skip unchanged values, as + // CallMethod does. + const bool skip_same = SkipSameValueWrites(); + const auto process = [&](u32 method, u32 value) { + if (!skip_same || regs.reg_array[method] != value) { + ProcessDirtyRegisters(method, value); + } + }; if (control == Regs::ShadowRamControl::Track || control == Regs::ShadowRamControl::TrackWithFilter) { for (auto [method, value] : method_sink) { shadow_state.reg_array[method] = value; - ProcessDirtyRegisters(method, value); + process(method, value); } } else if (control == Regs::ShadowRamControl::Replay) { for (auto [method, value] : method_sink) - ProcessDirtyRegisters(method, shadow_state.reg_array[method]); + process(method, shadow_state.reg_array[method]); } else { for (auto [method, value] : method_sink) - ProcessDirtyRegisters(method, value); + process(method, value); } method_sink.clear(); } @@ -445,7 +454,21 @@ void Maxwell3D::CallMethod(Core::System& system, u32 method, u32 method_argument } ASSERT(method < Regs::NUM_REGS && "Invalid Maxwell3D register, increase the size of the Regs structure"); + if (VideoCommon::Nx2Profile::Enabled()) [[unlikely]] { + VideoCommon::Nx2Profile::Add(VideoCommon::Nx2Profile::Counter::MethodWrites, 1); + if (regs.reg_array[method] == method_argument) { + VideoCommon::Nx2Profile::Add(VideoCommon::Nx2Profile::Counter::SameValueWrites, 1); + } + } const u32 argument = ProcessShadowRam(method, method_argument); + // A state register written with the value it holds changes nothing: no dirty flags (they + // would make the next draw re-check that state), no method processing. Title 1 makes ~6 + // million 3D register writes a second, ~60% of them same-value, most from macro replays. + // Methods with side effects (execution_mask: draws, clears, constant buffer data and + // binds, semaphores, ...) always run. EDEN_NX2_SKIP_SAME=0 turns it off. + if (SkipSameValueWrites() && !execution_mask[method] && regs.reg_array[method] == argument) { + return; + } ProcessDirtyRegisters(method, argument); ProcessMethodCall(method, argument, method_argument, is_last_call); } diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 190d5de630..8a806cc070 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -9,6 +9,7 @@ #include <array> #include <bitset> #include <cmath> +#include <cstdlib> #include <limits> #include <optional> #include <span> @@ -3250,6 +3251,15 @@ private: */ void CallMacroMethod(Core::System& system, u32 method, std::span<const u32> parameters); + /// Whether state register writes that keep the register's value are dropped (CallMethod). + static bool SkipSameValueWrites() { + static const bool skip = [] { + const char* value = std::getenv("EDEN_NX2_SKIP_SAME"); + return value == nullptr || value[0] != '0'; + }(); + return skip; + } + /// Handles writes to the macro uploading register. void ProcessMacroUpload(u32 data); |
