diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 20:03:06 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 20:49:49 -0400 |
| commit | a08fc6a6a990fa4c5b51b6309e99ba4dcddafe97 (patch) | |
| tree | 0e4c74a56ce38d84dd8593bb17faa9a9150084ee /src | |
| parent | 42e9e37e081fc13348d9af70be74154fb1b58c57 (diff) | |
nx2: lower 2D TXD and split destination pairs
Splatoon Raiders binds two fragment shaders whose TXD is 2D (Ampere
dimension 1) with its second destination pair away from the first
(R12/R18, R18/R44); both were rejected, so every draw using them was
skipped. Emit Maxwell's 2D type for dimension 1 and, when the pairs are
not consecutive, write the four channels to scratch R248-R251 and move
each pair into place.
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/frontend/ampere/lower_to_maxwell.h | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h index 9e5dd0313f..2663f3a830 100644 --- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h +++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h @@ -758,20 +758,35 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) { (u64{insn.Bits(64, 8)} << 20) | (u64{maxwell} << 28)); break; } - case 0xb6c: { // TXD ARRAY_2D, four channels and consecutive split destinations. + case 0xb6c: { // TXD 2D or ARRAY_2D, four channels; the two destination pairs anywhere. const u32 binding = insn.Bits(54, 5), offset = insn.Bits(40, 14); const u32 coordinates = insn.Bits(24, 8), derivatives = insn.Bits(32, 8); + // Ampere dimensions: 1 = 2D, 5 = ARRAY_2D; Maxwell TXD's are 2 and 3. The coordinates + // (x, y[, layer]) and the four gradients sit in the same registers for both. + const u32 dimension = insn.Bits(61, 3); + const u32 high = insn.Bits(64, 8); // destination of the third and fourth channels if ((insn.words[2] & ~0xffU) != 0x001e0f00 || insn.Bits(59, 2) || - insn.Bits(61, 3) != 5 || binding >= 18 || offset > 0x1fff || - (dest & 1) || dest >= 248 || insn.Bits(64, 8) != dest + 2 || + (dimension != 1 && dimension != 5) || binding >= 18 || offset > 0x1fff || + (dest & 1) || dest >= 248 || (high & 1) || (high >= 248 && high != 255) || coordinates >= 248 || derivatives >= 247) - return fail(index, "native array gradient texture mode"); + return fail(index, "native gradient texture mode"); if (result.required_texture_buffer != ~0U && result.required_texture_buffer != binding) return fail(index, "native texture descriptor buffer conflict"); result.required_texture_buffer = binding; - emit(base(0xde00000000000000ULL) | (u64{coordinates} << 8) | - (u64{derivatives} << 20) | (u64{3} << 28) | (u64{15} << 31) | + // Maxwell writes four consecutive registers: when the second pair is elsewhere (Splatoon + // Raiders: R12/R18, R18/R44), write them to scratch and move each pair into place. + const bool consecutive = high == dest + 2; + const u64 target = consecutive ? dest : 248; + emit(0xde00000000000000ULL | predicate | target | (u64{coordinates} << 8) | + (u64{derivatives} << 20) | (u64{dimension == 5 ? 3U : 2U} << 28) | (u64{15} << 31) | (u64{offset} << 36) | (u64{insn.Bits(90, 1)} << 49) | (u64{7} << 51)); + if (!consecutive) { + for (u32 i = 0; i < 2; ++i) { + emit(0x5c98000000000000ULL | predicate | (dest + i) | (u64{15} << 39) | (u64{248 + i} << 20)); + if (high != 255) + emit(0x5c98000000000000ULL | predicate | (high + i) | (u64{15} << 39) | (u64{250 + i} << 20)); + } + } break; } case 0x989: { // SHFL, immediate lane and register clamp/segmentation mask, any mode. |
