Compare commits

...

10 commits

Author SHA1 Message Date
kd-11 728f0056ea
Merge 4a4569fa28 into 67f7119717 2025-12-05 01:13:15 +08:00
Elad 67f7119717
Make RSX FIFO Atomic fetching default (#17810)
Some checks failed
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, .ci/build-mac.sh, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, .ci/build-mac-arm64.sh, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang (win64, clang, clang64) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
Generate Translation Template / Generate Translation Template (push) Has been cancelled
2025-12-04 18:17:39 +02:00
kd-11 4a4569fa28 rsx/fp: Fix the delay slot detection 2025-11-17 22:04:44 +03:00
kd-11 a914fc8ca1 rsx/fp: Use precomputed masks instead of translating from strings 2025-11-17 21:38:57 +03:00
kd-11 b65687e1e9 rsx: Do not emit gather for FP delay slots 2025-11-16 20:20:50 +03:00
kd-11 b32ccacc57 rsx: Fix build 2025-11-16 18:13:32 +03:00
kd-11 c2a894996a rsx: Implement more robust FP register file aliasing resolution 2025-11-16 17:56:27 +03:00
kd-11 3102ae4b52 vk: Include GCM format in debug name for temp texture-cache resources 2025-11-16 14:26:41 +03:00
kd-11 f64db8b5ed rsx: Fix convolution filter decoding 2025-11-16 14:25:57 +03:00
kd-11 c00eeb5b10 rsx: Implement register lane gathering for operations other than UPX 2025-11-16 14:25:14 +03:00
8 changed files with 260 additions and 18 deletions

View file

@ -2,8 +2,10 @@
#include "FragmentProgramDecompiler.h"
#include "ProgramStateCache.h"
#include "Emu/RSX/Common/simple_array.hpp"
#include <algorithm>
#include <unordered_set>
namespace rsx
{
@ -31,6 +33,191 @@ enum VectorLane : u8
W = 3,
};
u32 FragmentProgramDecompiler::get_src_vector_mask(u32 opcode, u32 operand) const
{
constexpr u32 x = 0b0001;
constexpr u32 y = 0b0010;
constexpr u32 z = 0b0100;
constexpr u32 w = 0b1000;
constexpr u32 xy = 0b0011;
constexpr u32 xyz = 0b0111;
constexpr u32 xyzw = 0b1111;
constexpr u32 use_dst_mask = 1u << 31;
const auto decode = [&](const rsx::simple_array<u32>& masks) -> u32
{
return operand < masks.size()
? masks[operand]
: 0u;
};
switch (opcode)
{
case RSX_FP_OPCODE_NOP:
return 0;
case RSX_FP_OPCODE_MOV:
case RSX_FP_OPCODE_MUL:
case RSX_FP_OPCODE_ADD:
case RSX_FP_OPCODE_MAD:
return xyzw | use_dst_mask;
case RSX_FP_OPCODE_DP3:
return xyz;
case RSX_FP_OPCODE_DP4:
return xyzw;
case RSX_FP_OPCODE_DST:
return decode({ y|z, y|w });
case RSX_FP_OPCODE_MIN:
case RSX_FP_OPCODE_MAX:
return xyzw | use_dst_mask;
case RSX_FP_OPCODE_SLT:
case RSX_FP_OPCODE_SGE:
case RSX_FP_OPCODE_SLE:
case RSX_FP_OPCODE_SGT:
case RSX_FP_OPCODE_SNE:
case RSX_FP_OPCODE_SEQ:
return xyzw | use_dst_mask;
case RSX_FP_OPCODE_FRC:
case RSX_FP_OPCODE_FLR:
return xyzw | use_dst_mask;
case RSX_FP_OPCODE_KIL:
return 0;
case RSX_FP_OPCODE_PK4:
return xyzw;
case RSX_FP_OPCODE_UP4:
return x;
case RSX_FP_OPCODE_DDX:
case RSX_FP_OPCODE_DDY:
return xyzw | use_dst_mask;
case RSX_FP_OPCODE_TEX:
case RSX_FP_OPCODE_TXD:
switch (m_prog.get_texture_dimension(dst.tex_num))
{
case rsx::texture_dimension_extended::texture_dimension_1d:
return x;
case rsx::texture_dimension_extended::texture_dimension_2d:
return xy;
case rsx::texture_dimension_extended::texture_dimension_3d:
case rsx::texture_dimension_extended::texture_dimension_cubemap:
return xyz;
default:
return 0;
}
case RSX_FP_OPCODE_TXP:
switch (m_prog.get_texture_dimension(dst.tex_num))
{
case rsx::texture_dimension_extended::texture_dimension_1d:
return xy;
case rsx::texture_dimension_extended::texture_dimension_2d:
return xyz;
case rsx::texture_dimension_extended::texture_dimension_3d:
case rsx::texture_dimension_extended::texture_dimension_cubemap:
return xyzw;
default:
return 0;
}
case RSX_FP_OPCODE_RCP:
case RSX_FP_OPCODE_RSQ:
case RSX_FP_OPCODE_EX2:
case RSX_FP_OPCODE_LG2:
return x;
case RSX_FP_OPCODE_LIT:
return xyzw;
case RSX_FP_OPCODE_LRP:
return xyzw | use_dst_mask;
case RSX_FP_OPCODE_STR:
case RSX_FP_OPCODE_SFL:
return xyzw | use_dst_mask;
case RSX_FP_OPCODE_COS:
case RSX_FP_OPCODE_SIN:
return x;
case RSX_FP_OPCODE_PK2:
return xy;
case RSX_FP_OPCODE_UP2:
return x;
case RSX_FP_OPCODE_POW:
fmt::throw_exception("Unimplemented POW instruction."); // Unused ??
case RSX_FP_OPCODE_PKB:
return xyzw;
case RSX_FP_OPCODE_UPB:
return x;
case RSX_FP_OPCODE_PK16:
return xy;
case RSX_FP_OPCODE_UP16:
return x;
case RSX_FP_OPCODE_BEM:
return decode({ xy, xy, xyzw });
case RSX_FP_OPCODE_PKG:
return xyzw;
case RSX_FP_OPCODE_UPG:
return x;
case RSX_FP_OPCODE_DP2A:
return decode({ xy, xy, x });
case RSX_FP_OPCODE_TXL:
case RSX_FP_OPCODE_TXB:
return decode({ xy, x });
case RSX_FP_OPCODE_TEXBEM:
case RSX_FP_OPCODE_TXPBEM:
return decode({ xy, xy, xyzw }); // Coordinate generated from BEM operation
case RSX_FP_OPCODE_BEMLUM:
fmt::throw_exception("Unimplemented BEMLUM instruction"); // Unused
case RSX_FP_OPCODE_REFL:
return xyzw;
case RSX_FP_OPCODE_TIMESWTEX:
fmt::throw_exception("Unimplemented TIMESWTEX instruction"); // Unused
case RSX_FP_OPCODE_DP2:
return xy;
case RSX_FP_OPCODE_NRM:
return xyz;
case RSX_FP_OPCODE_DIV:
case RSX_FP_OPCODE_DIVSQ:
return decode({ xyzw, x });
case RSX_FP_OPCODE_LIF:
return decode({ y|w });
case RSX_FP_OPCODE_FENCT:
case RSX_FP_OPCODE_FENCB:
case RSX_FP_OPCODE_BRK:
case RSX_FP_OPCODE_CAL:
case RSX_FP_OPCODE_IFE:
case RSX_FP_OPCODE_LOOP:
case RSX_FP_OPCODE_REP:
case RSX_FP_OPCODE_RET:
// Flow control. Special registers are provided for these outside the common file
return 0;
default:
break;
}
return 0;
}
bool FragmentProgramDecompiler::is_delay_slot() const
{
if (dst.opcode != RSX_FP_OPCODE_MOV || // These slots are always populated with MOV
dst.no_dest || // Must have a sink
src0.reg_type != RSX_FP_REGISTER_TYPE_TEMP || // Must read from reg
dst.dest_reg != src0.tmp_reg_index || // Must be a write-to-self
dst.fp16 || // Always full lane. We need to collect more data on this but it won't matter
dst.saturate || // Precision modifier
(dst.prec != RSX_FP_PRECISION_REAL &&
dst.prec != RSX_FP_PRECISION_UNKNOWN)) // Cannot have precision modifiers
{
return false;
}
// Check if we have precision modifiers on the source
if (src0.abs || src0.neg || src1.scale)
{
return false;
}
if (dst.mask_x && src0.swizzle_x != 0) return false;
if (dst.mask_y && src0.swizzle_y != 1) return false;
if (dst.mask_z && src0.swizzle_z != 2) return false;
if (dst.mask_w && src0.swizzle_w != 3) return false;
return true;
}
FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size)
: m_size(size)
, m_prog(prog)
@ -166,7 +353,10 @@ void FragmentProgramDecompiler::SetDst(std::string code, u32 flags)
}
}
temp_registers[reg_index].tag(dst.dest_reg, !!dst.fp16, dst.mask_x, dst.mask_y, dst.mask_z, dst.mask_w);
if (!is_delay_slot())
{
temp_registers[reg_index].tag(dst.dest_reg, !!dst.fp16, dst.mask_x, dst.mask_y, dst.mask_z, dst.mask_w);
}
}
void FragmentProgramDecompiler::AddFlowOp(const std::string& code)
@ -501,22 +691,33 @@ void FragmentProgramDecompiler::AddCodeCond(const std::string& lhs, const std::s
AddCode(lhs + " = _select(" + lhs + ", " + src_prefix + rhs + ", " + cond + ");");
}
template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
template<typename T>
requires std::is_same_v<T, SRC0> || std::is_same_v<T, SRC1> || std::is_same_v<T, SRC2>
std::string FragmentProgramDecompiler::GetSRC(T src)
{
std::string ret;
u32 precision_modifier = 0;
u32 operand_idx = umax;
if constexpr (std::is_same_v<T, SRC0>)
{
precision_modifier = src1.src0_prec_mod;
operand_idx = 0;
}
else if constexpr (std::is_same_v<T, SRC1>)
{
precision_modifier = src1.src1_prec_mod;
operand_idx = 1;
}
else if constexpr (std::is_same_v<T, SRC2>)
{
precision_modifier = src1.src2_prec_mod;
operand_idx = 2;
}
else
{
// Unreachable unless we add another SRC type
fmt::throw_exception("Invalid SRC input");
}
switch (src.reg_type)
@ -525,21 +726,45 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
if (!src.fp16)
{
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)
// We need to determine if any vector lanes need a gather op
// In theory, splitting can also be required, but that is currently unsupported
u32 src_lane_mask = is_delay_slot() ? 0u : get_src_vector_mask(dst.opcode, operand_idx);
std::unordered_set<u8> lanes_to_gather;
const bool apply_dst_mask = src_lane_mask & (1u << 31);
src_lane_mask &= ~(1u << 31);
if (apply_dst_mask && !dst.no_dest)
{
auto &reg = temp_registers[src.tmp_reg_index];
if (reg.requires_gather(src.swizzle_x))
if (!dst.mask_x) src_lane_mask &= ~(1u << 0);
if (!dst.mask_y) src_lane_mask &= ~(1u << 1);
if (!dst.mask_z) src_lane_mask &= ~(1u << 2);
if (!dst.mask_w) src_lane_mask &= ~(1u << 3);
}
if (src_lane_mask & (1u << 0)) lanes_to_gather.insert(src.swizzle_x);
if (src_lane_mask & (1u << 1)) lanes_to_gather.insert(src.swizzle_y);
if (src_lane_mask & (1u << 2)) lanes_to_gather.insert(src.swizzle_z);
if (src_lane_mask & (1u << 3)) lanes_to_gather.insert(src.swizzle_w);
auto& reg = temp_registers[src.tmp_reg_index];
bool skip_reg_assign = false;
for (const auto& ch : lanes_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)
{

View file

@ -81,7 +81,11 @@ class FragmentProgramDecompiler
void AddCodeCond(const std::string& lhs, const std::string& rhs);
std::string GetRawCond();
std::string GetCond();
template<typename T> std::string GetSRC(T src);
template<typename T>
requires std::is_same_v<T, SRC0> || std::is_same_v<T, SRC1> || std::is_same_v<T, SRC2>
std::string GetSRC(T src);
std::string BuildCode();
static u32 GetData(const u32 d) { return d << 16 | d >> 16; }
@ -100,6 +104,17 @@ class FragmentProgramDecompiler
*/
bool handle_tex_srb(u32 opcode);
/**
* Calculates the lane mask for a given input
* This is a temporary workaround until the decompiler is rewritten with some IR to allow granular split/gather passes
*/
u32 get_src_vector_mask(u32 opcode, u32 operand) const;
/**
* Detects delay slots. These evaluate to a NOP so we don't actually need to emit them
*/
bool is_delay_slot() const;
protected:
const RSXFragmentProgram &m_prog;
u32 m_ctrl = 0;

View file

@ -251,7 +251,7 @@ namespace rsx
u8 fragment_texture::convolution_filter() const
{
return ((registers[NV4097_SET_TEXTURE_FILTER + (m_index * 8)] >> 13) & 0xf);
return ((registers[NV4097_SET_TEXTURE_FILTER + (m_index * 8)] >> 13) & 0x7);
}
u8 fragment_texture::argb_signed() const

View file

@ -716,7 +716,7 @@ namespace vk
view_swizzle = source->native_component_map;
}
image->set_debug_name("Temp view");
image->set_debug_name(fmt::format("Temp view, fmt=0x%x", gcm_format));
image->set_native_component_layout(view_swizzle);
auto view = image->get_view(remap_vector);

View file

@ -954,6 +954,8 @@ namespace gcm
CELL_GCM_TEXTURE_LINEAR_LINEAR = 6,
CELL_GCM_TEXTURE_CONVOLUTION_MIN = 7,
CELL_GCM_TEXTURE_CONVOLUTION_MAG = 4,
// Convolution mode
CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX = 1,
CELL_GCM_TEXTURE_CONVOLUTION_GAUSSIAN = 2,
CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX_ALT = 3,

View file

@ -53,7 +53,7 @@ struct cfg_root : cfg::node
}
};
fifo_setting rsx_fifo_accuracy{this, "RSX FIFO Accuracy", rsx_fifo_mode::fast };
fifo_setting rsx_fifo_accuracy{this, "RSX FIFO Fetch Accuracy", rsx_fifo_mode::atomic };
cfg::_bool spu_verification{ this, "SPU Verification", true }; // Should be enabled
cfg::_bool spu_cache{ this, "SPU Cache", true };
cfg::_bool spu_prof{ this, "SPU Profiler", false };

