mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Further adjust how we handle RT alpha in blending.
Check whenever RT alpha min is equal or higher than RT alpha max / 2. This will allow us to use the min value as a more accurate option than the actual value since it will be less accurate.
This commit is contained in:
parent
d49323c7c4
commit
1a79e23b12
|
@ -3505,6 +3505,9 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
|
||||||
GL_INS("Draw AlphaMinMax: %d-%d, RT AlphaMinMax: %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max, rt_alpha_min, rt_alpha_max);
|
GL_INS("Draw AlphaMinMax: %d-%d, RT AlphaMinMax: %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max, rt_alpha_min, rt_alpha_max);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool blend_ad_improved = false;
|
||||||
|
const bool alpha_mask = (m_cached_ctx.FRAME.FBMSK & 0xFF000000) == 0xFF000000;
|
||||||
|
|
||||||
// When AA1 is enabled and Alpha Blending is disabled, alpha blending done with coverage instead of alpha.
|
// When AA1 is enabled and Alpha Blending is disabled, alpha blending done with coverage instead of alpha.
|
||||||
// We use a COV value of 128 (full coverage) in triangles (except the edge geometry, which we can't do easily).
|
// We use a COV value of 128 (full coverage) in triangles (except the edge geometry, which we can't do easily).
|
||||||
if (IsCoverageAlpha())
|
if (IsCoverageAlpha())
|
||||||
|
@ -3526,6 +3529,13 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
|
||||||
AFIX = 128;
|
AFIX = 128;
|
||||||
m_conf.ps.blend_c = 2;
|
m_conf.ps.blend_c = 2;
|
||||||
}
|
}
|
||||||
|
// Check whenever we can use rt alpha min as the new alpha value, will be more accurate.
|
||||||
|
else if (!alpha_mask && (rt_alpha_min >= (rt_alpha_max / 2)))
|
||||||
|
{
|
||||||
|
AFIX = rt_alpha_min;
|
||||||
|
m_conf.ps.blend_c = 2;
|
||||||
|
blend_ad_improved = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get alpha value
|
// Get alpha value
|
||||||
|
@ -3582,7 +3592,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
|
||||||
// Replace Ad with As, blend flags will be used from As since we are chaging the blend_index value.
|
// Replace Ad with As, blend flags will be used from As since we are chaging the blend_index value.
|
||||||
// Must be done before index calculation, after blending equation optimizations
|
// Must be done before index calculation, after blending equation optimizations
|
||||||
const bool blend_ad = m_conf.ps.blend_c == 1;
|
const bool blend_ad = m_conf.ps.blend_c == 1;
|
||||||
bool blend_ad_alpha_masked = blend_ad && (m_cached_ctx.FRAME.FBMSK & 0xFF000000) == 0xFF000000;
|
bool blend_ad_alpha_masked = blend_ad && alpha_mask;
|
||||||
if (((GSConfig.AccurateBlendingUnit >= AccBlendLevel::Basic) || (COLCLAMP.CLAMP == 0))
|
if (((GSConfig.AccurateBlendingUnit >= AccBlendLevel::Basic) || (COLCLAMP.CLAMP == 0))
|
||||||
&& g_gs_device->Features().texture_barrier && blend_ad_alpha_masked)
|
&& g_gs_device->Features().texture_barrier && blend_ad_alpha_masked)
|
||||||
m_conf.ps.blend_c = 0;
|
m_conf.ps.blend_c = 0;
|
||||||
|
@ -3629,7 +3639,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
|
||||||
// BLEND_HW_CLR1 with Ad, BLEND_HW_CLR3 Cs > 0.5f will require sw blend.
|
// BLEND_HW_CLR1 with Ad, BLEND_HW_CLR3 Cs > 0.5f will require sw blend.
|
||||||
// BLEND_HW_CLR1 with As/F and BLEND_HW_CLR2 can be done in hw.
|
// BLEND_HW_CLR1 with As/F and BLEND_HW_CLR2 can be done in hw.
|
||||||
const bool clr_blend = !!(blend_flag & (BLEND_HW_CLR1 | BLEND_HW_CLR2 | BLEND_HW_CLR3));
|
const bool clr_blend = !!(blend_flag & (BLEND_HW_CLR1 | BLEND_HW_CLR2 | BLEND_HW_CLR3));
|
||||||
bool clr_blend1_2 = (blend_flag & (BLEND_HW_CLR1 | BLEND_HW_CLR2)) && (m_conf.ps.blend_c != 1) // Make sure it isn't an Ad case
|
bool clr_blend1_2 = (blend_flag & (BLEND_HW_CLR1 | BLEND_HW_CLR2)) && (m_conf.ps.blend_c != 1) && !blend_ad_improved // Make sure it isn't an Ad case
|
||||||
&& !m_draw_env->PABE.PABE // No PABE as it will require sw blending.
|
&& !m_draw_env->PABE.PABE // No PABE as it will require sw blending.
|
||||||
&& (COLCLAMP.CLAMP) // Let's add a colclamp check too, hw blend will clamp to 0-1.
|
&& (COLCLAMP.CLAMP) // Let's add a colclamp check too, hw blend will clamp to 0-1.
|
||||||
&& !(one_barrier || m_conf.require_full_barrier); // Also don't run if there are barriers present.
|
&& !(one_barrier || m_conf.require_full_barrier); // Also don't run if there are barriers present.
|
||||||
|
@ -3642,17 +3652,17 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
|
||||||
// Condition 1: Require full sw blend for full barrier.
|
// Condition 1: Require full sw blend for full barrier.
|
||||||
// Condition 2: One barrier is already enabled, prims don't overlap so let's use sw blend instead.
|
// Condition 2: One barrier is already enabled, prims don't overlap so let's use sw blend instead.
|
||||||
const bool prefer_sw_blend = m_conf.require_full_barrier || (one_barrier && m_prim_overlap == PRIM_OVERLAP_NO);
|
const bool prefer_sw_blend = m_conf.require_full_barrier || (one_barrier && m_prim_overlap == PRIM_OVERLAP_NO);
|
||||||
|
|
||||||
// SW Blend is (nearly) free. Let's use it.
|
|
||||||
const bool no_prim_overlap = (m_prim_overlap == PRIM_OVERLAP_NO);
|
const bool no_prim_overlap = (m_prim_overlap == PRIM_OVERLAP_NO);
|
||||||
const bool impossible_or_free_blend = (blend_flag & BLEND_A_MAX) // Impossible blending
|
const bool free_blend = blend_non_recursive // Free sw blending, doesn't require barriers or reading fb
|
||||||
|| blend_non_recursive // Free sw blending, doesn't require barriers or reading fb
|
|| accumulation_blend; // Mix of hw/sw blending
|
||||||
|| accumulation_blend // Mix of hw/sw blending
|
const bool blend_requires_barrier = (blend_flag & BLEND_A_MAX) // Impossible blending
|
||||||
|| (m_conf.require_full_barrier) // Another effect (for example fbmask) already requires a full barrier
|
|| (m_conf.require_full_barrier) // Another effect (for example fbmask) already requires a full barrier
|
||||||
// Blend can be done in a single draw, and we already need a barrier
|
// Blend can be done in a single draw, and we already need a barrier
|
||||||
// On fbfetch, one barrier is like full barrier
|
// On fbfetch, one barrier is like full barrier
|
||||||
|| (one_barrier && (no_prim_overlap || features.framebuffer_fetch))
|
|| (one_barrier && (no_prim_overlap || features.framebuffer_fetch))
|
||||||
|| ((alpha_c2_high_one || alpha_c0_high_max_one) && no_prim_overlap);
|
|| ((alpha_c2_high_one || alpha_c0_high_max_one) && no_prim_overlap)
|
||||||
|
// Ad blends are completely wrong without sw blend (Ad is 0.5 not 1 for 128). We can spare a barrier for it.
|
||||||
|
|| ((blend_ad || blend_ad_improved) && no_prim_overlap);
|
||||||
|
|
||||||
switch (GSConfig.AccurateBlendingUnit)
|
switch (GSConfig.AccurateBlendingUnit)
|
||||||
{
|
{
|
||||||
|
@ -3679,12 +3689,19 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
|
||||||
color_dest_blend &= !prefer_sw_blend;
|
color_dest_blend &= !prefer_sw_blend;
|
||||||
// If prims don't overlap prefer full sw blend on blend_ad_alpha_masked cases.
|
// If prims don't overlap prefer full sw blend on blend_ad_alpha_masked cases.
|
||||||
accumulation_blend &= !(prefer_sw_blend || (blend_ad_alpha_masked && m_prim_overlap == PRIM_OVERLAP_NO));
|
accumulation_blend &= !(prefer_sw_blend || (blend_ad_alpha_masked && m_prim_overlap == PRIM_OVERLAP_NO));
|
||||||
sw_blending |= impossible_or_free_blend;
|
// Enable sw blending for barriers.
|
||||||
// Ad blends are completely wrong without sw blend (Ad is 0.5 not 1 for 128). We can spare a barrier for it.
|
sw_blending |= blend_requires_barrier;
|
||||||
sw_blending |= blend_ad && no_prim_overlap;
|
|
||||||
// Try to do hw blend for clr2 case.
|
// Try to do hw blend for clr2 case.
|
||||||
sw_blending &= !clr_blend1_2;
|
sw_blending &= !clr_blend1_2;
|
||||||
// Do not run BLEND MIX if sw blending is already present, it's less accurate
|
// blend_ad_improved should only run if no other barrier blend is enabled, otherwise restore bit values.
|
||||||
|
if (blend_ad_improved && (sw_blending || prefer_sw_blend))
|
||||||
|
{
|
||||||
|
AFIX = 0;
|
||||||
|
m_conf.ps.blend_c = 1;
|
||||||
|
}
|
||||||
|
// Enable sw blending for free blending, should be done after blend_ad_improved check.
|
||||||
|
sw_blending |= free_blend;
|
||||||
|
// Do not run BLEND MIX if sw blending is already present, it's less accurate.
|
||||||
blend_mix &= !sw_blending;
|
blend_mix &= !sw_blending;
|
||||||
sw_blending |= blend_mix;
|
sw_blending |= blend_mix;
|
||||||
// Disable dithering on blend mix.
|
// Disable dithering on blend mix.
|
||||||
|
@ -3726,10 +3743,19 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
|
||||||
// Disable accumulation blend when there is fbmask with no overlap, will be faster.
|
// Disable accumulation blend when there is fbmask with no overlap, will be faster.
|
||||||
color_dest_blend &= !fbmask_no_overlap;
|
color_dest_blend &= !fbmask_no_overlap;
|
||||||
accumulation_blend &= !fbmask_no_overlap;
|
accumulation_blend &= !fbmask_no_overlap;
|
||||||
sw_blending |= accumulation_blend || blend_non_recursive || fbmask_no_overlap;
|
// Blending requires reading the framebuffer when there's no overlap.
|
||||||
|
sw_blending |= fbmask_no_overlap;
|
||||||
// Try to do hw blend for clr2 case.
|
// Try to do hw blend for clr2 case.
|
||||||
sw_blending &= !clr_blend1_2;
|
sw_blending &= !clr_blend1_2;
|
||||||
// Do not run BLEND MIX if sw blending is already present, it's less accurate
|
// blend_ad_improved should only run if no other barrier blend is enabled, otherwise restore bit values.
|
||||||
|
if (blend_ad_improved && (sw_blending || fbmask_no_overlap))
|
||||||
|
{
|
||||||
|
AFIX = 0;
|
||||||
|
m_conf.ps.blend_c = 1;
|
||||||
|
}
|
||||||
|
// Enable sw blending for free blending, should be done after blend_ad_improved check.
|
||||||
|
sw_blending |= accumulation_blend || blend_non_recursive;
|
||||||
|
// Do not run BLEND MIX if sw blending is already present, it's less accurate.
|
||||||
blend_mix &= !sw_blending;
|
blend_mix &= !sw_blending;
|
||||||
sw_blending |= blend_mix;
|
sw_blending |= blend_mix;
|
||||||
// Disable dithering on blend mix.
|
// Disable dithering on blend mix.
|
||||||
|
|
Loading…
Reference in New Issue