GS: Use pixel format mask for FBMSK checks

This commit is contained in:
refractionpcsx2 2022-03-20 14:10:26 +00:00
parent 224863fbd5
commit 9721ed0fb3
5 changed files with 23 additions and 17 deletions

View File

@ -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:

View File

@ -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();

View File

@ -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);

View File

@ -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<int>(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

View File

@ -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;
}