From 06a85f00d1ff522e51564a399ba88f08ac136368 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 13 Apr 2019 13:20:50 +0300 Subject: [PATCH] rsx: Shader decompiler cleanup and improvements - Improve support for float16_t by minimizing mixed inputs to functions (ambiguous overloads) - Minimize amount of downcasts in code by using opcode flags - Re-enable float16_t support for vulkan --- .../RSX/Common/FragmentProgramDecompiler.cpp | 208 ++++++++++++------ .../RSX/Common/FragmentProgramDecompiler.h | 22 +- rpcs3/Emu/RSX/Common/GLSLCommon.h | 16 +- .../RSX/Common/VertexProgramDecompiler.cpp | 3 +- .../D3D12/D3D12FragmentProgramDecompiler.cpp | 5 - .../D3D12/D3D12FragmentProgramDecompiler.h | 1 - rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp | 8 +- rpcs3/Emu/RSX/GL/GLFragmentProgram.h | 1 - rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 8 +- rpcs3/Emu/RSX/VK/VKFragmentProgram.h | 1 - rpcs3/Emu/RSX/VK/VKHelpers.h | 2 +- 11 files changed, 162 insertions(+), 113 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 05754ca4a0..a327dd9f35 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -16,23 +16,37 @@ FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &p m_size = 0; } -void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask) +void FragmentProgramDecompiler::SetDst(std::string code, u32 flags) { if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; - switch (src1.scale) + if (src1.scale) { - case 0: break; - case 1: code = "(" + code + " * 2.0)"; break; - case 2: code = "(" + code + " * 4.0)"; break; - case 3: code = "(" + code + " * 8.0)"; break; - case 5: code = "(" + code + " / 2.0)"; break; - case 6: code = "(" + code + " / 4.0)"; break; - case 7: code = "(" + code + " / 8.0)"; break; + std::string modifier; + switch (src1.scale) + { + case 0: break; + case 1: code = "(" + code + " * "; modifier = "2."; break; + case 2: code = "(" + code + " * "; modifier = "4."; break; + case 3: code = "(" + code + " * "; modifier = "8."; break; + case 5: code = "(" + code + " / "; modifier = "2."; break; + case 6: code = "(" + code + " / "; modifier = "4."; break; + case 7: code = "(" + code + " / "; modifier = "8."; break; - default: - LOG_ERROR(RSX, "Bad scale: %d", u32{ src1.scale }); - break; + default: + LOG_ERROR(RSX, "Bad scale: %d", u32{ src1.scale }); + break; + } + + if (flags & OPFLAGS::skip_type_cast && dst.fp16 && device_props.has_native_half_support) + { + modifier = getHalfTypeName(1) + "(" + modifier + ")"; + } + + if (!modifier.empty()) + { + code = code + modifier + ")"; + } } if (!dst.no_dest) @@ -44,23 +58,23 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask) code = "((" + code + "- 0.5) * 2.)"; } - if (dst.fp16 && device_props.has_native_half_support) + if (dst.fp16 && device_props.has_native_half_support && !(flags & OPFLAGS::skip_type_cast)) { // Cast to native data type if (dst.opcode == RSX_FP_OPCODE_NRM) { // Returns a 3-component vector as the result - code = ClampValue(code + ".xyzz", 1); + code = ClampValue(code + ".xyzz", 1, true); } else { - code = ClampValue(code, 1); + code = ClampValue(code, 1, true); } } if (dst.saturate) { - code = saturate(code); + code = ClampValue(code, 4, !!dst.fp16); } else if (dst.prec) { @@ -94,14 +108,15 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask) break; // clamp value to allowed range - code = ClampValue(code, dst.prec); + code = ClampValue(code, dst.prec, !!dst.fp16); break; } } } } - code += (append_mask ? "$m" : ""); + opflags = flags; + code += (flags & OPFLAGS::no_src_mask) ? "" : "$m"; if (dst.no_dest) { @@ -249,36 +264,48 @@ std::string FragmentProgramDecompiler::AddX2d() return m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), "x2d", getFloatTypeName(4) + "(0., 0., 0., 0.)"); } -//Both of these were tested with a trace SoulCalibur IV title screen -//Failure to catch causes infinite values since there is a lot of rcp(0) -std::string FragmentProgramDecompiler::NotZero(const std::string& code) -{ - return "(max(abs(" + code + "), 0.0000000001) * sign(" + code + "))"; -} - -std::string FragmentProgramDecompiler::NotZeroPositive(const std::string& code) -{ - return "max(abs(" + code + "), 0.0000000001)"; -} - -std::string FragmentProgramDecompiler::ClampValue(const std::string& code, u32 precision) +std::string FragmentProgramDecompiler::ClampValue(const std::string& code, u32 precision, bool is_half_type) { // FP16 is expected to overflow a lot easier at 0+-65504 // FP32 can still work up to 0+-3.4E38 // See http://http.download.nvidia.com/developer/Papers/2005/FP_Specials/FP_Specials.pdf - switch (precision) + if (LIKELY(precision <= 1)) { - case 0: - break; - case 1: - return "clamp16(" + code + ")"; - case 2: - return "clamp(" + code + ", -2., 2.)"; - case 3: - return "clamp(" + code + ", -1., 1.)"; - case 4: - return "clamp(" + code + ", 0., 1.)"; + if (precision == 1) + { + return "clamp16(" + code + ")"; + } + else + { + return code; + } + } + + if (!is_half_type || !device_props.has_native_half_support) + { + switch (precision) + { + case 2: + return "clamp(" + code + ", -2., 2.)"; + case 3: + return "clamp(" + code + ", -1., 1.)"; + case 4: + return "clamp(" + code + ", 0., 1.)"; + } + } + else + { + const auto type = getHalfTypeName(1); + switch (precision) + { + case 2: + return "clamp(" + code + ", " + type + "(-2.), " + type + "(2.))"; + case 3: + return "clamp(" + code + ", " + type + "(-1.), " + type + "(1.))"; + case 4: + return "clamp(" + code + ", " + type + "(0.), " + type + "(1.))"; + } } return code; @@ -316,7 +343,7 @@ std::string FragmentProgramDecompiler::Format(const std::string& code, bool igno }, { "$cond", std::bind(std::mem_fn(&FragmentProgramDecompiler::GetCond), this) }, { "$_c", std::bind(std::mem_fn(&FragmentProgramDecompiler::AddConst), this) }, - { "$float4", [this]() -> std::string { return getFloatTypeName(4); } } + { "$Ty", [this]() -> std::string { return (!device_props.has_native_half_support || !dst.fp16)? getFloatTypeName(4) : getHalfTypeName(4); } } }; if (!ignore_redirects) @@ -404,6 +431,7 @@ template std::string FragmentProgramDecompiler::GetSRC(T src) { std::string ret; bool apply_precision_modifier = !!src1.input_prec_mod; + bool is_half_type = false; switch (src.reg_type) { @@ -427,8 +455,19 @@ template std::string FragmentProgramDecompiler::GetSRC(T src) } } } + else + { + is_half_type = true; + } + + ret += AddReg(src.tmp_reg_index, is_half_type); + + if (opflags & OPFLAGS::src_cast_f32 && is_half_type && device_props.has_native_half_support) + { + // Upconvert if there is a chance for ambiguity + ret = getFloatTypeName(4) + "(" + ret + ")"; + } - ret += AddReg(src.tmp_reg_index, !!src.fp16); break; case RSX_FP_REGISTER_TYPE_INPUT: @@ -497,7 +536,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 (apply_precision_modifier) ret = ClampValue(ret, src1.input_prec_mod, is_half_type); if (src.neg) ret = "-" + ret; return ret; @@ -590,12 +629,34 @@ std::string FragmentProgramDecompiler::BuildCode() "vec3 clamp16(vec3 x){ return clamp16(x.xyzz).xyz; }\n" "vec2 clamp16(vec2 x){ return clamp16(x.xyxy).xy; }\n" "float clamp16(float x){ return isnan(x)? x : clamp(x, -65504., +65504.); }\n\n"; + + OS << + "#define _builtin_min min\n" + "#define _builtin_max max\n" + "#define _builtin_lit lit_legacy\n" + "#define _builtin_distance distance\n" + "#define _builtin_rcp(x) (1. / x)\n" + "#define _builtin_rsq(x) (1. / sqrt(x))\n" + "#define _builtin_log2(x) log2(abs(x))\n" + "#define _builtin_div(x, y) (x / y)\n" + "#define _builtin_divsq(x, y) (x / sqrt(y))\n\n"; } else { // Define raw casts from f32->f16 + // Also define upcasting to avoid ambiguous function overloading in case of mixed inputs const std::string half4 = getHalfTypeName(4); - OS << "#define clamp16(x) " << half4 << "(x)\n\n"; + OS << + "#define clamp16(x) " << half4 << "(x)\n" + "#define _builtin_min(x, y) min(vec4(x), vec4(y))\n" + "#define _builtin_max(x, y) max(vec4(x), vec4(y))\n" + "#define _builtin_lit lit_legacy\n" + "#define _builtin_distance(x, y) distance(vec4(x), vec4(y))\n" + "#define _builtin_rcp(x) (1. / x)\n" + "#define _builtin_rsq(x) (1. / sqrt(x))\n" + "#define _builtin_log2(x) log2(abs(x))\n" + "#define _builtin_div(x, y) (x / y)\n" + "#define _builtin_divsq(x, y) (x / sqrt(y))\n\n"; } @@ -634,37 +695,37 @@ bool FragmentProgramDecompiler::handle_sct_scb(u32 opcode) switch (opcode) { case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true; - case RSX_FP_OPCODE_DIV: SetDst("($0 / " + NotZero("$1.x") + ")"); return true; + case RSX_FP_OPCODE_DIV: SetDst("_builtin_div($0, $1.x)"); 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("($0 / sqrt(" + NotZeroPositive("$1.x") + "))"); 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; - case RSX_FP_OPCODE_DP2A: SetDst(getFunction(FUNCTION::FUNCTION_DP2A)); return true; + case RSX_FP_OPCODE_DIVSQ: SetDst("_builtin_divsq($0, $1.x)"); return true; + case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2), OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3), OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4), OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_DP2A: SetDst(getFunction(FUNCTION::FUNCTION_DP2A), OPFLAGS::op_extern); return true; case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); return true; - case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); return true; - case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); return true; + case RSX_FP_OPCODE_MAX: SetDst("_builtin_max($0, $1)"); return true; + case RSX_FP_OPCODE_MIN: SetDst("_builtin_min($0, $1)"); return true; case RSX_FP_OPCODE_MOV: SetDst("$0"); return true; case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true; // Note: It's highly likely that RCP is not IEEE compliant but a game that uses rcp(0) has to be found - case RSX_FP_OPCODE_RCP: SetDst("(1. / " + NotZero("$0.x") + ").xxxx"); return true; + case RSX_FP_OPCODE_RCP: SetDst("_builtin_rcp($0.x).xxxx"); 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("(1. / sqrt(" + NotZeroPositive("$0.x") + ").xxxx)"); 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; - case RSX_FP_OPCODE_SGT: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGT, "$0", "$1") + ")"); return true; - case RSX_FP_OPCODE_SLE: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SLE, "$0", "$1") + ")"); return true; - case RSX_FP_OPCODE_SLT: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SLT, "$0", "$1") + ")"); return true; - case RSX_FP_OPCODE_SNE: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SNE, "$0", "$1") + ")"); return true; - case RSX_FP_OPCODE_STR: SetDst(getFunction(FUNCTION::FUNCTION_STR)); return true; + case RSX_FP_OPCODE_RSQ: SetDst("_builtin_rsq($0.x).xxxx"); return true; + case RSX_FP_OPCODE_SEQ: SetDst("$Ty(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")", OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL), OPFLAGS::skip_type_cast); return true; + case RSX_FP_OPCODE_SGE: SetDst("$Ty(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")", OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_SGT: SetDst("$Ty(" + compareFunction(COMPARE::FUNCTION_SGT, "$0", "$1") + ")", OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_SLE: SetDst("$Ty(" + compareFunction(COMPARE::FUNCTION_SLE, "$0", "$1") + ")", OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_SLT: SetDst("$Ty(" + compareFunction(COMPARE::FUNCTION_SLT, "$0", "$1") + ")", OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_SNE: SetDst("$Ty(" + compareFunction(COMPARE::FUNCTION_SNE, "$0", "$1") + ")", OPFLAGS::op_extern); return true; + case RSX_FP_OPCODE_STR: SetDst(getFunction(FUNCTION::FUNCTION_STR), OPFLAGS::skip_type_cast); return true; // SCB-only ops case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); return true; - case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); return true; - case RSX_FP_OPCODE_REFL: SetDst(getFunction(FUNCTION::FUNCTION_REFL)); return true; + case RSX_FP_OPCODE_DST: SetDst("_builtin_distance($0, $1).xxxx"); return true; + case RSX_FP_OPCODE_REFL: SetDst(getFunction(FUNCTION::FUNCTION_REFL), OPFLAGS::op_extern); return true; case RSX_FP_OPCODE_EX2: SetDst("exp2($0.xxxx)"); return true; case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); return true; case RSX_FP_OPCODE_FRC: SetDst(getFunction(FUNCTION::FUNCTION_FRACT)); return true; @@ -672,15 +733,15 @@ bool FragmentProgramDecompiler::handle_sct_scb(u32 opcode) SetDst("lit_legacy($0)"); properties.has_lit_op = true; return true; - case RSX_FP_OPCODE_LIF: SetDst(getFloatTypeName(4) + "(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); return true; - case RSX_FP_OPCODE_LRP: SetDst(getFloatTypeName(4) + "($2 * (1 - $0) + $1 * $0)"); return true; - case RSX_FP_OPCODE_LG2: SetDst("log2(" + NotZeroPositive("$0.x") + ").xxxx"); return true; - //Pack operations. See https://www.khronos.org/registry/OpenGL/extensions/NV/NV_fragment_program.txt + case RSX_FP_OPCODE_LIF: SetDst("$Ty(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)", OPFLAGS::skip_type_cast); return true; + case RSX_FP_OPCODE_LRP: SetDst("$Ty($2 * (1 - $0) + $1 * $0)", OPFLAGS::skip_type_cast); return true; + case RSX_FP_OPCODE_LG2: SetDst("_builtin_log2($0.x).xxxx"); return true; + // Pack operations. See https://www.khronos.org/registry/OpenGL/extensions/NV/NV_fragment_program.txt case RSX_FP_OPCODE_PK2: SetDst(getFloatTypeName(4) + "(uintBitsToFloat(packHalf2x16($0.xy)))"); return true; case RSX_FP_OPCODE_PK4: SetDst(getFloatTypeName(4) + "(uintBitsToFloat(packSnorm4x8($0)))"); return true; case RSX_FP_OPCODE_PK16: SetDst(getFloatTypeName(4) + "(uintBitsToFloat(packSnorm2x16($0.xy)))"); return true; case RSX_FP_OPCODE_PKG: - //Should be similar to PKB but with gamma correction, see description of PK4UBG in khronos page + // Should be similar to PKB but with gamma correction, see description of PK4UBG in khronos page case RSX_FP_OPCODE_PKB: SetDst(getFloatTypeName(4) + "(uintBitsToFloat(packUnorm4x8($0)))"); return true; case RSX_FP_OPCODE_SIN: SetDst("sin($0.xxxx)"); return true; } @@ -813,12 +874,12 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) return true; } return false; - //Unpack operations. See https://www.khronos.org/registry/OpenGL/extensions/NV/NV_fragment_program.txt + // Unpack operations. See https://www.khronos.org/registry/OpenGL/extensions/NV/NV_fragment_program.txt case RSX_FP_OPCODE_UP2: SetDst("unpackHalf2x16(floatBitsToUint($0.x)).xyxy"); return true; case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8(floatBitsToUint($0.x))"); return true; case RSX_FP_OPCODE_UP16: SetDst("unpackSnorm2x16(floatBitsToUint($0.x)).xyxy"); return true; case RSX_FP_OPCODE_UPG: - //Same as UPB with gamma correction + // Same as UPB with gamma correction case RSX_FP_OPCODE_UPB: SetDst("(unpackUnorm4x8(floatBitsToUint($0.x)))"); return true; } return false; @@ -871,6 +932,7 @@ std::string FragmentProgramDecompiler::Decompile() src2.HEX = GetData(data[3]); m_offset = 4 * sizeof(u32); + opflags = 0; const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6); diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h index 6afed73702..c88e975dab 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h @@ -128,10 +128,20 @@ struct temp_register */ class FragmentProgramDecompiler { + enum OPFLAGS + { + no_src_mask = 1, + src_cast_f32 = 2, + skip_type_cast = 4, + + op_extern = src_cast_f32 | skip_type_cast, + }; + OPDEST dst; SRC0 src0; SRC1 src1; SRC2 src2; + u32 opflags; std::string main; u32& m_size; @@ -148,7 +158,7 @@ class FragmentProgramDecompiler std::string GetMask(); - void SetDst(std::string code, bool append_mask = true); + void SetDst(std::string code, u32 flags = 0); void AddCode(const std::string& code); std::string AddReg(u32 index, bool fp16); bool HasReg(u32 index, bool fp16); @@ -164,13 +174,8 @@ class FragmentProgramDecompiler //Support the transform-2d temp result for use with TEXBEM std::string AddX2d(); - //Prevent division by zero by catching denormals - //Simpler variant where input and output are expected to be positive - std::string NotZero(const std::string& code); - std::string NotZeroPositive(const std::string& code); - //Prevents operations from overflowing the desired range (tested with fp_dynamic3 autotest sample, DS2 for src1.input_prec_mod) - std::string ClampValue(const std::string& code, u32 precision); + std::string ClampValue(const std::string& code, u32 precision, bool is_half_type); /** * Returns true if the dst set is not a vector (i.e only a single component) @@ -219,9 +224,6 @@ protected: */ virtual std::string getFunction(FUNCTION) = 0; - /** returns string calling saturate function. - */ - virtual std::string saturate(const std::string &code) = 0; /** returns string calling comparison function on 2 args passed as strings. */ virtual std::string compareFunction(COMPARE, const std::string &, const std::string &) = 0; diff --git a/rpcs3/Emu/RSX/Common/GLSLCommon.h b/rpcs3/Emu/RSX/Common/GLSLCommon.h index 4cf245dd75..d5c342f6d5 100644 --- a/rpcs3/Emu/RSX/Common/GLSLCommon.h +++ b/rpcs3/Emu/RSX/Common/GLSLCommon.h @@ -660,23 +660,23 @@ namespace glsl default: abort(); case FUNCTION::FUNCTION_DP2: - return "vec4(dot($0.xy, $1.xy))"; + return "$Ty(dot($0.xy, $1.xy))"; case FUNCTION::FUNCTION_DP2A: - return "vec4(dot($0.xy, $1.xy) + $2.x)"; + return "$Ty(dot($0.xy, $1.xy) + $2.x)"; case FUNCTION::FUNCTION_DP3: - return "vec4(dot($0.xyz, $1.xyz))"; + return "$Ty(dot($0.xyz, $1.xyz))"; case FUNCTION::FUNCTION_DP4: - return "vec4(dot($0, $1))"; + return "$Ty(dot($0, $1))"; case FUNCTION::FUNCTION_DPH: - return "vec4(dot(vec4($0.xyz, 1.0), $1))"; + return "$Ty(dot(vec4($0.xyz, 1.0), $1))"; case FUNCTION::FUNCTION_SFL: - return "vec4(0., 0., 0., 0.)"; + return "$Ty(0., 0., 0., 0.)"; case FUNCTION::FUNCTION_STR: - return "vec4(1., 1., 1., 1.)"; + return "$Ty(1., 1., 1., 1.)"; case FUNCTION::FUNCTION_FRACT: return "fract($0)"; case FUNCTION::FUNCTION_REFL: - return "vec4($0 - 2.0 * (dot($0, $1)) * $1)"; + return "$Ty($0 - 2.0 * (dot($0, $1)) * $1)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D: return "TEX1D($_i, $0.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_BIAS: diff --git a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp index d7c083333d..e74675bd94 100644 --- a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp @@ -241,7 +241,8 @@ std::string VertexProgramDecompiler::Format(const std::string& code) } }, { "$cond", std::bind(std::mem_fn(&VertexProgramDecompiler::GetCond), this) }, - { "$ifbcond", std::bind(std::mem_fn(&VertexProgramDecompiler::GetOptionalBranchCond), this) } + { "$ifbcond", std::bind(std::mem_fn(&VertexProgramDecompiler::GetOptionalBranchCond), this) }, + { "$Ty", [this](){ return getFloatTypeName(4); } } }; return fmt::replace_all(code, repl_list); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index 9cbc597afa..795469023e 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -28,11 +28,6 @@ std::string D3D12FragmentDecompiler::getFunction(enum class FUNCTION f) return getFunctionImp(f); } -std::string D3D12FragmentDecompiler::saturate(const std::string & code) -{ - return "saturate(" + code + ")"; -} - std::string D3D12FragmentDecompiler::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1) { return compareFunctionImp(f, Op0, Op1); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.h b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.h index 4b4d699c1e..ab5c03ca8c 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.h @@ -11,7 +11,6 @@ protected: virtual std::string getFloatTypeName(size_t elementCount) override; virtual std::string getHalfTypeName(size_t elementCount) override; virtual std::string getFunction(enum class FUNCTION) override; - virtual std::string saturate(const std::string &code) override; virtual std::string compareFunction(enum class COMPARE, const std::string &, const std::string &) override; virtual void insertHeader(std::stringstream &OS) override; diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index cd9e63bb8a..a2bd6ad86c 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -23,11 +23,6 @@ std::string GLFragmentDecompilerThread::getFunction(FUNCTION f) return glsl::getFunctionImpl(f); } -std::string GLFragmentDecompilerThread::saturate(const std::string & code) -{ - return "clamp(" + code + ", 0., 1.)"; -} - std::string GLFragmentDecompilerThread::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1) { return glsl::compareFunctionImpl(f, Op0, Op1); @@ -110,7 +105,8 @@ void GLFragmentDecompilerThread::insertOutputs(std::stringstream & OS) { "ocol3", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r4" : "h8" }, }; - const auto reg_type = (m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "vec4" : getHalfTypeName(4); + const bool float_type = (m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) || !device_props.has_native_half_support; + const auto reg_type = float_type ? "vec4" : getHalfTypeName(4); for (int i = 0; i < std::size(table); ++i) { if (m_parr.HasParam(PF_PARAM_NONE, reg_type, table[i].second)) diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h index 9852697b9f..73ecfb193f 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h @@ -22,7 +22,6 @@ protected: virtual std::string getFloatTypeName(size_t elementCount) override; virtual std::string getHalfTypeName(size_t elementCount) override; virtual std::string getFunction(FUNCTION) override; - virtual std::string saturate(const std::string &code) override; virtual std::string compareFunction(COMPARE, const std::string&, const std::string&) override; virtual void insertHeader(std::stringstream &OS) override; diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index b1b78c054e..dcde6fda12 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -22,11 +22,6 @@ std::string VKFragmentDecompilerThread::getFunction(FUNCTION f) return glsl::getFunctionImpl(f); } -std::string VKFragmentDecompilerThread::saturate(const std::string & code) -{ - return "clamp(" + code + ", 0., 1.)"; -} - std::string VKFragmentDecompilerThread::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1) { return glsl::compareFunctionImpl(f, Op0, Op1); @@ -107,7 +102,8 @@ void VKFragmentDecompilerThread::insertOutputs(std::stringstream & OS) //NOTE: We do not skip outputs, the only possible combinations are a(0), b(0), ab(0,1), abc(0,1,2), abcd(0,1,2,3) u8 output_index = 0; - const auto reg_type = (m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "vec4" : getHalfTypeName(4); + const bool float_type = (m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) || !device_props.has_native_half_support; + const auto reg_type = float_type ? "vec4" : getHalfTypeName(4); for (int i = 0; i < std::size(table); ++i) { if (m_parr.HasParam(PF_PARAM_NONE, reg_type, table[i].second)) diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h index 839b19bf7b..1e4aecb33f 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h @@ -26,7 +26,6 @@ protected: virtual std::string getFloatTypeName(size_t elementCount) override; virtual std::string getHalfTypeName(size_t elementCount) override; virtual std::string getFunction(FUNCTION) override; - virtual std::string saturate(const std::string &code) override; virtual std::string compareFunction(COMPARE, const std::string&, const std::string&) override; virtual void insertHeader(std::stringstream &OS) override; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index d8cc447284..032553d991 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -541,7 +541,7 @@ namespace vk features2.pNext = &shader_support_info; vkGetPhysicalDeviceFeatures2(*pgpu, &features2); - m_shader_types_support.allow_float16 = false;//!!shader_support_info.shaderFloat16; + m_shader_types_support.allow_float16 = !!shader_support_info.shaderFloat16; m_shader_types_support.allow_int8 = !!shader_support_info.shaderInt8; features = features2.features; }