mirror of https://github.com/PCSX2/pcsx2.git
GS: Use pixel format mask for FBMSK checks
This commit is contained in:
parent
224863fbd5
commit
9721ed0fb3
|
@ -2730,7 +2730,7 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||||
break;
|
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());
|
m_mem.m_clut.Invalidate(m_context->FRAME.Block());
|
||||||
|
|
||||||
if (auto_flush && m_index.tail >= n)
|
if (auto_flush && m_index.tail >= n)
|
||||||
|
@ -3206,12 +3206,14 @@ void GSState::CalcAlphaMinMax()
|
||||||
m_vt.m_alpha.valid = true;
|
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
|
// Shortcut for the easy case
|
||||||
if (m_context->TEST.ATST == ATST_ALWAYS)
|
if (m_context->TEST.ATST == ATST_ALWAYS)
|
||||||
return true;
|
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
|
// Alpha test can only control the write of some channels. If channels are already masked
|
||||||
// the alpha test is therefore a nop.
|
// the alpha test is therefore a nop.
|
||||||
switch (m_context->TEST.AFAIL)
|
switch (m_context->TEST.AFAIL)
|
||||||
|
@ -3223,11 +3225,11 @@ bool GSState::TryAlphaTest(u32& fm, u32& zm)
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
case AFAIL_ZB_ONLY:
|
case AFAIL_ZB_ONLY:
|
||||||
if (fm == 0xFFFFFFFF)
|
if ((fm & framemask) == framemask)
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
case AFAIL_RGB_ONLY:
|
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;
|
return true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -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)
|
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);
|
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 IsOpaque();
|
||||||
bool IsMipMapDraw();
|
bool IsMipMapDraw();
|
||||||
bool IsMipMapActive();
|
bool IsMipMapActive();
|
||||||
|
|
|
@ -1249,13 +1249,14 @@ void GSRendererHW::Draw()
|
||||||
|
|
||||||
u32 fm = context->FRAME.FBMSK;
|
u32 fm = context->FRAME.FBMSK;
|
||||||
u32 zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
|
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.
|
// Note required to compute TryAlphaTest below. So do it now.
|
||||||
if (PRIM->TME && tex_psm.pal > 0)
|
if (PRIM->TME && tex_psm.pal > 0)
|
||||||
m_mem.m_clut.Read32(context->TEX0, env.TEXA);
|
m_mem.m_clut.Read32(context->TEX0, env.TEXA);
|
||||||
|
|
||||||
// Test if we can optimize Alpha Test as a NOP
|
// 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->FRAME.FBMSK = fm;
|
||||||
context->ZBUF.ZMSK = zm != 0;
|
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)
|
// 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) ||
|
(zm != 0 && m_context->TEST.ZTST <= ZTST_ALWAYS && !m_context->TEST.DATE) ||
|
||||||
// Depth will be written through the RT
|
// 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)
|
if (no_rt && no_ds)
|
||||||
|
@ -1504,7 +1505,7 @@ void GSRendererHW::Draw()
|
||||||
&& draw_sprite_tex && m_src->m_32_bits_fmt;
|
&& draw_sprite_tex && m_src->m_32_bits_fmt;
|
||||||
|
|
||||||
// Okami mustn't call this code
|
// 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
|
// Avious dubious call to m_texture_shuffle on 16 bits games
|
||||||
// The pattern is severals column of 8 pixels. A single sprite
|
// 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->m_valid = rt->m_valid.runion(r);
|
||||||
rt->UpdateValidity(m_r);
|
rt->UpdateValidity(m_r);
|
||||||
|
|
|
@ -230,7 +230,7 @@ void GSRendererNew::EmulateTextureShuffleAndFbmask()
|
||||||
|
|
||||||
// Please bang my head against the wall!
|
// Please bang my head against the wall!
|
||||||
// 1/ Reduce the frame mask to a 16 bit format
|
// 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);
|
const u32 fbmask = ((m >> 3) & 0x1F) | ((m >> 6) & 0x3E0) | ((m >> 9) & 0x7C00) | ((m >> 16) & 0x8000);
|
||||||
// FIXME GSVector will be nice here
|
// FIXME GSVector will be nice here
|
||||||
const u8 rg_mask = fbmask & 0xFF;
|
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,
|
// Don't allow only unused bits on 16bit format to enable fbmask,
|
||||||
// let's set the mask to 0 in such cases.
|
// let's set the mask to 0 in such cases.
|
||||||
int fbmask = static_cast<int>(m_context->FRAME.FBMSK);
|
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;
|
fbmask &= fbmask_r;
|
||||||
const GSVector4i fbmask_v = GSVector4i::load(fbmask);
|
const GSVector4i fbmask_v = GSVector4i::load(fbmask);
|
||||||
const GSVector4i fbmask_vr = GSVector4i::load(fbmask_r);
|
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
|
// 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 (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)
|
// 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
|
// Ratchet & Clank, Jak do alpha integer multiplication (tfx) which is mostly equivalent to +1/-1
|
||||||
|
|
|
@ -962,6 +962,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
||||||
|
|
||||||
u32 fm = context->FRAME.FBMSK;
|
u32 fm = context->FRAME.FBMSK;
|
||||||
u32 zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
|
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.
|
// 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
|
// 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 (context->TEST.ATE)
|
||||||
{
|
{
|
||||||
if (!TryAlphaTest(fm, zm))
|
if (!TryAlphaTest(fm, fm_mask, zm))
|
||||||
{
|
{
|
||||||
gd.sel.atst = context->TEST.ATST;
|
gd.sel.atst = context->TEST.ATST;
|
||||||
gd.sel.afail = context->TEST.AFAIL;
|
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 ftest = gd.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24;
|
||||||
|
|
||||||
bool zwrite = zm != 0xffffffff;
|
bool zwrite = zm != 0xffffffff;
|
||||||
|
@ -1302,12 +1303,13 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
||||||
gd.afix = GSVector4i((int)context->ALPHA.FIX << 7).xxzzlh();
|
gd.afix = GSVector4i((int)context->ALPHA.FIX << 7).xxzzlh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const u32 masked_fm = fm & fm_mask;
|
||||||
if (gd.sel.date
|
if (gd.sel.date
|
||||||
|| gd.sel.aba == 1 || gd.sel.abb == 1 || gd.sel.abc == 1 || gd.sel.abd == 1
|
|| 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.atst != ATST_ALWAYS && gd.sel.afail == AFAIL_RGB_ONLY
|
||||||
|| gd.sel.fpsm == 0 && fm != 0 && fm != 0xffffffff
|
|| gd.sel.fpsm == 0 && masked_fm != 0 && masked_fm != fm_mask
|
||||||
|| gd.sel.fpsm == 1 && (fm & 0x00ffffff) != 0 && (fm & 0x00ffffff) != 0x00ffffff
|
|| gd.sel.fpsm == 1 && masked_fm != 0 && masked_fm != fm_mask
|
||||||
|| gd.sel.fpsm == 2 && (fm & 0x80f8f8f8) != 0 && (fm & 0x80f8f8f8) != 0x80f8f8f8)
|
|| gd.sel.fpsm == 2 && masked_fm != 0 && masked_fm != fm_mask)
|
||||||
{
|
{
|
||||||
gd.sel.rfb = 1;
|
gd.sel.rfb = 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue