diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 14:23:02 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 11:09:41 -0500 |
| commit | 6e289d893535b76727876efafd64c23eda486cea (patch) | |
| tree | fc8fc61ebbe0e770be96e5afccf5039bf59369fd /src | |
| parent | b14a268ebce6e11e822875bd8115f20ed907fe87 (diff) | |
nx2: lower TMML for 1D, 3D and cube textures and with a uniform handle
Kirby Air Riders queries the LOD of a cube texture whose handle is in a
uniform register (TMML.LOD RZ, R43, R32, UR4, CUBE, 0x2, in 16
programs). Take the 1D/2D/3D/cube coordinate counts (all from Ra when Rb
is RZ, otherwise split as for TEX), and emit Maxwell TMML.B with the
handle first in Rb for the uniform form (bit 91).
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/frontend/ampere/lower_to_maxwell.h | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h index 882144f21c..641e98c1e4 100644 --- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h +++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h @@ -56,7 +56,7 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) { for (const auto& instruction : code) { const u32 op = instruction.Bits(0, 12); uses_uniform_bank |= op == 0x3c4 || op == 0x2bd || op == 0x896 || op == 0xf60 || op == 0xc11 || op == 0xd08 || op == 0xc0c || op == 0x986 || op == 0x9a8 || op == 0xc12 || op == 0xc17 || op == 0xe24 || op == 0xc24 || op == 0xd00 || op == 0xd09 || op == 0x9c3 || op == 0xc45 || op == 0x2a4 || op == 0x891 || op == 0x890 || op == 0x290 || op == 0x28c || op == 0x88c || op == 0x287 || op == 0x887 || op == 0x958 || op == 0xab9 || op == 0xabb || op == 0x899 || op == 0xc20 || op == 0xe21 || op == 0xe23 || op == 0xc02 || - op == 0x886 || op == 0x3c2 || op == 0xc82 || op == 0x882 || op == 0x292 || op == 0x892 || op == 0x291 || op == 0x981 || op == 0xc13 || op == 0xc10 || op == 0xc23 || op == 0x526 || op == 0x2be || op == 0x8a4 || op == 0xd05 || (op == 0x984 && instruction.Bits(91, 1)) || op == 0x89c || op == 0x883 || op == 0x2a5 || op == 0xd06 || op == 0xc0b || op == 0x8a5 || op == 0x299 || op == 0xc09 || (op == 0x81c && instruction.Bits(67, 1)); + op == 0x886 || op == 0x3c2 || op == 0xc82 || op == 0x882 || op == 0x292 || op == 0x892 || op == 0x291 || op == 0x981 || op == 0xc13 || op == 0xc10 || op == 0xc23 || op == 0x526 || op == 0x2be || op == 0x8a4 || op == 0xd05 || (op == 0x984 && instruction.Bits(91, 1)) || op == 0x89c || op == 0x883 || op == 0x2a5 || op == 0xd06 || op == 0xf69 || op == 0xc0b || op == 0x8a5 || op == 0x299 || op == 0xc09 || (op == 0x81c && instruction.Bits(67, 1)); } const auto address_of = [](u32 index) { return 0x50U + index * 8 + ((index + 1) / 3) * 8; }; const auto fail = [&](u32 index, std::string_view reason) { @@ -1580,22 +1580,31 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) { return fail(index, "native dependency barrier mode"); } break; - case 0xb69: { // TMML (LOD query), 2D. Results are 8.8 fixed point, as on Maxwell. + case 0xb69: case 0xf69: { // TMML (LOD query), 1D/2D/3D/CUBE. Results are 8.8 fixed point, as on Maxwell. + // 0xf69: the handle in a uniform register (bit 91), Maxwell TMML.B with the handle in Rb. + const bool bindless = opcode == 0xf69; + const u32 handle = bindless ? uniform_register(insn.Bits(40, 6)) : 255; const u32 mask = insn.Bits(72, 4), second_dest = insn.Bits(64, 8); const u32 source_a = insn.Bits(24, 8), source_b = insn.Bits(32, 8); - const u32 binding = insn.Bits(54, 5); - if (insn.Bits(61, 3) != 1 || insn.Bits(76, 4) || insn.Bits(80, 10) || insn.Bits(59, 1) || - insn.Bits(40, 14) > 0x1fff || binding >= 18 || mask == 0 || source_a >= 246 || - (result.required_texture_buffer != ~0U && result.required_texture_buffer != binding)) + const u32 binding = insn.Bits(54, 5), dimension = insn.Bits(61, 3); + // Coordinates: all from Ra when Rb is RZ, else split as for TEX (2D: Ra, Rb). + constexpr std::array<u32, 4> coordinate_count{1, 2, 3, 3}; + const u32 coordinates = dimension < 4 ? coordinate_count[dimension] : 0; + const u32 in_a = source_b == 255 ? coordinates : (coordinates + 1) / 2; + if (coordinates == 0 || insn.Bits(76, 4) || insn.Bits(80, 10) || insn.Bits(59, 1) || mask == 0 || + source_a + in_a > 246 || (source_b != 255 && source_b + (coordinates - in_a) > 246) || + (bindless ? (handle >= 246 || insn.Bits(46, 13) || !insn.Bits(91, 1)) + : (insn.Bits(40, 14) > 0x1fff || binding >= 18 || + (result.required_texture_buffer != ~0U && result.required_texture_buffer != binding)))) return fail(index, "native texture LOD query mode"); - result.required_texture_buffer = binding; - // Coordinates: (Ra, Ra+1) when Rb is RZ, else (Ra, Rb). - emit(0x5c98000000000000ULL | predicate | 250 | (u64{15} << 39) | (u64{source_a} << 20)); - emit(0x5c98000000000000ULL | predicate | 251 | (u64{15} << 39) | - (u64{source_b == 255 ? source_a + 1 : source_b} << 20)); - emit(0xdf58000000000000ULL | predicate | 250 | (u64{250} << 8) | (u64{255} << 20) | - (u64{2} << 28) | (u64{mask} << 31) | (u64{insn.Bits(40, 14)} << 36) | - (u64{insn.Bits(90, 1)} << 49)); + if (!bindless) result.required_texture_buffer = binding; + for (u32 i = 0; i < coordinates; ++i) + emit(0x5c98000000000000ULL | predicate | (250 + i) | (u64{15} << 39) | + (u64{i < in_a ? source_a + i : source_b + (i - in_a)} << 20)); + if (bindless) emit(0x5c98000000000000ULL | predicate | 246 | (u64{15} << 39) | (u64{handle} << 20)); + emit((bindless ? 0xdf60000000000000ULL : 0xdf58000000000000ULL) | predicate | 250 | (u64{250} << 8) | + (u64{bindless ? 246U : 255U} << 20) | (u64{dimension * 2} << 28) | (u64{mask} << 31) | + (u64{bindless ? 0U : insn.Bits(40, 14)} << 36) | (u64{insn.Bits(90, 1)} << 49)); const u32 components = static_cast<u32>(std::popcount(mask)); const bool split = second_dest != 255; for (u32 i = 0; i < components; ++i) { |
