mirror of https://github.com/PCSX2/pcsx2.git
GS-hw: Adjust how we handle specific blend mix cases.
Replace Cs*As + Cd*(1 - As) with Cs*As - Cd*(As - 1). Replace Cs*F + Cd*(1 - F) with Cs*F - Cd*(F - 1). As - 1 or F - 1 subtraction is only done for the dual source output (hw blending part) since we are changing the equation. Af will be replaced with As in shader and send it to dual source output. Also check if A*Alpha in the shader overflows, if it does then adjust the alpha that is sent for HW blending further to compensate.
This commit is contained in:
parent
1478819258
commit
6b48cf574d
|
@ -750,7 +750,7 @@ void ps_color_clamp_wrap(inout float3 C)
|
|||
}
|
||||
}
|
||||
|
||||
void ps_blend(inout float4 Color, float As, float2 pos_xy)
|
||||
void ps_blend(inout float4 Color, inout float As, float2 pos_xy)
|
||||
{
|
||||
if (SW_BLEND)
|
||||
{
|
||||
|
@ -775,10 +775,26 @@ void ps_blend(inout float4 Color, float As, float2 pos_xy)
|
|||
float3 D = (PS_BLEND_D == 0) ? Cs : ((PS_BLEND_D == 1) ? Cd : (float3)0.0f);
|
||||
|
||||
// As/Af clamp alpha for Blend mix
|
||||
if (PS_BLEND_MIX)
|
||||
C = min(C, (float)1.0f);
|
||||
// We shouldn't clamp blend mix with clr1 as we want alpha higher
|
||||
if (PS_BLEND_MIX && PS_CLR_HW != 1)
|
||||
C = min(C, 1.0f);
|
||||
|
||||
Color.rgb = (PS_BLEND_A == PS_BLEND_B) ? D : trunc(((A - B) * C) + D);
|
||||
|
||||
if (PS_CLR_HW == 1)
|
||||
{
|
||||
// Replace Af with As so we can do proper compensation for Alpha.
|
||||
if (PS_BLEND_C == 2)
|
||||
As = Af;
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
float min_color = min(min(Color.r, Color.g), Color.b);
|
||||
float alpha_compensate = max(1.0f, min_color / 255.0f);
|
||||
As -= alpha_compensate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -689,7 +689,7 @@ void ps_color_clamp_wrap(inout vec3 C)
|
|||
#endif
|
||||
}
|
||||
|
||||
void ps_blend(inout vec4 Color, float As)
|
||||
void ps_blend(inout vec4 Color, inout float As)
|
||||
{
|
||||
#if SW_BLEND
|
||||
|
||||
|
@ -754,8 +754,9 @@ void ps_blend(inout vec4 Color, float As)
|
|||
#endif
|
||||
|
||||
// As/Af clamp alpha for Blend mix
|
||||
#if PS_BLEND_MIX
|
||||
C = min(C, float(1.0f));
|
||||
// We shouldn't clamp blend mix with clr1 as we want alpha higher
|
||||
#if PS_BLEND_MIX && PS_CLR_HW != 1
|
||||
C = min(C, 1.0f);
|
||||
#endif
|
||||
|
||||
#if PS_BLEND_A == PS_BLEND_B
|
||||
|
@ -764,6 +765,21 @@ void ps_blend(inout vec4 Color, float As)
|
|||
Color.rgb = trunc((A - B) * C + D);
|
||||
#endif
|
||||
|
||||
#if PS_CLR_HW == 1
|
||||
// Replace Af with As so we can do proper compensation for Alpha.
|
||||
#if PS_BLEND_C == 2
|
||||
As = Af;
|
||||
#endif
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
float min_color = min(min(Color.r, Color.g), Color.b);
|
||||
float alpha_compensate = max(1.0f, min_color / 255.0f);
|
||||
As -= alpha_compensate;
|
||||
#endif
|
||||
|
||||
#else
|
||||
// Needed for Cd * (As/Ad/F + 1) blending modes
|
||||
#if PS_CLR_HW == 1 || PS_CLR_HW == 5
|
||||
|
|
|
@ -990,7 +990,7 @@ void ps_color_clamp_wrap(inout vec3 C)
|
|||
#endif
|
||||
}
|
||||
|
||||
void ps_blend(inout vec4 Color, float As)
|
||||
void ps_blend(inout vec4 Color, inout float As)
|
||||
{
|
||||
#if SW_BLEND
|
||||
|
||||
|
@ -1053,7 +1053,8 @@ void ps_blend(inout vec4 Color, float As)
|
|||
#endif
|
||||
|
||||
// As/Af clamp alpha for Blend mix
|
||||
#if PS_BLEND_MIX
|
||||
// We shouldn't clamp blend mix with clr1 as we want alpha higher
|
||||
#if PS_BLEND_MIX && PS_CLR_HW != 1
|
||||
C = min(C, 1.0f);
|
||||
#endif
|
||||
|
||||
|
@ -1063,6 +1064,21 @@ void ps_blend(inout vec4 Color, float As)
|
|||
Color.rgb = trunc((A - B) * C + D);
|
||||
#endif
|
||||
|
||||
#if PS_CLR_HW == 1
|
||||
// Replace Af with As so we can do proper compensation for Alpha.
|
||||
#if PS_BLEND_C == 2
|
||||
As = Af;
|
||||
#endif
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
float min_color = min(min(Color.r, Color.g), Color.b);
|
||||
float alpha_compensate = max(1.0f, min_color / 255.0f);
|
||||
As -= alpha_compensate;
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if PS_CLR_HW == 1 || PS_CLR_HW == 5
|
||||
// Needed for Cd * (As/Ad/F + 1) blending modes
|
||||
|
|
|
@ -2359,6 +2359,7 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
|||
// Get alpha value
|
||||
const bool alpha_c0_zero = (m_conf.ps.blend_c == 0 && GetAlphaMinMax().max == 0) && !IsCoverageAlpha();
|
||||
const bool alpha_c0_one = (m_conf.ps.blend_c == 0 && (GetAlphaMinMax().min == 128) && (GetAlphaMinMax().max == 128)) || IsCoverageAlpha();
|
||||
const bool alpha_c0_high_min_one = (m_conf.ps.blend_c == 0 && GetAlphaMinMax().min > 128) && !IsCoverageAlpha();
|
||||
const bool alpha_c0_high_max_one = (m_conf.ps.blend_c == 0 && GetAlphaMinMax().max > 128) && !IsCoverageAlpha();
|
||||
const bool alpha_c2_zero = (m_conf.ps.blend_c == 2 && ALPHA.FIX == 0u);
|
||||
const bool alpha_c2_one = (m_conf.ps.blend_c == 2 && ALPHA.FIX == 128u);
|
||||
|
@ -2713,11 +2714,20 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
|||
m_conf.blend = {true, GSDevice::CONST_ONE, blend.dst, blend.op, m_conf.ps.blend_c == 2, ALPHA.FIX};
|
||||
m_conf.ps.blend_mix = 1;
|
||||
|
||||
// Elide DSB colour output if not used by dest.
|
||||
m_conf.ps.no_color1 |= !GSDevice::IsDualSourceBlendFactor(blend.dst);
|
||||
|
||||
if (blend_mix1)
|
||||
{
|
||||
if (m_conf.ps.blend_b == m_conf.ps.blend_d && (alpha_c0_high_min_one || alpha_c2_high_one))
|
||||
{
|
||||
// Replace Cs*As + Cd*(1 - As) with Cs*As - Cd*(As - 1).
|
||||
// Replace Cs*F + Cd*(1 - F) with Cs*F - Cd*(F - 1).
|
||||
// As - 1 or F - 1 subtraction is only done for the dual source output (hw blending part) since we are changing the equation.
|
||||
// Af will be replaced with As in shader and send it to dual source output.
|
||||
m_conf.blend = {true, GSDevice::CONST_ONE, GSDevice::SRC1_ALPHA, GSDevice::OP_SUBTRACT, false, 0};
|
||||
// clr_hw 1 will disable alpha clamp, we can reuse the old bits.
|
||||
m_conf.ps.clr_hw = 1;
|
||||
//m_conf.ps.blend_mix = 0;
|
||||
}
|
||||
|
||||
m_conf.ps.blend_a = 0;
|
||||
m_conf.ps.blend_b = 2;
|
||||
m_conf.ps.blend_d = 2;
|
||||
|
@ -2742,6 +2752,9 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
|||
// Swap Ad with As for hw blend
|
||||
m_conf.ps.clr_hw = 6;
|
||||
}
|
||||
|
||||
// Elide DSB colour output if not used by dest.
|
||||
m_conf.ps.no_color1 |= !GSDevice::IsDualSourceBlendFactor(blend.dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -721,7 +721,7 @@ struct PSMain
|
|||
return selector == 0 ? zero : selector == 1 ? one : two;
|
||||
}
|
||||
|
||||
void ps_blend(thread float4& Color, float As)
|
||||
void ps_blend(thread float4& Color, thread float& As)
|
||||
{
|
||||
if (SW_BLEND)
|
||||
{
|
||||
|
@ -729,7 +729,7 @@ struct PSMain
|
|||
if (PS_PABE)
|
||||
{
|
||||
// No blending so early exit
|
||||
if (As < 1.0f)
|
||||
if (As < 1.f)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -743,13 +743,30 @@ struct PSMain
|
|||
float C = pick(PS_BLEND_C, As, Ad, cb.alpha_fix);
|
||||
float3 D = pick(PS_BLEND_D, Cs, Cd, float3(0.f));
|
||||
|
||||
if (PS_BLEND_MIX)
|
||||
// As/Af clamp alpha for Blend mix
|
||||
// We shouldn't clamp blend mix with clr1 as we want alpha higher
|
||||
if (PS_BLEND_MIX && PS_CLR_HW != 1)
|
||||
C = min(C, 1.f);
|
||||
|
||||
if (PS_BLEND_A == PS_BLEND_B)
|
||||
Color.rgb = D;
|
||||
else
|
||||
Color.rgb = trunc((A - B) * C + D);
|
||||
|
||||
if (PS_CLR_HW == 1)
|
||||
{
|
||||
// Replace Af with As so we can do proper compensation for Alpha.
|
||||
if (PS_BLEND_C == 2)
|
||||
As = cb.alpha_fix;
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
float min_color = min(min(Color.r, Color.g), Color.b);
|
||||
float alpha_compensate = max(1.f, min_color / 255.f);
|
||||
As -= alpha_compensate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue