GS/HW: Improve float precision of blend second pass.

This commit is contained in:
lightningterror 2024-07-19 11:45:52 +02:00
parent 47606400fa
commit 09f3a6bb73
6 changed files with 36 additions and 8 deletions

View File

@ -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); As_rgba.rgb = (float3)Alpha * (float3)(128.0f / 255.0f);
Color.rgb = (float3)127.5f; 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;
}
} }
} }

View File

@ -937,6 +937,12 @@ float As = As_rgba.a;
#endif #endif
As_rgba.rgb = vec3(Alpha) * vec3(128.0f / 255.0f); As_rgba.rgb = vec3(Alpha) * vec3(128.0f / 255.0f);
Color.rgb = vec3(127.5f); 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
#endif #endif

View File

@ -1205,6 +1205,12 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
As_rgba.rgb = vec3(Alpha) * vec3(128.0f / 255.0f); As_rgba.rgb = vec3(Alpha) * vec3(128.0f / 255.0f);
Color.rgb = vec3(127.5f); 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
#endif #endif
} }

View File

@ -172,10 +172,12 @@ enum ChannelFetch
enum class HWBlendType 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_ALPHA_DST_FACTOR = 2, // Use the dest color as blend factor, Cs is set to (Alpha - 1).
SRC_DOUBLE = 3, // Double source color. 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_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_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. BMIX1_SRC_HALF = 2, // Impossible blend will always be wrong on hw, divide Cs by 2.

View File

@ -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; 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. // 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.enable = true;
m_conf.blend_second_pass.blend_hw = static_cast<u8>(HWBlendType::SRC_ONE_DST_FACTOR); m_conf.blend_second_pass.blend_hw = static_cast<u8>(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}; 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)) 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 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. // 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.enable = true;
m_conf.blend_second_pass.blend_hw = static_cast<u8>(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}; 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)) 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 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. // 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.enable = true;
m_conf.blend_second_pass.blend_hw = static_cast<u8>(HWBlendType::SRC_ONE_DST_FACTOR); m_conf.blend_second_pass.blend_hw = static_cast<u8>(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}; 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)) 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; blend.src = GSDevice::CONST_COLOR;
// Render pass 2: Take result (Cd) from render pass 1 and double it. // 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.enable = true;
m_conf.blend_second_pass.blend_hw = static_cast<u8>(HWBlendType::SRC_ONE_DST_FACTOR); m_conf.blend_second_pass.blend_hw = static_cast<u8>(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}; 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)) 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; blend.op = GSDevice::OP_SUBTRACT;
// Render pass 2: Take result (Cd) from render pass 1 and double it. // 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.enable = true;
m_conf.blend_second_pass.blend_hw = static_cast<u8>(HWBlendType::SRC_ONE_DST_FACTOR); m_conf.blend_second_pass.blend_hw = static_cast<u8>(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}; 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) 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 1: Do Cs*(1 - Alpha).
// Render pass 2: Take result (Cd) from render pass 1 and subtract Cs*Alpha from it. // 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.enable = true;
m_conf.blend_second_pass.blend_hw = static_cast<u8>(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}; 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) if (!m_conf.blend_second_pass.enable && blend_flag & BLEND_HW1)
{ {
m_conf.ps.blend_hw = static_cast<u8>(HWBlendType::SRC_ONE_DST_FACTOR); m_conf.ps.blend_hw = static_cast<u8>(HWBlendType::SRC_ONE_DST_FACTOR1);
} }
else if (blend_flag & BLEND_HW2) 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<u8>(HWBlendType::SRC_DOUBLE); m_conf.ps.blend_hw = static_cast<u8>(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<u8>(HWBlendType::SRC_ALPHA_DST_FACTOR) ||
m_conf.ps.blend_hw == static_cast<u8>(HWBlendType::SRC_HALF_ONE_DST_FACTOR) ||
m_conf.blend_second_pass.blend_hw == static_cast<u8>(HWBlendType::SRC_ALPHA_DST_FACTOR)))
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(AFIX) / 128.0f; m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(AFIX) / 128.0f;
const GSDevice::BlendFactor src_factor_alpha = m_conf.blend_second_pass.enable ? GSDevice::CONST_ZERO : GSDevice::CONST_ONE; const GSDevice::BlendFactor src_factor_alpha = m_conf.blend_second_pass.enable ? GSDevice::CONST_ZERO : GSDevice::CONST_ONE;

View File

@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the /// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache. /// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 53; static constexpr u32 SHADER_CACHE_VERSION = 54;