View file

@ -1198,10 +1198,10 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_
case emu_settings_type::FIFOAccuracy:
switch (static_cast<rsx_fifo_mode>(index))
{
case rsx_fifo_mode::fast: return tr("Fast", "RSX FIFO Accuracy");
case rsx_fifo_mode::atomic: return tr("Atomic", "RSX FIFO Accuracy");
case rsx_fifo_mode::atomic_ordered: return tr("Ordered & Atomic", "RSX FIFO Accuracy");
case rsx_fifo_mode::as_ps3: return tr("PS3", "RSX FIFO Accuracy");
case rsx_fifo_mode::fast: return tr("Fast", "RSX FIFO Fetch Accuracy");
case rsx_fifo_mode::atomic: return tr("Atomic", "RSX FIFO Fetch Accuracy");
case rsx_fifo_mode::atomic_ordered: return tr("Ordered & Atomic", "RSX FIFO Fetch Accuracy");
case rsx_fifo_mode::as_ps3: return tr("PS3", "RSX FIFO Fetch Accuracy");
}
break;
case emu_settings_type::PerfOverlayDetailLevel:

View file

@ -235,7 +235,7 @@ inline static const std::map<emu_settings_type, cfg_location> settings_location
{ emu_settings_type::AccurateSpuDMA, { "Core", "Accurate SPU DMA"}},
{ emu_settings_type::AccurateClineStores, { "Core", "Accurate Cache Line Stores"}},
{ emu_settings_type::AccurateRSXAccess, { "Core", "Accurate RSX reservation access"}},
{ emu_settings_type::FIFOAccuracy, { "Core", "RSX FIFO Accuracy"}},
{ emu_settings_type::FIFOAccuracy, { "Core", "RSX FIFO Fetch Accuracy"}},
{ emu_settings_type::XFloatAccuracy, { "Core", "XFloat Accuracy"}},
{ emu_settings_type::MFCCommandsShuffling, { "Core", "MFC Commands Shuffling Limit"}},
{ emu_settings_type::SetDAZandFTZ, { "Core", "Set DAZ and FTZ"}},