From 9721ed0fb32d0daa962415d9f8c3124ee79466c1 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Sun, 20 Mar 2022 14:10:26 +0000 Subject: [PATCH] GS: Use pixel format mask for FBMSK checks --- pcsx2/GS/GSState.cpp | 10 ++++++---- pcsx2/GS/GSState.h | 2 +- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 9 +++++---- pcsx2/GS/Renderers/HW/GSRendererNew.cpp | 7 ++++--- pcsx2/GS/Renderers/SW/GSRendererSW.cpp | 12 +++++++----- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 31f93d0f00..802fdaba10 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -2730,7 +2730,7 @@ __forceinline void GSState::VertexKick(u32 skip) break; } - if (m_context->FRAME.FBMSK != 0xFFFFFFFF) + 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) @@ -3206,12 +3206,14 @@ void GSState::CalcAlphaMinMax() m_vt.m_alpha.valid = true; } -bool GSState::TryAlphaTest(u32& fm, u32& zm) +bool GSState::TryAlphaTest(u32& fm, const u32 fm_mask, u32& zm) { // Shortcut for the easy case if (m_context->TEST.ATST == ATST_ALWAYS) return true; + const u32 framemask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk; + const u32 framemaskalpha = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk & 0xFF000000; // Alpha test can only control the write of some channels. If channels are already masked // the alpha test is therefore a nop. switch (m_context->TEST.AFAIL) @@ -3223,11 +3225,11 @@ bool GSState::TryAlphaTest(u32& fm, u32& zm) return true; break; case AFAIL_ZB_ONLY: - if (fm == 0xFFFFFFFF) + if ((fm & framemask) == framemask) return true; break; case AFAIL_RGB_ONLY: - if (zm == 0xFFFFFFFF && ((fm & 0xFF000000) == 0xFF000000 || GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt == 1)) + if (zm == 0xFFFFFFFF && ((fm & framemaskalpha) == framemaskalpha || GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt == 1)) return true; break; default: diff --git a/pcsx2/GS/GSState.h b/pcsx2/GS/GSState.h index 2dc34c0513..008ab1543a 100644 --- a/pcsx2/GS/GSState.h +++ b/pcsx2/GS/GSState.h @@ -212,7 +212,7 @@ protected: u8 uses_boundary; ///< Whether or not the usage touches the left, top, right, or bottom edge (and therefore needs wrap modes preserved) }; TextureMinMaxResult GetTextureMinMax(const GIFRegTEX0& TEX0, const GIFRegCLAMP& CLAMP, bool linear); - bool TryAlphaTest(u32& fm, u32& zm); + bool TryAlphaTest(u32& fm, const u32 fm_mask, u32& zm); bool IsOpaque(); bool IsMipMapDraw(); bool IsMipMapActive(); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index bc1884ed29..ea7e46f57b 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -1249,13 +1249,14 @@ void GSRendererHW::Draw() u32 fm = context->FRAME.FBMSK; u32 zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0; + const u32 fm_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk; // Note required to compute TryAlphaTest below. So do it now. if (PRIM->TME && tex_psm.pal > 0) m_mem.m_clut.Read32(context->TEX0, env.TEXA); // Test if we can optimize Alpha Test as a NOP - context->TEST.ATE = context->TEST.ATE && !GSRenderer::TryAlphaTest(fm, zm); + context->TEST.ATE = context->TEST.ATE && !GSRenderer::TryAlphaTest(fm, fm_mask, zm); context->FRAME.FBMSK = fm; context->ZBUF.ZMSK = zm != 0; @@ -1271,7 +1272,7 @@ void GSRendererHW::Draw() // Depth is always pass/fail (no read) and write are discarded (tekken 5). (Note: DATE is currently implemented with a stencil buffer => a depth/stencil buffer) (zm != 0 && m_context->TEST.ZTST <= ZTST_ALWAYS && !m_context->TEST.DATE) || // Depth will be written through the RT - (context->FRAME.FBP == context->ZBUF.ZBP && !PRIM->TME && zm == 0 && fm == 0 && context->TEST.ZTE) + (context->FRAME.FBP == context->ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && context->TEST.ZTE) ); if (no_rt && no_ds) @@ -1504,7 +1505,7 @@ void GSRendererHW::Draw() && draw_sprite_tex && m_src->m_32_bits_fmt; // Okami mustn't call this code - if (m_texture_shuffle && m_vertex.next < 3 && PRIM->FST && (m_context->FRAME.FBMSK == 0)) + if (m_texture_shuffle && m_vertex.next < 3 && PRIM->FST && ((m_context->FRAME.FBMSK & fm_mask) == 0)) { // Avious dubious call to m_texture_shuffle on 16 bits games // The pattern is severals column of 8 pixels. A single sprite @@ -1741,7 +1742,7 @@ void GSRendererHW::Draw() // - if (fm != 0xffffffff && rt) + if ((fm & fm_mask) != fm_mask && rt) { //rt->m_valid = rt->m_valid.runion(r); rt->UpdateValidity(m_r); diff --git a/pcsx2/GS/Renderers/HW/GSRendererNew.cpp b/pcsx2/GS/Renderers/HW/GSRendererNew.cpp index aff3dc6b18..02fc5f76ea 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererNew.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererNew.cpp @@ -230,7 +230,7 @@ void GSRendererNew::EmulateTextureShuffleAndFbmask() // Please bang my head against the wall! // 1/ Reduce the frame mask to a 16 bit format - const u32& m = m_context->FRAME.FBMSK; + const u32 m = m_context->FRAME.FBMSK & GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk; const u32 fbmask = ((m >> 3) & 0x1F) | ((m >> 6) & 0x3E0) | ((m >> 9) & 0x7C00) | ((m >> 16) & 0x8000); // FIXME GSVector will be nice here const u8 rg_mask = fbmask & 0xFF; @@ -301,7 +301,7 @@ void GSRendererNew::EmulateTextureShuffleAndFbmask() // Don't allow only unused bits on 16bit format to enable fbmask, // let's set the mask to 0 in such cases. int fbmask = static_cast(m_context->FRAME.FBMSK); - const int fbmask_r = m_conf.ps.dfmt == 2 ? 0x80F8F8F8 : m_conf.ps.dfmt == 1 ? 0x00FFFFFF : 0xFFFFFFFF; + const int fbmask_r = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk; fbmask &= fbmask_r; const GSVector4i fbmask_v = GSVector4i::load(fbmask); const GSVector4i fbmask_vr = GSVector4i::load(fbmask_r); @@ -1329,7 +1329,8 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour // Detect framebuffer read that will need special handling if (g_gs_device->Features().texture_barrier && (m_context->FRAME.Block() == m_context->TEX0.TBP0) && PRIM->TME && GSConfig.AccurateBlendingUnit != AccBlendLevel::Minimum) { - if ((m_context->FRAME.FBMSK == 0x00FFFFFF) && (m_vt.m_primclass == GS_TRIANGLE_CLASS)) + const u32 fb_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk; + if (((m_context->FRAME.FBMSK & fb_mask) == (fb_mask & 0x00FFFFFF)) && (m_vt.m_primclass == GS_TRIANGLE_CLASS)) { // This pattern is used by several games to emulate a stencil (shadow) // Ratchet & Clank, Jak do alpha integer multiplication (tfx) which is mostly equivalent to +1/-1 diff --git a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp index 854ddab931..baee1be8bd 100644 --- a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp +++ b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp @@ -962,6 +962,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data) u32 fm = context->FRAME.FBMSK; u32 zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0; + const u32 fm_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk; // When the format is 24bit (Z or C), DATE ceases to function. // It was believed that in 24bit mode all pixels pass because alpha doesn't exist @@ -988,7 +989,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data) if (context->TEST.ATE) { - if (!TryAlphaTest(fm, zm)) + if (!TryAlphaTest(fm, fm_mask, zm)) { gd.sel.atst = context->TEST.ATST; gd.sel.afail = context->TEST.AFAIL; @@ -1009,7 +1010,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data) } } - bool fwrite = fm != 0xffffffff; + bool fwrite = (fm & fm_mask) != fm_mask; bool ftest = gd.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24; bool zwrite = zm != 0xffffffff; @@ -1302,12 +1303,13 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data) gd.afix = GSVector4i((int)context->ALPHA.FIX << 7).xxzzlh(); } + const u32 masked_fm = fm & fm_mask; if (gd.sel.date || gd.sel.aba == 1 || gd.sel.abb == 1 || gd.sel.abc == 1 || gd.sel.abd == 1 || gd.sel.atst != ATST_ALWAYS && gd.sel.afail == AFAIL_RGB_ONLY - || gd.sel.fpsm == 0 && fm != 0 && fm != 0xffffffff - || gd.sel.fpsm == 1 && (fm & 0x00ffffff) != 0 && (fm & 0x00ffffff) != 0x00ffffff - || gd.sel.fpsm == 2 && (fm & 0x80f8f8f8) != 0 && (fm & 0x80f8f8f8) != 0x80f8f8f8) + || gd.sel.fpsm == 0 && masked_fm != 0 && masked_fm != fm_mask + || gd.sel.fpsm == 1 && masked_fm != 0 && masked_fm != fm_mask + || gd.sel.fpsm == 2 && masked_fm != 0 && masked_fm != fm_mask) { gd.sel.rfb = 1; }