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:
kd-11 2020-06-06 19:46:30 +03:00 committed by kd-11
parent dcf5c06d6d
commit 87cc937d4e
2 changed files with 23 additions and 25 deletions

View File

@ -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;

View File

@ -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;
};