mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-08-10 10:09:22 +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
2 changed files with 23 additions and 25 deletions
|
@ -480,7 +480,20 @@ void FragmentProgramDecompiler::AddCodeCond(const std::string& lhs, const std::s
|
||||||
template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||||
{
|
{
|
||||||
std::string ret;
|
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)
|
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
|
// 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);
|
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)
|
if (!src2.use_index_reg)
|
||||||
{
|
{
|
||||||
ret += "_saturate(" + reg_var + ")";
|
ret += "_saturate(" + reg_var + ")";
|
||||||
apply_precision_modifier = false;
|
precision_modifier = RSX_FP_PRECISION_REAL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -625,7 +638,7 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret += reg_var;
|
ret += reg_var;
|
||||||
apply_precision_modifier = false;
|
precision_modifier = RSX_FP_PRECISION_REAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,7 +654,6 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||||
|
|
||||||
case RSX_FP_REGISTER_TYPE_CONSTANT:
|
case RSX_FP_REGISTER_TYPE_CONSTANT:
|
||||||
ret += AddConst();
|
ret += AddConst();
|
||||||
apply_precision_modifier = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RSX_FP_REGISTER_TYPE_UNKNOWN: // ??? Used by a few games, what is it?
|
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);
|
dst.opcode, dst.HEX, src0.HEX, src1.HEX, src2.HEX);
|
||||||
|
|
||||||
ret += AddType3();
|
ret += AddType3();
|
||||||
apply_precision_modifier = false;
|
precision_modifier = RSX_FP_PRECISION_REAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -658,21 +670,6 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||||
break;
|
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' };
|
static const char f[4] = { 'x', 'y', 'z', 'w' };
|
||||||
|
|
||||||
std::string swizzle;
|
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)
|
// Warning: Modifier order matters. e.g neg should be applied after precision clamping (tested with Naruto UNS)
|
||||||
if (src.abs) ret = "abs(" + ret + ")";
|
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;
|
if (src.neg) ret = "-" + ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -158,8 +158,9 @@ union SRC1
|
||||||
u32 swizzle_w : 2;
|
u32 swizzle_w : 2;
|
||||||
u32 neg : 1;
|
u32 neg : 1;
|
||||||
u32 abs : 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 src0_prec_mod : 3; // Precision modifier for src0 (many games)
|
||||||
u32 : 6;
|
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 scale : 3;
|
||||||
u32 opcode_is_branch : 1;
|
u32 opcode_is_branch : 1;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue