From 09f3a6bb736dc09eb9599a02afd941ab9131aebf Mon Sep 17 00:00:00 2001 From: lightningterror <18107717+lightningterror@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:45:52 +0200 Subject: [PATCH] GS/HW: Improve float precision of blend second pass. --- bin/resources/shaders/dx11/tfx.fx | 10 ++++++++++ bin/resources/shaders/opengl/tfx_fs.glsl | 6 ++++++ bin/resources/shaders/vulkan/tfx.glsl | 6 ++++++ pcsx2/GS/Renderers/Common/GSDevice.h | 4 +++- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 16 ++++++++++------ pcsx2/ShaderCacheVersion.h | 2 +- 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/bin/resources/shaders/dx11/tfx.fx b/bin/resources/shaders/dx11/tfx.fx index 012507b884..557ea539ac 100644 --- a/bin/resources/shaders/dx11/tfx.fx +++ b/bin/resources/shaders/dx11/tfx.fx @@ -982,6 +982,16 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy) As_rgba.rgb = (float3)Alpha * (float3)(128.0f / 255.0f); Color.rgb = (float3)127.5f; } + else if (PS_BLEND_HW == 5) + { + // Needed for Cs*Ad, Cs*Ad + Cd, Cd - Cs*Ad. + Color.rgb = max(Color.rgb - (Color.rgb / (float3)128.0f), (float3)0.0f); + } + else if (PS_BLEND_HW == 6) + { + // Needed for Cd*Ad - Cs*Ad, Cs*Ad - Cd*Ad. + Color.rgb = (float3)253.0f; + } } } diff --git a/bin/resources/shaders/opengl/tfx_fs.glsl b/bin/resources/shaders/opengl/tfx_fs.glsl index e8042a54b5..f93e21402d 100644 --- a/bin/resources/shaders/opengl/tfx_fs.glsl +++ b/bin/resources/shaders/opengl/tfx_fs.glsl @@ -937,6 +937,12 @@ float As = As_rgba.a; #endif As_rgba.rgb = vec3(Alpha) * vec3(128.0f / 255.0f); Color.rgb = vec3(127.5f); +#elif PS_BLEND_HW == 5 + // Needed for Cs*Ad, Cs*Ad + Cd, Cd - Cs*Ad. + Color.rgb = max(Color.rgb - (Color.rgb / vec3(128.0f)), vec3(0.0f)); +#elif PS_BLEND_HW == 6 + // Needed for Cd*Ad - Cs*Ad, Cs*Ad - Cd*Ad. + Color.rgb = vec3(253.0f); #endif #endif diff --git a/bin/resources/shaders/vulkan/tfx.glsl b/bin/resources/shaders/vulkan/tfx.glsl index db99c79b95..be5985eb25 100644 --- a/bin/resources/shaders/vulkan/tfx.glsl +++ b/bin/resources/shaders/vulkan/tfx.glsl @@ -1205,6 +1205,12 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba) As_rgba.rgb = vec3(Alpha) * vec3(128.0f / 255.0f); Color.rgb = vec3(127.5f); + #elif PS_BLEND_HW == 5 + // Needed for Cs*Ad, Cs*Ad + Cd, Cd - Cs*Ad. + Color.rgb = max(Color.rgb - (Color.rgb / vec3(128.0f)), vec3(0.0f)); + #elif PS_BLEND_HW == 6 + // Needed for Cd*Ad - Cs*Ad, Cs*Ad - Cd*Ad. + Color.rgb = vec3(253.0f); #endif #endif } diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index d60ea6c688..ffd6e81bd8 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -172,10 +172,12 @@ enum ChannelFetch enum class HWBlendType { - SRC_ONE_DST_FACTOR = 1, // Use the dest color as blend factor, Cs is set to 1. + SRC_ONE_DST_FACTOR1 = 1, // Use the dest color as blend factor, Cs is set to 1. SRC_ALPHA_DST_FACTOR = 2, // Use the dest color as blend factor, Cs is set to (Alpha - 1). SRC_DOUBLE = 3, // Double source color. SRC_HALF_ONE_DST_FACTOR = 4, // Use the dest color as blend factor, Cs is set to 0.5, additionally divide As or Af by 2. + SRC_FLOAT_PRECISION = 5, // Adjust Cs by a small amount to compensate for float precision loss. + SRC_ONE_DST_FACTOR2 = 6, // Use the dest color as blend factor, Cs is set to 0.9921875 instead of 1 for float precision loss. BMIX1_ALPHA_HIGH_ONE = 1, // Blend formula is replaced when alpha is higher than 1. BMIX1_SRC_HALF = 2, // Impossible blend will always be wrong on hw, divide Cs by 2. diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index e9f852b7dd..e2df9886af 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -4643,7 +4643,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo blend.dst = (m_conf.ps.blend_c == 1) ? GSDevice::DST_ALPHA : GSDevice::SRC1_COLOR; // Render pass 2: Take result (Cd) from render pass 1 and double it. m_conf.blend_second_pass.enable = true; - m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR); + m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR1); m_conf.blend_second_pass.blend = {true, blend_second_pass.src, GSDevice::CONST_ONE, blend_second_pass.op, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0}; } else if (alpha_c1_high_no_rta_correct && (blend_flag & BLEND_HW3)) @@ -4653,6 +4653,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo // Render pass 1: Do Cs*Alpha, Cs*Alpha + Cd or Cd - Cs*Alpha on first pass. // Render pass 2: Take result (Cd) from render pass 1 and either add or rev subtract Cs*Alpha based on the blend operation. m_conf.blend_second_pass.enable = true; + m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_FLOAT_PRECISION); m_conf.blend_second_pass.blend = {true, blend_second_pass.src, GSDevice::CONST_ONE, blend_second_pass.op, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0}; } else if ((alpha_c0_high_max_one || alpha_c2_high_one) && (blend_flag & BLEND_HW4)) @@ -4679,7 +4680,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo // Render pass 1: Do (Cd - Cs)*Alpha, (Cs - Cd)*Alpha or Cd*Alpha on first pass. // Render pass 2: Take result (Cd) from render pass 1 and double it. m_conf.blend_second_pass.enable = true; - m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR); + m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR2); m_conf.blend_second_pass.blend = {true, GSDevice::DST_COLOR, GSDevice::CONST_ONE, GSDevice::OP_ADD, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0}; } else if (alpha_c1_high_no_rta_correct && (blend_flag & BLEND_HW6)) @@ -4692,7 +4693,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo blend.src = GSDevice::CONST_COLOR; // Render pass 2: Take result (Cd) from render pass 1 and double it. m_conf.blend_second_pass.enable = true; - m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR); + m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR1); m_conf.blend_second_pass.blend = {true, GSDevice::DST_COLOR, GSDevice::CONST_ONE, GSDevice::OP_ADD, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0}; } else if (alpha_c1_high_no_rta_correct && (blend_flag & BLEND_HW7)) @@ -4706,7 +4707,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo blend.op = GSDevice::OP_SUBTRACT; // Render pass 2: Take result (Cd) from render pass 1 and double it. m_conf.blend_second_pass.enable = true; - m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR); + m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR1); m_conf.blend_second_pass.blend = {true, GSDevice::DST_COLOR, GSDevice::CONST_ONE, GSDevice::OP_ADD, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0}; } else if (blend_flag & BLEND_HW8) @@ -4726,13 +4727,14 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo // Render pass 1: Do Cs*(1 - Alpha). // Render pass 2: Take result (Cd) from render pass 1 and subtract Cs*Alpha from it. m_conf.blend_second_pass.enable = true; + m_conf.blend_second_pass.blend_hw = static_cast(HWBlendType::SRC_FLOAT_PRECISION); m_conf.blend_second_pass.blend = {true, GSDevice::DST_ALPHA, GSDevice::CONST_ONE, GSDevice::OP_REV_SUBTRACT, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0}; } } if (!m_conf.blend_second_pass.enable && blend_flag & BLEND_HW1) { - m_conf.ps.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR); + m_conf.ps.blend_hw = static_cast(HWBlendType::SRC_ONE_DST_FACTOR1); } else if (blend_flag & BLEND_HW2) { @@ -4743,7 +4745,9 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo m_conf.ps.blend_hw = static_cast(HWBlendType::SRC_DOUBLE); } - if (m_conf.ps.blend_c == 2 && (m_conf.ps.blend_hw == 2 || m_conf.ps.blend_hw == 4 || m_conf.blend_second_pass.blend_hw == 2)) + if (m_conf.ps.blend_c == 2 && (m_conf.ps.blend_hw == static_cast(HWBlendType::SRC_ALPHA_DST_FACTOR) || + m_conf.ps.blend_hw == static_cast(HWBlendType::SRC_HALF_ONE_DST_FACTOR) || + m_conf.blend_second_pass.blend_hw == static_cast(HWBlendType::SRC_ALPHA_DST_FACTOR))) m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast(AFIX) / 128.0f; const GSDevice::BlendFactor src_factor_alpha = m_conf.blend_second_pass.enable ? GSDevice::CONST_ZERO : GSDevice::CONST_ONE; diff --git a/pcsx2/ShaderCacheVersion.h b/pcsx2/ShaderCacheVersion.h index 9f743001e5..1aba91d825 100644 --- a/pcsx2/ShaderCacheVersion.h +++ b/pcsx2/ShaderCacheVersion.h @@ -3,4 +3,4 @@ /// Version number for GS and other shaders. Increment whenever any of the contents of the /// shaders change, to invalidate the cache. -static constexpr u32 SHADER_CACHE_VERSION = 53; +static constexpr u32 SHADER_CACHE_VERSION = 54;