diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 244b7ae00d..2f5293b1bb 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -480,7 +480,20 @@ void FragmentProgramDecompiler::AddCodeCond(const std::string& lhs, const std::s template 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::value) + { + precision_modifier = src1.src0_prec_mod; + } + else if constexpr (std::is_same::value) + { + precision_modifier = src1.src1_prec_mod; + } + else if constexpr (std::is_same::value) + { + precision_modifier = src1.src2_prec_mod; + } switch (src.reg_type) { @@ -504,10 +517,10 @@ template 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 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 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 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 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 std::string FragmentProgramDecompiler::GetSRC(T src) break; } - if (apply_precision_modifier && !src.neg) - { - if constexpr (!std::is_same::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 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; diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 2c0f8b5c26..6b033d76cf 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -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; };