mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-13 07:14:49 +00:00
rsx/fp: Separate SRC precision modifiers
- SRC0, SRC1 and SRC2 have different bits for precision modifiers all stored inside SRC1 - This explains the strange observed behavior of the MAD instruction which has 3 inputs
This commit is contained in:
parent
dcf5c06d6d
commit
87cc937d4e
@ -480,7 +480,20 @@ void FragmentProgramDecompiler::AddCodeCond(const std::string& lhs, const std::s
|
||||
template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
{
|
||||
std::string ret;
|
||||
bool apply_precision_modifier = !!src1.input_prec_mod;
|
||||
u32 precision_modifier = 0;
|
||||
|
||||
if constexpr (std::is_same<T, SRC0>::value)
|
||||
{
|
||||
precision_modifier = src1.src0_prec_mod;
|
||||
}
|
||||
else if constexpr (std::is_same<T, SRC1>::value)
|
||||
{
|
||||
precision_modifier = src1.src1_prec_mod;
|
||||
}
|
||||
else if constexpr (std::is_same<T, SRC2>::value)
|
||||
{
|
||||
precision_modifier = src1.src2_prec_mod;
|
||||
}
|
||||
|
||||
switch (src.reg_type)
|
||||
{
|
||||
@ -504,10 +517,10 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (src1.input_prec_mod == RSX_FP_PRECISION_HALF)
|
||||
else if (precision_modifier == RSX_FP_PRECISION_HALF)
|
||||
{
|
||||
// clamp16() is not a cheap operation when emulated; avoid at all costs
|
||||
apply_precision_modifier = false;
|
||||
precision_modifier = RSX_FP_PRECISION_REAL;
|
||||
}
|
||||
|
||||
ret += AddReg(src.tmp_reg_index, src.fp16);
|
||||
@ -554,7 +567,7 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
if (!src2.use_index_reg)
|
||||
{
|
||||
ret += "_saturate(" + reg_var + ")";
|
||||
apply_precision_modifier = false;
|
||||
precision_modifier = RSX_FP_PRECISION_REAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -625,7 +638,7 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
}
|
||||
|
||||
ret += reg_var;
|
||||
apply_precision_modifier = false;
|
||||
precision_modifier = RSX_FP_PRECISION_REAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -641,7 +654,6 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
|
||||
case RSX_FP_REGISTER_TYPE_CONSTANT:
|
||||
ret += AddConst();
|
||||
apply_precision_modifier = false;
|
||||
break;
|
||||
|
||||
case RSX_FP_REGISTER_TYPE_UNKNOWN: // ??? Used by a few games, what is it?
|
||||
@ -649,7 +661,7 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
dst.opcode, dst.HEX, src0.HEX, src1.HEX, src2.HEX);
|
||||
|
||||
ret += AddType3();
|
||||
apply_precision_modifier = false;
|
||||
precision_modifier = RSX_FP_PRECISION_REAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -658,21 +670,6 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
break;
|
||||
}
|
||||
|
||||
if (apply_precision_modifier && !src.neg)
|
||||
{
|
||||
if constexpr (!std::is_same<T, SRC0>::value)
|
||||
{
|
||||
if (dst.opcode == RSX_FP_OPCODE_MAD)
|
||||
{
|
||||
// Hardware tests show special behavior on MAD operation
|
||||
// Only src0 obeys precision modifier (sat tested)
|
||||
// Results: 1 * 100 + 0 = 100, 1 * 1 + 100 = 100, 100 * 1 + 0 = 1
|
||||
// NOTE: Neg modifier seems to break this rule; 1 * -100 + 0 = -1 not -99
|
||||
apply_precision_modifier = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char f[4] = { 'x', 'y', 'z', 'w' };
|
||||
|
||||
std::string swizzle;
|
||||
@ -685,7 +682,7 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
|
||||
// Warning: Modifier order matters. e.g neg should be applied after precision clamping (tested with Naruto UNS)
|
||||
if (src.abs) ret = "abs(" + ret + ")";
|
||||
if (apply_precision_modifier) ret = ClampValue(ret, src1.input_prec_mod);
|
||||
if (precision_modifier) ret = ClampValue(ret, precision_modifier);
|
||||
if (src.neg) ret = "-" + ret;
|
||||
|
||||
return ret;
|
||||
|
@ -158,8 +158,9 @@ union SRC1
|
||||
u32 swizzle_w : 2;
|
||||
u32 neg : 1;
|
||||
u32 abs : 1;
|
||||
u32 input_prec_mod : 3; // Looks to be a precision clamping modifier affecting all inputs (tested with Dark Souls II)
|
||||
u32 : 6;
|
||||
u32 src0_prec_mod : 3; // Precision modifier for src0 (many games)
|
||||
u32 src1_prec_mod : 3; // Precision modifier for src1 (CoD:MW series)
|
||||
u32 src2_prec_mod : 3; // Precision modifier for src2 (unproven, should affect MAD instruction)
|
||||
u32 scale : 3;
|
||||
u32 opcode_is_branch : 1;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user