Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GS/HW: Improvements to rt alpha accuracy #10873

Merged
merged 1 commit into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5055,17 +5055,20 @@ __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.
blend_alpha_min = 128;
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))
{
Expand All @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
55 changes: 32 additions & 23 deletions pcsx2/GS/Renderers/HW/GSTextureCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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++)
{
Expand All @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading