From c00eeb5b10a14f5edbc0489ec5a75afad7afb156 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 16 Nov 2025 14:25:14 +0300 Subject: [PATCH] rsx: Implement register lane gathering for operations other than UPX --- .../RSX/Program/FragmentProgramDecompiler.cpp | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp index e5742fffda..f49ceb3742 100644 --- a/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp @@ -4,6 +4,7 @@ #include "ProgramStateCache.h" #include +#include namespace rsx { @@ -527,21 +528,48 @@ template std::string FragmentProgramDecompiler::GetSRC(T src) if (!src.fp16) { + // We may need to perform gather on all the f32 lanes. + // First, confirm that we're actually reading all the lanes + // TODO: GetSRC should take a lane count argument + std::unordered_set to_gather; + + // Unpack instructions always read the whole vector if (dst.opcode == RSX_FP_OPCODE_UP16 || dst.opcode == RSX_FP_OPCODE_UP2 || dst.opcode == RSX_FP_OPCODE_UP4 || dst.opcode == RSX_FP_OPCODE_UPB || dst.opcode == RSX_FP_OPCODE_UPG) { - auto ® = temp_registers[src.tmp_reg_index]; - if (reg.requires_gather(src.swizzle_x)) + to_gather.insert(src.swizzle_x); + } + else if (!dst.no_dest) + { + // FIXME: No_DST inputs also require lane gather. A regalloc pre-pass will solve this. + // We try to guess which channels will be read. Since there is no lane count, mask input on output mask + if (dst.mask_x) to_gather.insert(src.swizzle_x); + if (dst.mask_y) to_gather.insert(src.swizzle_y); + if (dst.mask_z) to_gather.insert(src.swizzle_z); + if (dst.mask_w) to_gather.insert(src.swizzle_w); + } + + auto& reg = temp_registers[src.tmp_reg_index]; + bool skip_reg_assign = false; + for (const auto& ch : to_gather) + { + if (reg.requires_gather(ch)) { properties.has_gather_op = true; AddReg(src.tmp_reg_index, src.fp16); ret = getFloatTypeName(4) + reg.gather_r(); + skip_reg_assign = true; break; } } + + if (skip_reg_assign) + { + break; + } } else if (precision_modifier == RSX_FP_PRECISION_HALF) {