GS: Correct depth trace for sprites + optimize HW depth selection

This commit is contained in:
refractionpcsx2 2024-06-13 22:40:04 +01:00
parent 6aa57b7e87
commit 8917c5dbc9
2 changed files with 60 additions and 14 deletions

View File

@ -132,13 +132,15 @@ void GSVertexTrace::CorrectDepthTrace(const void* vertex, int count)
const GSVertex* RESTRICT v = (GSVertex*)vertex;
u32 z = v[0].XYZ.Z;
// ought to check only 1/2 for sprite
const int sprite_step = (m_primclass == GS_SPRITE_CLASS) ? 1 : 0;
u32 z = v[sprite_step].XYZ.Z;
if (z & 1)
{
// Check that first bit is always 1
for (int i = 0; i < count; i++)
for (int i = sprite_step; i < count; i += (sprite_step + 1))
{
z &= v[i].XYZ.Z;
}
@ -146,13 +148,13 @@ void GSVertexTrace::CorrectDepthTrace(const void* vertex, int count)
else
{
// Check that first bit is always 0
for (int i = 0; i < count; i++)
for (int i = sprite_step; i < count; i += (sprite_step + 1))
{
z |= v[i].XYZ.Z;
}
}
if (z == v[0].XYZ.Z)
if (z == v[sprite_step].XYZ.Z)
{
m_eq.z = 1;
}

View File

@ -1397,10 +1397,11 @@ bool GSRendererHW::IsRTWritten()
bool GSRendererHW::IsDepthAlwaysPassing()
{
const u32 max_z = (0xFFFFFFFF >> (GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].fmt * 8));
const int check_index = m_vt.m_primclass == GS_SPRITE_CLASS ? 1 : 0;
// Depth is always pass/fail (no read) and write are discarded.
return (!m_cached_ctx.TEST.ZTE || m_cached_ctx.TEST.ZTST <= ZTST_ALWAYS) ||
// Depth test will always pass
(m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[0].XYZ.Z, max_z) == max_z);
(m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[check_index].XYZ.Z, max_z) == max_z);
}
bool GSRendererHW::IsUsingCsInBlend()
@ -2708,15 +2709,58 @@ void GSRendererHW::Draw()
ds = g_texture_cache->LookupTarget(ZBUF_TEX0, t_size, target_scale, GSTextureCache::DepthStencil,
m_cached_ctx.DepthWrite(), 0, false, force_preload, preserve_depth, preserve_depth, unclamped_draw_rect, IsPossibleChannelShuffle(), is_possible_mem_clear && ZBUF_TEX0.TBP0 != m_cached_ctx.FRAME.Block());
if (!ds)
{
ds = g_texture_cache->CreateTarget(ZBUF_TEX0, t_size, GetValidSize(src), target_scale, GSTextureCache::DepthStencil,
true, 0, false, force_preload, preserve_depth, m_r, src);
if (!ds) [[unlikely]]
ds = g_texture_cache->CreateTarget(ZBUF_TEX0, t_size, GetValidSize(src), target_scale, GSTextureCache::DepthStencil,
true, 0, false, force_preload, preserve_depth, m_r, src);
if (!ds) [[unlikely]]
{
GL_INS("ERROR: Failed to create ZBUF target, skipping.");
CleanupDraw(true);
return;
}
}
else
{
// If it failed to check depth test earlier, we can now check the top bits from the alpha to get a bit more accurate picture.
if (((zm && m_cached_ctx.TEST.ZTST > ZTST_ALWAYS) || (m_vt.m_eq.z && m_cached_ctx.TEST.ZTST == ZTST_GEQUAL)) && GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].trbpp == 32)
{
GL_INS("ERROR: Failed to create ZBUF target, skipping.");
CleanupDraw(true);
return;
if (ds->m_alpha_max != 0)
{
const u32 max_z = (static_cast<u64>(ds->m_alpha_max + 1) << 24) - 1;
switch (m_cached_ctx.TEST.ZTST)
{
case ZTST_GEQUAL:
// Every Z value will pass
if (max_z <= m_vt.m_min.p.z)
{
m_cached_ctx.TEST.ZTST = ZTST_ALWAYS;
if (zm)
{
ds = nullptr;
no_ds = true;
}
}
break;
case ZTST_GREATER:
// Every Z value will pass
if (max_z < m_vt.m_min.p.z)
{
m_cached_ctx.TEST.ZTST = ZTST_ALWAYS;
if (zm)
{
ds = nullptr;
no_ds = true;
}
}
break;
default:
break;
}
}
}
}
}
@ -5608,8 +5652,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
// Not gonna spend too much time with this, it's not likely to be used much, can't be less accurate than it was.
if (ds)
{
ds->m_alpha_max = std::max(ds->m_alpha_max, static_cast<int>(m_vt.m_max.p.z) >> 24);
ds->m_alpha_min = std::min(ds->m_alpha_min, static_cast<int>(m_vt.m_min.p.z) >> 24);
ds->m_alpha_max = std::max(static_cast<u32>(ds->m_alpha_max), static_cast<u32>(m_vt.m_max.p.z) >> 24);
ds->m_alpha_min = std::min(static_cast<u32>(ds->m_alpha_min), static_cast<u32>(m_vt.m_min.p.z) >> 24);
GL_INS("New DS Alpha Range: %d-%d", ds->m_alpha_min, ds->m_alpha_max);
if (GSLocalMemory::m_psm[ds->m_TEX0.PSM].bpp == 16)