aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 20:03:06 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 20:49:49 -0400
commita08fc6a6a990fa4c5b51b6309e99ba4dcddafe97 (patch)
tree0e4c74a56ce38d84dd8593bb17faa9a9150084ee /src
parent42e9e37e081fc13348d9af70be74154fb1b58c57 (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.h27
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.