aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/engines
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 07:49:09 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 20:49:47 -0400
commit15eef40dd12c2b751d5b1cac57dd8f3602e2d133 (patch)
tree44b191586781c8c11e0e0279983ef9b45abe6c34 /src/video_core/engines
parent4d7558e25bb0a59d90153bc8dfdca4b4e1fc2f48 (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.cpp29
-rw-r--r--src/video_core/engines/maxwell_3d.h10
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);