diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 04:25:31 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 11:29:28 -0500 |
| commit | eb02d1dd53a03d0bb6ce541694243579a4c10c6f (patch) | |
| tree | d21ece3200bfeb70cde2152e06b85d38def6b500 /src/shader_recompiler | |
| parent | 6a95f4fb29d6ab75f7e04bbcb9af6514021f2855 (diff) | |
nx2: keep ISBERD/ISBEWR and lower UPOPC for task and mesh programs
Mario Kart World draws some geometry with task and mesh programs that read
and write the stage buffer (ISBE) with ISBERD and ISBEWR. Pass them through
as an nx2 pseudo instruction in a free Maxwell opcode (0xefc0), with the
register, offset, size, region, skew, output and write fields, for the
frontend to translate per stage. Also lower UPOPC like the other uniform
bit operations. Every dumped program of the title now lowers.
Diffstat (limited to 'src/shader_recompiler')
| -rw-r--r-- | src/shader_recompiler/frontend/ampere/lower_to_maxwell.h | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h index 2deca4e7a0..66593b68e4 100644 --- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h +++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h @@ -872,6 +872,11 @@ inline LoweredProgram LowerToMaxwellWith(std::span<const Instruction> code, u32 emit(0x3828000000000000ULL | predicate | (dest + 216) | (u64{insn.words[1] + 216} << 8) | (u64{1} << 39) | (u64{1} << 40)); break; + case 0x2bf: // UPOPC, as POPC of the uniform's register. + if (dest >= 16 || insn.words[1] >= 16 || insn.words[2] != 0x08000000 || native_predicate != 7) + return fail(index, "native uniform population count mode"); + emit(0x5c08000000000000ULL | predicate | (dest + 216) | (u64{insn.words[1] + 216} << 20)); + break; case 0x3a1: { // MATCH.ALL (.U32, or .U64 on bit 73) with only the all-equal predicate retained. const u32 source = insn.Bits(24, 8), target = insn.Bits(81, 3); const u32 words = insn.Bits(73, 1) ? 2 : 1; @@ -2531,6 +2536,24 @@ inline LoweredProgram LowerToMaxwellWith(std::span<const Instruction> code, u32 return finish(index); // the closing self-branch break; } + case 0x923: case 0x927: { // ISBERD / ISBEWR: task and mesh programs' stage buffer. + // Ampere: Ra 24-31, offset 40-63, ISBERD dest 16-23, ISBEWR data 32-39; 75 = .32 (else + // U8), 76-77 = 3 .ATTR (0 the map region), 78 = .SKEW, 79 = .O (the output buffer). + // Kept as an nx2 pseudo instruction (Maxwell 0xefc0, free there) that the frontend + // reads for the task or mesh stage: data/dest 0-7, Ra 8-15, offset 20-43, .32 44, + // .ATTR 45, .SKEW 46, .O 47, write 48. Addresses are linear bytes in the region. + const bool write = opcode == 0x927; + const u32 region = insn.Bits(76, 2); + const bool output = insn.Bits(79, 1) != 0; + if ((insn.words[2] & ~0xf800U) != 0 || (region != 0 && region != 3) || write != output || + (!write && region != 3) || (!write && dest == 255)) + return fail(index, "native stage buffer access mode"); + emit(0xefc0000000000000ULL | predicate | (write ? u64{insn.Bits(32, 8)} : dest) | + (u64{insn.Bits(24, 8)} << 8) | (u64{insn.Bits(40, 24)} << 20) | + (u64{insn.Bits(75, 1)} << 44) | (u64{region == 3} << 45) | + (u64{insn.Bits(78, 1)} << 46) | (u64{output} << 47) | (u64{write} << 48)); + break; + } case 0x94d: { // EXIT if (insn.Bits(84, 2)) { return fail(index, "native conditional/special EXIT"); |
