GS/HW: Improvements to rt alpha accuracy

This commit is contained in:
refractionpcsx2 2024-03-01 15:35:35 +00:00
parent 244a8775dd
commit 812a3c1123
2 changed files with 45 additions and 38 deletions

View File

@ -5055,6 +5055,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
blend_alpha_max = rt->m_alpha_max;
const bool is_24_bit = (GSLocalMemory::m_psm[rt->m_TEX0.PSM].trbpp == 24);
const u32 alpha_mask = GSLocalMemory::m_psm[rt->m_TEX0.PSM].fmsk & 0xFF000000;
if (is_24_bit)
{
// C24/Z24 - alpha is 1.
@ -5062,10 +5064,11 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
blend_alpha_max = 128;
}
if (!m_channel_shuffle && !m_texture_shuffle)
if (GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & 0x8 && !m_channel_shuffle && !m_texture_shuffle)
{
const int fba_value = m_prev_env.CTXT[m_prev_env.PRIM.CTXT].FBA.FBA * 128;
if ((m_cached_ctx.FRAME.FBMSK & 0xff000000) == 0)
if ((m_cached_ctx.FRAME.FBMSK & alpha_mask) == 0)
{
if (rt->m_valid.rintersect(m_r).eq(rt->m_valid) && PrimitiveCoversWithoutGaps() && !(m_cached_ctx.TEST.DATE || m_cached_ctx.TEST.ATE || m_cached_ctx.TEST.ZTST != ZTST_ALWAYS))
{
@ -5078,22 +5081,13 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
rt->m_alpha_min = std::min(GetAlphaMinMax().min | fba_value, rt->m_alpha_min);
}
}
else if ((m_cached_ctx.FRAME.FBMSK & 0xff000000) != 0xff000000) // We can't be sure of the alpha if it's partially masked.
else if ((m_cached_ctx.FRAME.FBMSK & alpha_mask) != alpha_mask) // We can't be sure of the alpha if it's partially masked.
{
rt->m_alpha_max |= std::max(GetAlphaMinMax().max | fba_value, rt->m_alpha_max);
rt->m_alpha_min = std::min(GetAlphaMinMax().min | fba_value, rt->m_alpha_min);
}
else if (!is_24_bit)
{
// If both are zero then we probably don't know what the alpha is.
if (rt->m_alpha_max == 0 && rt->m_alpha_min == 0)
{
rt->m_alpha_max = 255;
rt->m_alpha_min = 0;
}
}
}
else if ((m_texture_shuffle && m_conf.ps.write_rg == false) || m_channel_shuffle)
else if ((m_texture_shuffle && m_conf.colormask.wa) || (m_channel_shuffle && (m_cached_ctx.FRAME.FBMSK & alpha_mask) != alpha_mask))
{
rt->m_alpha_max = 255;
rt->m_alpha_min = 0;
@ -6143,8 +6137,12 @@ bool GSRendererHW::TryTargetClear(GSTextureCache::Target* rt, GSTextureCache::Ta
const u32 c = GetConstantDirectWriteMemClearColor();
GL_INS("TryTargetClear(): RT at %x <= %08X", rt->m_TEX0.TBP0, c);
g_gs_device->ClearRenderTarget(rt->m_texture, c);
rt->m_alpha_max = c >> 24;
rt->m_alpha_min = c >> 24;
if (GSLocalMemory::m_psm[rt->m_TEX0.PSM].trbpp != 24)
{
rt->m_alpha_max = c >> 24;
rt->m_alpha_min = c >> 24;
}
if (!rt->m_32_bits_fmt)
{

View File

@ -3807,6 +3807,14 @@ bool GSTextureCache::ShuffleMove(u32 BP, u32 BW, u32 PSM, int sx, int sy, int dx
config.ps.write_rg = write_rg;
config.ps.shuffle = true;
GSRendererHW::GetInstance()->EndHLEHardwareDraw(false);
if (!write_rg)
{
// Because we don't know the new alpha value which came from green, just go full paranoid.
tgt->m_alpha_min = 0;
tgt->m_alpha_max = 255;
}
return true;
}
@ -5809,8 +5817,17 @@ GSTextureCache::Target::Target(GIFRegTEX0 TEX0, int type, const GSVector2i& unsc
m_unscaled_size = unscaled_size;
m_scale = scale;
m_texture = texture;
m_alpha_min = 0;
m_alpha_max = 0;
if ((m_TEX0.PSM & 0xf) == PSMCT24)
{
m_alpha_min = 128;
m_alpha_max = 128;
}
else
{
m_alpha_min = 0;
m_alpha_max = 0;
}
m_32_bits_fmt |= (GSLocalMemory::m_psm[TEX0.PSM].trbpp != 16);
}
@ -5901,7 +5918,10 @@ void GSTextureCache::Target::Update()
u32 ndrects = 0;
const GSOffset off(g_gs_renderer->m_mem.GetOffset(m_TEX0.TBP0, m_TEX0.TBW, m_TEX0.PSM));
const u32 bpp = GSLocalMemory::m_psm[m_TEX0.PSM].bpp;
std::pair<u8, u8> alpha_minmax = {255, 0};
bool transferring_alpha = false;
for (size_t i = 0; i < m_dirty.size(); i++)
{
@ -5914,11 +5934,13 @@ void GSTextureCache::Target::Update()
if (update_r.rempty())
continue;
transferring_alpha |= m_dirty[i].rgba.c.a;
const GSVector4i read_r = m_dirty.GetDirtyRect(i, m_TEX0, total_rect, true);
const GSVector4i t_r(read_r - t_offset);
if (mapped)
{
if (m_32_bits_fmt && (m_TEX0.PSM & 0xf) != PSMCT24)
if ((m_TEX0.PSM & 0xf) != PSMCT24 && m_dirty[i].rgba.c.a && bpp >= 16)
{
// TODO: Only read once in 32bit and copy to the mapped texture. Bit out of scope of this PR and not a huge impact.
const int pitch = VectorAlign(read_r.width() * sizeof(u32));
@ -5937,7 +5959,7 @@ void GSTextureCache::Target::Update()
const int pitch = VectorAlign(read_r.width() * sizeof(u32));
g_gs_renderer->m_mem.ReadTexture(off, read_r, s_unswizzle_buffer, pitch, TEXA);
if (m_32_bits_fmt && (m_TEX0.PSM & 0xf) != PSMCT24)
if ((m_TEX0.PSM & 0xf) != PSMCT24 && m_dirty[i].rgba.c.a && bpp >= 16)
{
std::pair<u8, u8> new_alpha_minmax = GSGetRGBA8AlphaMinMax(s_unswizzle_buffer, read_r.width(), read_r.height(), pitch);
alpha_minmax.first = std::min(alpha_minmax.first, new_alpha_minmax.first);
@ -5994,30 +6016,17 @@ void GSTextureCache::Target::Update()
g_gs_device->DrawMultiStretchRects(drects, ndrects, m_texture, shader);
}
if ((m_TEX0.PSM & 0xf) == PSMCT24)
if (transferring_alpha && bpp >= 16)
{
m_alpha_min = 128;
m_alpha_max = 128;
}
else
{
if (m_32_bits_fmt)
if (m_dirty.size() != 1 || !total_rect.eq(m_valid))
{
if (!total_rect.eq(m_valid))
{
m_alpha_min = std::min(static_cast<int>(alpha_minmax.first), m_alpha_min);
m_alpha_max = std::max(static_cast<int>(alpha_minmax.second), m_alpha_max);
}
else
{
m_alpha_min = alpha_minmax.first;
m_alpha_max = alpha_minmax.second;
}
m_alpha_min = std::min(static_cast<int>(alpha_minmax.first), m_alpha_min);
m_alpha_max = std::max(static_cast<int>(alpha_minmax.second), m_alpha_max);
}
else
{
m_alpha_min = 0;
m_alpha_max = 128;
m_alpha_min = alpha_minmax.first;
m_alpha_max = alpha_minmax.second;
}
}
g_gs_device->Recycle(t);