aboutsummaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 14:29:58 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-11-01 11:09:52 -0500
commit01389ee5266fe5e775ef205ca90122d68d4c46c5 (patch)
tree01fc51be5f8a0b84daeab6caf0c40ae3e5a823f5 /src/shader_recompiler
parente39825807109ca5ac6c2213b03a6bcdab8fc3922 (diff)
nx2: mirror uniform registers above UR27 below R216
Uniform registers have GPR mirrors only for UR0-UR27 (R216-R237, R240-R245). Kirby Air Riders' graphics shaders load a 64-bit base into UR28:UR29 (ULDC.64 UR28, c[0x0][0x510]) and address global loads with it (4 programs). When a program uses UR28 or above, lower it again with those registers mirrored just below R216 (UR28 at R(216 - n), n even so pairs stay adjacent) and that range kept from the program's own registers; other programs keep the same layout.
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/frontend/ampere/lower_to_maxwell.h25
1 files changed, 21 insertions, 4 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h
index 0d977ded9d..198769709d 100644
--- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h
+++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h
@@ -34,6 +34,9 @@ struct LoweredProgram {
std::vector<u32> source_instruction_offsets;
u32 source_size{};
u32 required_texture_buffer = ~0U;
+ // UR28 and up seen without a mirror: lowering again with this many registers below R216
+ // reserved for them (even, so pairs stay adjacent) maps them.
+ u32 high_uniform_registers{};
u32 error_offset{};
std::string_view error;
@@ -43,8 +46,10 @@ struct LoweredProgram {
// Lower only operations whose semantics are representable by the existing
// Maxwell frontend. These are new instructions, not reinterpretations of the
// native bytes. Scheduling/control words are added by the environment adapter.
-inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) {
+inline LoweredProgram LowerToMaxwellWith(std::span<const Instruction> code, u32 high_uniforms) {
LoweredProgram result;
+ // UR28 and up (when used) live just below R216: UR28 at R(216 - high_uniforms).
+ const u32 high_uniform_base = 216 - high_uniforms;
struct Relocation { u32 output_index; s64 target; };
std::vector<Relocation> relocations;
std::vector<u32> barrier_tokens;
@@ -101,15 +106,17 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) {
for (u32 bit : {16U, 24U, 32U, 64U}) {
if (bit == 32 && insn.Bits(9, 3) != 1 && opcode != 0xb60 && opcode != 0xb66) continue;
const u32 reg = insn.Bits(bit, 8);
- if (reg >= (uses_uniform_bank ? 216U : 246U) && reg < 255) return fail(index, "native program uses lowering scratch registers");
+ if (reg >= (uses_uniform_bank ? high_uniform_base : 246U) && reg < 255) return fail(index, "native program uses lowering scratch registers");
}
// UR0-UR21 live in R216-R237 and UR22-UR27 in R240-R245 (R239 holds the uniform
- // predicates), so even/odd pairs stay adjacent. Sites that still check reg < 16 rely on
- // UR0-UR15 being R216-R231.
+ // predicates), so even/odd pairs stay adjacent; UR28 and up below R216. Sites that
+ // still check reg < 16 rely on UR0-UR15 being R216-R231.
const auto uniform_register = [&](u32 reg) -> u32 {
if (reg < 22) return 216 + reg;
if (reg < 28) return 218 + reg;
if (reg == 63) return 255;
+ if (reg < 63 && reg - 28 < high_uniforms) return high_uniform_base + (reg - 28);
+ if (reg < 63) result.high_uniform_registers = (std::max)(result.high_uniform_registers, (reg - 26) & ~1U);
return ~0U;
};
bool rewritten_uniform = false;
@@ -2513,4 +2520,14 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) {
return fail(static_cast<u32>(code.size()), main_exited ? "native program lacks captured library return" : "native program has no unconditional EXIT");
}
+inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) {
+ // Programs using uniform registers above UR27 are lowered again with mirrors for them.
+ u32 high_uniforms = 0;
+ for (;;) {
+ LoweredProgram lowered = LowerToMaxwellWith(code, high_uniforms);
+ if (lowered || lowered.high_uniform_registers <= high_uniforms) return lowered;
+ high_uniforms = lowered.high_uniform_registers;
+ }
+}
+
} // namespace Shader::Ampere