GS: Add Auto Flush for Z buffer draws

Adjust Burnout CRC hack
This commit is contained in:
refractionpcsx2 2022-03-08 15:16:19 +00:00
parent d9f914eb7c
commit 90a4a11d49
2 changed files with 23 additions and 20 deletions

View File

@ -2433,10 +2433,14 @@ GSState::PRIM_OVERLAP GSState::PrimitiveOverlap()
__forceinline void GSState::HandleAutoFlush() __forceinline void GSState::HandleAutoFlush()
{ {
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);
// 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 zbuf_hit = (m_context->ZBUF.Block() == m_context->TEX0.TBP0) && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL != 2 && (m_context->ZBUF.PSM & 0x30) == 0x30) && !m_context->ZBUF.ZMSK;
// 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. // 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. // 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. // 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 ((m_context->FRAME.Block() == m_context->TEX0.TBP0) && (m_context->TEX0.PSM == m_context->FRAME.PSM) && PRIM->TME && (m_context->FRAME.FBMSK != 0xFFFFFFFF)) if (((frame_hit && ((m_context->TEX0.PSM ^ m_context->FRAME.PSM) & ~0x30) == 0) || (zbuf_hit && ((m_context->TEX0.PSM ^ m_context->ZBUF.PSM) & ~0x30) == 0)) && PRIM->TME && (m_context->FRAME.FBMSK != 0xFFFFFFFF))
{ {
const int page_mask_x = ~(GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.x - 1); const int page_mask_x = ~(GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.x - 1);
const int page_mask_y = ~(GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.y - 1); const int page_mask_y = ~(GSLocalMemory::m_psm[m_context->TEX0.PSM].pgs.y - 1);
@ -2513,12 +2517,20 @@ __forceinline void GSState::HandleAutoFlush()
if(page_crossed) if(page_crossed)
{ {
// Update the vertex trace, scissor it (important for Jak 3!) and intersect with the current texture. // Make sure the format matches, otherwise the coordinates aren't gonna match, so the draws won't intersect.
if((m_index.tail - 1) == current_tex_end) if ((frame_hit && (m_context->TEX0.PSM == m_context->FRAME.PSM)) || (zbuf_hit && (m_context->TEX0.PSM == m_context->ZBUF.PSM)))
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail - m_vertex.head, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM)); {
// Update the vertex trace, scissor it (important for Jak 3!) and intersect with the current texture.
if ((m_index.tail - 1) == current_tex_end)
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail - m_vertex.head, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
GSVector4i area_out = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in)); GSVector4i area_out = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
if (!area_out.rintersect(tex_rect).rempty()) if (!area_out.rintersect(tex_rect).rempty())
{
Flush();
}
}
else // Format of the TEX and FRAME/Z is different, so uhh, just fall back to flushing each page. It's slower, sorry.
{ {
Flush(); Flush();
} }
@ -2534,29 +2546,19 @@ __forceinline void GSState::VertexKick(u32 skip)
switch (prim) switch (prim)
{ {
case GS_POINTLIST: case GS_POINTLIST:
case GS_INVALID:
n = 1; n = 1;
break; break;
case GS_LINELIST: case GS_LINELIST:
n = 2; case GS_SPRITE:
break;
case GS_LINESTRIP: case GS_LINESTRIP:
n = 2; n = 2;
break; break;
case GS_TRIANGLELIST: case GS_TRIANGLELIST:
n = 3;
break;
case GS_TRIANGLESTRIP: case GS_TRIANGLESTRIP:
n = 3;
break;
case GS_TRIANGLEFAN: case GS_TRIANGLEFAN:
n = 3; n = 3;
break; break;
case GS_SPRITE:
n = 2;
break;
case GS_INVALID:
n = 1;
break;
} }
if (m_context->FRAME.FBMSK != 0xFFFFFFFF) if (m_context->FRAME.FBMSK != 0xFFFFFFFF)

View File

@ -18,7 +18,7 @@
bool s_nativeres; bool s_nativeres;
static CRCHackLevel s_crc_hack_level = CRCHackLevel::Full; static CRCHackLevel s_crc_hack_level = CRCHackLevel::Full;
bool s_autoflush;
// hacks // hacks
#define CRC_Partial (s_crc_hack_level >= CRCHackLevel::Partial) #define CRC_Partial (s_crc_hack_level >= CRCHackLevel::Partial)
#define CRC_Full (s_crc_hack_level >= CRCHackLevel::Full) #define CRC_Full (s_crc_hack_level >= CRCHackLevel::Full)
@ -419,7 +419,7 @@ bool GSC_BurnoutGames(const GSFrameInfo& fi, int& skip)
// 0x01dc0 01c00(MP) ntsc, 0x01f00 0x01d40(MP) ntsc progressive, 0x02200(MP) pal. // 0x01dc0 01c00(MP) ntsc, 0x01f00 0x01d40(MP) ntsc progressive, 0x02200(MP) pal.
// Yellow stripes. // Yellow stripes.
// Multiplayer tested only on Takedown. // Multiplayer tested only on Takedown.
skip = 4; skip = s_autoflush ? 2 : 4;
} }
} }
@ -950,6 +950,7 @@ void GSState::SetupCrcHack()
s_nativeres = m_nativeres; s_nativeres = m_nativeres;
s_crc_hack_level = m_crc_hack_level; s_crc_hack_level = m_crc_hack_level;
s_autoflush = m_userhacks_auto_flush;
memset(lut, 0, sizeof(lut)); memset(lut, 0, sizeof(lut));