RSX: restore two hunks lost resolving the ROP remap merge conflict

Both sat inside set_transform_program, the handler upstream rewrote for
ROP_OUTPUT_REMAP. Resolving that conflict took upstream's version as the base and
re-applied our profiler scopes, which put the scopes back and quietly dropped
these.

The first is the one that matters. e13fc184f made the redundant vertex program
check actually compare: the destination holds each word byte-swapped individually
by copy_data_swap_u32, while be_t<u64> swaps all eight bytes and so also exchanges
the two words. Without the rotl the check compares (w0,w1) against (w1,w0), which
can only match when w0 == w1 -- so it never fires, and every single upload marks
the ucode dirty. That forces a vertex program re-analysis, a program cache hint
drop and a full transform constant re-upload on every draw.

That is a per-draw cost on the RSX thread, restored to 0.9.4 by the merge after
being fixed, and it fits issue #78: Wipeout HD Fury reported as much higher CPU
and far worse performance on 0.9.4 than 0.9.3, with no other change in the window
that adds per-draw work.

The second is g_xform_program_words, which the profiler divides by
g_xform_program_calls to report average batch size. Losing the increment prints 0
rather than printing nothing -- exactly the failure mode I checked for on the
transform CONSTANT counter during the same merge, and missed on this one.

ISO.cpp, the other conflicted file, was checked the same way and lost nothing.
This commit is contained in:
jpolo1224
2026-08-21 00:23:37 -04:00
parent b9689d07fd
commit c6a0878a97
+18 -2
View File
@@ -205,8 +205,19 @@ namespace rsx
const usz first_index_off = 0;
const usz second_index_off = (((rcount / 4) - 1) / 2) * 4;
const u64 src_op1_2 = read_from_ptr<be_t<u64>>(fifo_span, first_index_off);
const u64 src_op2_2 = read_from_ptr<be_t<u64>>(fifo_span, second_index_off);
// Rotated by 32: the destination holds each word already byte-swapped
// individually (copy_data_swap_u32), but be_t<u64> swaps all eight bytes,
// which additionally EXCHANGES the two words. Without the rotate this
// compares (w0,w1) against (w1,w0) and can only match when w0 == w1, so the
// redundant-upload check never fired: every upload set the ucode dirty,
// forcing a vertex program re-analysis, a program cache hint drop and a full
// transform constant re-upload on every draw.
//
// Lost once already, in the ROP output remap merge: this hunk sits inside the
// same handler upstream rewrote, and re-applying the profiler scopes around it
// did not put it back. Restored in b9689d07f's follow-up.
const u64 src_op1_2 = std::rotl<u64>(read_from_ptr<be_t<u64>>(fifo_span, first_index_off), 32);
const u64 src_op2_2 = std::rotl<u64>(read_from_ptr<be_t<u64>>(fifo_span, second_index_off), 32);
// Fast comparison
if (src_op1_2 != read_from_ptr_unsafe<u64>(out_ptr, first_index_off) || src_op2_2 != read_from_ptr_unsafe<u64>(out_ptr, second_index_off))
@@ -224,6 +235,11 @@ namespace rsx
to_set_dirty = rsx::pipeline_state::vertex_program_ucode_dirty;
}
// Pairs with g_xform_program_calls: the profiler reports words/calls, so without
// this the average batch size prints 0 rather than printing nothing. Also lost in
// the ROP remap merge, alongside the rotl above.
if (rsx::prof::enabled()) [[unlikely]] rsx::prof::g_xform_program_words += rcount;
RSX(ctx)->m_graphics_state |= to_set_dirty;
REGS(ctx)->transform_program_load_set(load_pos + ((rcount + index % 4) / 4));
RSX(ctx)->fifo_ctrl->skip_methods(rcount - 1);