GS: Add checking of multiple LODs to IsAutoFlushDraw().

This commit is contained in:
TJnotJT 2025-08-11 09:02:29 -04:00 committed by lightningterror
parent 2cba346ff5
commit 0c70cc7e5a
2 changed files with 46 additions and 6 deletions

View File

@ -3994,7 +3994,7 @@ void GSState::CalculatePrimitiveCoversWithoutGaps()
m_primitive_covers_without_gaps = SpriteDrawWithoutGaps() ? (m_primitive_covers_without_gaps == GapsFound ? SpriteNoGaps : m_primitive_covers_without_gaps) : GapsFound;
}
__forceinline bool GSState::IsAutoFlushDraw(u32 prim)
__forceinline bool GSState::IsAutoFlushDraw(u32 prim, int& tex_layer)
{
if (!PRIM->TME || (GSConfig.UserHacks_AutoFlush == GSHWAutoFlushLevel::SpritesOnly && prim != GS_SPRITE))
return false;
@ -4013,15 +4013,54 @@ __forceinline bool GSState::IsAutoFlushDraw(u32 prim)
if (const_spacing)
return false;
}
// Check if one of the texture being used is the same as the FRAME or ZBUF.
// In the case of possible mip-mapping, we need to check all possible layers.
bool frame_addr_hit = false;
bool zbuf_addr_hit = false;
const bool possible_mip_map = m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5;
int min_possible_layer = 0;
int max_possible_layer = 0;
if (possible_mip_map)
{
if (m_context->TEX1.LCM)
{
// Fixed LOD.
min_possible_layer = std::clamp(m_context->TEX1.K >> 4, 0, static_cast<int>(m_context->TEX1.MXL));
max_possible_layer = std::clamp((m_context->TEX1.K + 0xF) >> 4, 0, static_cast<int>(m_context->TEX1.MXL));
}
else
{
// Variable LOD based on vertex Q.
max_possible_layer = static_cast<int>(m_context->TEX1.MXL);
}
}
GIFRegTEX0 TEX0_hit;
for (tex_layer = min_possible_layer; tex_layer <= max_possible_layer; tex_layer++)
{
TEX0_hit = GetTex0Layer(tex_layer);
if (TEX0_hit.TBP0 == m_context->FRAME.Block())
{
frame_addr_hit = true;
break;
}
if (TEX0_hit.TBP0 == m_context->ZBUF.Block())
{
zbuf_addr_hit = true;
break;
}
}
const u32 frame_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk;
const bool frame_hit = m_context->FRAME.Block() == m_context->TEX0.TBP0 && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask);
const bool frame_hit = frame_addr_hit && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask);
// There's a strange behaviour we need to test on a PS2 here, if the FRAME is a Z format, like Powerdrome something swaps over, and it seems Alpha Fail of "FB Only" writes to the Z.. it's odd.
const bool z_needed = !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL != 2) && !m_context->ZBUF.ZMSK;
const bool zbuf_hit = (m_context->ZBUF.Block() == m_context->TEX0.TBP0) && z_needed;
const bool zbuf_hit = zbuf_addr_hit && z_needed;
const u32 frame_z_psm = frame_hit ? m_context->FRAME.PSM : m_context->ZBUF.PSM;
const u32 frame_z_bp = frame_hit ? m_context->FRAME.Block() : m_context->ZBUF.Block();
if ((frame_hit || zbuf_hit) && GSUtil::HasSharedBits(frame_z_bp, frame_z_psm, m_context->TEX0.TBP0, m_context->TEX0.PSM))
if ((frame_hit || zbuf_hit) && GSUtil::HasSharedBits(frame_z_bp, frame_z_psm, TEX0_hit.TBP0, TEX0_hit.PSM))
return true;
return false;
@ -4109,7 +4148,8 @@ __forceinline void GSState::HandleAutoFlush()
// To briefly explain what's going on here, what we are checking for is draws over a texture when the source and destination are themselves.
// Because one page of the texture gets buffered in the Texture Cache (the PS2's one) if any of those pixels are overwritten, you still read the old data.
// So we need to calculate if a page boundary is being crossed for the format it is in and if the same part of the texture being written and read inside the draw.
if (IsAutoFlushDraw(prim))
int lod = 0;
if (IsAutoFlushDraw(prim, lod))
{
int n = 1;
u32 buff[3];

View File

@ -171,7 +171,7 @@ protected:
void UpdateVertexKick();
void GrowVertexBuffer();
bool IsAutoFlushDraw(u32 prim);
bool IsAutoFlushDraw(u32 prim, int& tex_layer);
template<u32 prim> void HandleAutoFlush();
void CheckCLUTValidity(u32 prim);