diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 22a1b4503c..ad9fb43e28 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -341,7 +341,9 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode) { case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true; case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true; - case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1).xxxx)"); return true; + // Note: DIVSQ is not IEEE compliant. divsq(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix). + // sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven. + case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, $1)"); return true; case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true; case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true; case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true; @@ -351,8 +353,11 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode) case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); return true; case RSX_FP_OPCODE_MOV: SetDst("$0"); return true; case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true; - case RSX_FP_OPCODE_RCP: SetDst("1.0 / $0"); return true; - case RSX_FP_OPCODE_RSQ: SetDst("1.f / sqrt($0)"); return true; + // Note: It's higly likely that RCP is not IEEE compliant but a game that uses rcp(0) has to be found + case RSX_FP_OPCODE_RCP: SetDst("rcp_legacy($0)"); return true; + // Note: RSQ is not IEEE compliant. rsq(0) is some big number (Silent Hill 3 HD) + // It is not know what happens if 0 is negative. + case RSX_FP_OPCODE_RSQ: SetDst("rsq_legacy($0)"); return true; case RSX_FP_OPCODE_SEQ: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); return true; case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL)); return true; case RSX_FP_OPCODE_SGE: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")"); return true; @@ -372,7 +377,9 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode) case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true; case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); return true; case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true; - case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1).xxxx)"); return true; + // Note: DIVSQ is not IEEE compliant. sqrt(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix). + // sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven. + case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, sqrt($1).xxxx)"); return true; case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true; case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true; case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index ec2094d3d6..43ae0dbf6b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -141,6 +141,24 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS) void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) { + // "lib" function + // 0.00001 is used as "some non zero very little number" + OS << "float4 divsq_legacy(float4 num, float4 denum)\n"; + OS << "{\n"; + OS << " return num / sqrt(max(denum.xxxx, 0.00001));\n"; + OS << "}\n"; + + OS << "float4 rcp_legacy(float4 denum)\n"; + OS << "{\n"; + OS << " return 1. / denum;\n"; + OS << "}\n"; + + OS << "float4 rsq_legacy(float4 denum)\n"; + OS << "{\n"; + OS << " return 1. / sqrt(max(denum, 0.00001));\n"; + OS << "}\n"; + + const std::set output_value = { "r0", "r1", "r2", "r3", "r4", diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 24600c02eb..82814d861d 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -84,6 +84,23 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { + // "lib" function + // 0.00001 is used as "some non zero very little number" + OS << "vec4 divsq_legacy(vec4 num, vec4 denum)\n"; + OS << "{\n"; + OS << " return num / sqrt(max(denum.xxxx, 0.00001));\n"; + OS << "}\n"; + + OS << "vec4 rcp_legacy(vec4 denum)\n"; + OS << "{\n"; + OS << " return 1. / denum;\n"; + OS << "}\n"; + + OS << "vec4 rsq_legacy(vec4 denum)\n"; + OS << "{\n"; + OS << " return 1. / sqrt(max(denum, 0.00001));\n"; + OS << "}\n"; + OS << "void main ()" << std::endl; OS << "{" << std::endl;