diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 802fdaba10..024bce5315 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -134,6 +134,7 @@ GSState::GSState() PRIM = &m_env.PRIM; //CSR->rREV = 0x20; m_env.PRMODECONT.AC = 1; + m_last_prim.U32[0] = PRIM->U32[0]; Reset(); @@ -650,6 +651,15 @@ void GSState::DumpVertices(const std::string& filename) file.close(); } +__inline void GSState::CheckFlushes() +{ + if (m_primflush) + Flush(); + + if ((m_context->FRAME.FBMSK & GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk) != GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk) + m_mem.m_clut.Invalidate(m_context->FRAME.Block()); +} + void GSState::GIFPackedRegHandlerNull(const GIFPackedReg* RESTRICT r) { } @@ -707,6 +717,8 @@ void GSState::GIFPackedRegHandlerUV_Hack(const GIFPackedReg* RESTRICT r) template void GSState::GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r) { + CheckFlushes(); + GSVector4i xy = GSVector4i::loadl(&r->U64[0]); GSVector4i zf = GSVector4i::loadl(&r->U64[1]); @@ -721,6 +733,8 @@ void GSState::GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r) template void GSState::GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r) { + CheckFlushes(); + const GSVector4i xy = GSVector4i::loadl(&r->U64[0]); const GSVector4i z = GSVector4i::loadl(&r->U64[1]); const GSVector4i xyz = xy.upl16(xy.srl<4>()).upl32(z); @@ -749,6 +763,8 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u3 { ASSERT(size > 0 && size % 3 == 0); + CheckFlushes(); + const GIFPackedReg* RESTRICT r_end = r + size; while (r < r_end) @@ -781,6 +797,8 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 { ASSERT(size > 0 && size % 3 == 0); + CheckFlushes(); + const GIFPackedReg* RESTRICT r_end = r + size; while (r < r_end) @@ -817,19 +835,6 @@ void GSState::GIFRegHandlerNull(const GIFReg* RESTRICT r) __forceinline void GSState::ApplyPRIM(u32 prim) { - if (GSUtil::GetPrimClass(m_env.PRIM.PRIM) == GSUtil::GetPrimClass(prim & 7)) // NOTE: assume strips/fans are converted to lists - { - u32 prim_mask = 0x7f8; - if (GSConfig.UseHardwareRenderer() && GSUtil::GetPrimClass(prim & 7) == GS_TRIANGLE_CLASS) - prim_mask &= ~0x80; // Mask out AA1. - - if (m_env.PRMODECONT.AC == 1 && (m_env.PRIM.U32[0] ^ prim) & prim_mask) // all fields except PRIM - Flush(); - } - else - { - Flush(); - } if (m_env.PRMODECONT.AC == 1) { @@ -842,12 +847,29 @@ __forceinline void GSState::ApplyPRIM(u32 prim) m_env.PRIM.PRIM = prim & 0x7; } + m_primflush = false; + u32 prim_mask = 0x7ff; + + // Same class of draw so we don't need to flush + if (GSUtil::GetPrimClass(m_last_prim.PRIM) == GSUtil::GetPrimClass(m_env.PRIM.PRIM)) + prim_mask &= ~0x7; + + if (GSConfig.UseHardwareRenderer() && GSUtil::GetPrimClass(prim & 7) == GS_TRIANGLE_CLASS) + prim_mask &= ~0x80; // Mask out AA1. + + if ((m_last_prim.U32[0] ^ m_env.PRIM.U32[0]) & prim_mask) + m_primflush = true; + UpdateVertexKick(); ASSERT(m_index.tail == 0 || !g_gs_device->Features().provoking_vertex_last || m_index.buff[m_index.tail - 1] + 1 == m_vertex.next); if (m_index.tail == 0) + { m_vertex.next = 0; + m_primflush = false; + m_last_prim.U32[0] = m_env.PRIM.U32[0]; + } m_vertex.head = m_vertex.tail = m_vertex.next; // remove unused vertices from the end of the vertex buffer } @@ -898,6 +920,8 @@ void GSState::GIFRegHandlerUV_Hack(const GIFReg* RESTRICT r) template void GSState::GIFRegHandlerXYZF2(const GIFReg* RESTRICT r) { + CheckFlushes(); + GSVector4i xyzf = GSVector4i::loadl(&r->XYZF); GSVector4i xyz = xyzf & (GSVector4i::xffffffff().upl32(GSVector4i::x00ffffff())); GSVector4i uvf = GSVector4i::load((int)m_v.UV).upl32(xyzf.srl32(24).srl<4>()); @@ -910,6 +934,8 @@ void GSState::GIFRegHandlerXYZF2(const GIFReg* RESTRICT r) template void GSState::GIFRegHandlerXYZ2(const GIFReg* RESTRICT r) { + CheckFlushes(); + m_v.m[1] = GSVector4i::load(&r->XYZ, &m_v.UV); VertexKick(adc); @@ -940,7 +966,7 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0) constexpr u64 mask = 0x1f78001fffffffffull; // TBP0 TBW PSM TW TH TCC TFX CPSM CSA - if (wt || PRIM->CTXT == i && ((TEX0.U64 ^ m_env.CTXT[i].TEX0.U64) & mask)) + if (wt || (PRIM->CTXT == i || m_primflush) && ((TEX0.U64 ^ m_env.CTXT[i].TEX0.U64) & mask)) Flush(); TEX0.CPSM &= 0xa; // 1010b @@ -1074,7 +1100,7 @@ void GSState::GIFRegHandlerCLAMP(const GIFReg* RESTRICT r) { GL_REG("CLAMP_%d = 0x%x_%x", i, r->U32[1], r->U32[0]); - if (PRIM->CTXT == i && r->CLAMP != m_env.CTXT[i].CLAMP) + if ((PRIM->CTXT == i || m_primflush) && r->CLAMP != m_env.CTXT[i].CLAMP) Flush(); m_env.CTXT[i].CLAMP = (GSVector4i)r->CLAMP; @@ -1094,7 +1120,7 @@ void GSState::GIFRegHandlerTEX1(const GIFReg* RESTRICT r) { GL_REG("TEX1_%d = 0x%x_%x", i, r->U32[1], r->U32[0]); - if (PRIM->CTXT == i && r->TEX1 != m_env.CTXT[i].TEX1) + if ((PRIM->CTXT == i || m_primflush) && r->TEX1 != m_env.CTXT[i].TEX1) Flush(); m_env.CTXT[i].TEX1 = (GSVector4i)r->TEX1; @@ -1148,24 +1174,33 @@ void GSState::GIFRegHandlerPRMODE(const GIFReg* RESTRICT r) { GL_REG("PRMODE = 0x%x_%x", r->U32[1], r->U32[0]); - if (!m_env.PRMODECONT.AC) - { - u32 prim_mask = 0x7f8; - if (GSConfig.UseHardwareRenderer() && GSUtil::GetPrimClass(m_env.PRIM.PRIM) == GS_TRIANGLE_CLASS) - prim_mask &= ~0x80; // Mask out AA1. - - if ((m_env.PRIM.U32[0] ^ r->PRMODE.U32[0]) & prim_mask) - Flush(); - } - else - { + // We're in PRIM mode, need to ignore any writes + if (m_env.PRMODECONT.AC) return; - } const u32 _PRIM = m_env.PRIM.PRIM; m_env.PRIM = (GSVector4i)r->PRMODE; m_env.PRIM.PRIM = _PRIM; + u32 prim_mask = 0x7ff; + + // Same class of draw so we don't need to flush + if (GSUtil::GetPrimClass(m_last_prim.PRIM) == GSUtil::GetPrimClass(m_env.PRIM.PRIM)) + prim_mask &= ~0x7; + + if (GSConfig.UseHardwareRenderer() && GSUtil::GetPrimClass(m_env.PRIM.PRIM) == GS_TRIANGLE_CLASS) + prim_mask &= ~0x80; // Mask out AA1. + + m_primflush = false; + if ((m_last_prim.U32[0] ^ m_env.PRIM.U32[0]) & prim_mask) + m_primflush = true; + + if (m_index.tail == 0) + { + m_primflush = false; + m_last_prim.U32[0] = m_env.PRIM.U32[0]; + } + UpdateContext(); } @@ -1194,7 +1229,7 @@ void GSState::GIFRegHandlerMIPTBP1(const GIFReg* RESTRICT r) { GL_REG("MIPTBP1_%d = 0x%x_%x", i, r->U32[1], r->U32[0]); - if (PRIM->CTXT == i && r->MIPTBP1 != m_env.CTXT[i].MIPTBP1) + if ((PRIM->CTXT == i || m_primflush) && r->MIPTBP1 != m_env.CTXT[i].MIPTBP1) Flush(); m_env.CTXT[i].MIPTBP1 = (GSVector4i)r->MIPTBP1; @@ -1205,7 +1240,7 @@ void GSState::GIFRegHandlerMIPTBP2(const GIFReg* RESTRICT r) { GL_REG("MIPTBP2_%d = 0x%x_%x", i, r->U32[1], r->U32[0]); - if (PRIM->CTXT == i && r->MIPTBP2 != m_env.CTXT[i].MIPTBP2) + if ((PRIM->CTXT == i || m_primflush) && r->MIPTBP2 != m_env.CTXT[i].MIPTBP2) Flush(); m_env.CTXT[i].MIPTBP2 = (GSVector4i)r->MIPTBP2; @@ -1244,7 +1279,7 @@ void GSState::GIFRegHandlerTEXFLUSH(const GIFReg* RESTRICT r) template void GSState::GIFRegHandlerSCISSOR(const GIFReg* RESTRICT r) { - if (PRIM->CTXT == i && r->SCISSOR != m_env.CTXT[i].SCISSOR) + if ((PRIM->CTXT == i || m_primflush) && r->SCISSOR != m_env.CTXT[i].SCISSOR) Flush(); m_env.CTXT[i].SCISSOR = (GSVector4i)r->SCISSOR; @@ -1258,7 +1293,7 @@ template void GSState::GIFRegHandlerALPHA(const GIFReg* RESTRICT r) { GL_REG("ALPHA = 0x%x_%x", r->U32[1], r->U32[0]); - if (PRIM->CTXT == i && r->ALPHA != m_env.CTXT[i].ALPHA) + if ((PRIM->CTXT == i || m_primflush) && r->ALPHA != m_env.CTXT[i].ALPHA) Flush(); m_env.CTXT[i].ALPHA = (GSVector4i)r->ALPHA; @@ -1307,7 +1342,7 @@ void GSState::GIFRegHandlerCOLCLAMP(const GIFReg* RESTRICT r) template void GSState::GIFRegHandlerTEST(const GIFReg* RESTRICT r) { - if (PRIM->CTXT == i && r->TEST != m_env.CTXT[i].TEST) + if ((PRIM->CTXT == i || m_primflush) && r->TEST != m_env.CTXT[i].TEST) Flush(); m_env.CTXT[i].TEST = (GSVector4i)r->TEST; @@ -1324,7 +1359,7 @@ void GSState::GIFRegHandlerPABE(const GIFReg* RESTRICT r) template void GSState::GIFRegHandlerFBA(const GIFReg* RESTRICT r) { - if (PRIM->CTXT == i && r->FBA != m_env.CTXT[i].FBA) + if ((PRIM->CTXT == i || m_primflush) && r->FBA != m_env.CTXT[i].FBA) Flush(); m_env.CTXT[i].FBA = (GSVector4i)r->FBA; @@ -1340,7 +1375,7 @@ void GSState::GIFRegHandlerFRAME(const GIFReg* RESTRICT r) // However there is some issues so even software mode is incorrect on PCSX2, but this works better.. NewFrame.FBW = std::clamp(NewFrame.FBW, 1U, 32U); - if (PRIM->CTXT == i && NewFrame != m_env.CTXT[i].FRAME) + if ((PRIM->CTXT == i || m_primflush) && NewFrame != m_env.CTXT[i].FRAME) Flush(); if ((NewFrame.PSM & 0x30) == 0x30) @@ -1399,7 +1434,7 @@ void GSState::GIFRegHandlerZBUF(const GIFReg* RESTRICT r) else ZBUF.PSM |= 0x30; - if (PRIM->CTXT == i && ZBUF != m_env.CTXT[i].ZBUF) + if ((PRIM->CTXT == i || m_primflush) && ZBUF != m_env.CTXT[i].ZBUF) Flush(); if ((m_env.CTXT[i].ZBUF.U32[0] ^ ZBUF.U32[0]) & 0x3f0001ff) // ZBP PSM @@ -1491,7 +1526,6 @@ void GSState::GIFRegHandlerHWREG(const GIFReg* RESTRICT r) void GSState::Flush() { FlushWrite(); - FlushPrim(); } @@ -1522,6 +1556,15 @@ void GSState::FlushWrite() void GSState::FlushPrim() { + const u32 new_prim = PRIM->U32[0]; + + if (m_primflush) + { + // We need to restore the old PRIM and update the Context (in case it changed) + m_env.PRIM.U32[0] = m_last_prim.U32[0]; + UpdateContext(); + } + if (m_index.tail > 0) { GL_REG("FlushPrim ctxt %d", PRIM->CTXT); @@ -1554,10 +1597,12 @@ void GSState::FlushPrim() case GS_LINELIST: case GS_LINESTRIP: case GS_SPRITE: + unused = 1; + buff[0] = m_vertex.buff[tail - 1]; case GS_TRIANGLELIST: case GS_TRIANGLESTRIP: - unused = tail - head; - memcpy(buff, &m_vertex.buff[head], sizeof(GSVertex) * unused); + unused = std::min(tail - head, 2); + memcpy(buff, &m_vertex.buff[tail - unused], sizeof(GSVertex) * 2); break; case GS_TRIANGLEFAN: buff[0] = m_vertex.buff[head]; @@ -1626,6 +1671,16 @@ void GSState::FlushPrim() m_vertex.next = 0; } } + + if (m_primflush) + { + // Restore the backup + PRIM->U32[0] = new_prim; + UpdateContext(); + } + + m_primflush = false; + m_last_prim.U32[0] = new_prim; } void GSState::Write(const u8* mem, int len) @@ -2730,9 +2785,6 @@ __forceinline void GSState::VertexKick(u32 skip) break; } - if ((m_context->FRAME.FBMSK & GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk) != GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk) - m_mem.m_clut.Invalidate(m_context->FRAME.Block()); - if (auto_flush && m_index.tail >= n) HandleAutoFlush(); diff --git a/pcsx2/GS/GSState.h b/pcsx2/GS/GSState.h index 008ab1543a..abe655241a 100644 --- a/pcsx2/GS/GSState.h +++ b/pcsx2/GS/GSState.h @@ -51,6 +51,8 @@ class GSState : public GSAlignedClass<32> GIFPackedRegHandler m_fpGIFPackedRegHandlers[16]; GIFPackedRegHandler m_fpGIFPackedRegHandlerXYZ[8][4]; + void CheckFlushes(); + void GIFPackedRegHandlerNull(const GIFPackedReg* RESTRICT r); void GIFPackedRegHandlerRGBA(const GIFPackedReg* RESTRICT r); void GIFPackedRegHandlerSTQ(const GIFPackedReg* RESTRICT r); @@ -232,6 +234,8 @@ public: bool m_NTSC_Saturation; bool m_nativeres; bool m_mipmap; + bool m_primflush; + GIFRegPRIM m_last_prim; static int s_n; bool s_dump;