GS/HW: Add CRC hack to cover IRem games to deal with depth deswizzle shuffle

This commit is contained in:
refractionpcsx2 2025-11-05 01:32:17 +00:00 committed by lightningterror
parent b8680c3139
commit 47eb499893
2 changed files with 86 additions and 0 deletions

View File

@ -37,6 +37,90 @@ static bool s_nativeres;
// Partial level, broken on all renderers.
////////////////////////////////////////////////////////////////////////////////
bool GSHwHack::GSC_IRem(GSRendererHW& r, int& skip)
{
if (skip == 0)
{
const int get_next_ctx = r.m_env.PRIM.CTXT;
const GSDrawingContext& next_ctx = r.m_env.CTXT[get_next_ctx];
// Game does alternate line channel shuffles with blending, we can't handle this and the first one does it, so skip the second.
if (RTME && RTPSM == PSMT8 && (RTBP0 + 0x20) == next_ctx.TEX0.TBP0 && RFBP == next_ctx.FRAME.Block())
{
skip = 1;
return false;
}
// Detect the deswizzling shuffle from depth, copying the RG and BA separately on each half of the page (ignore the split).
if (RTME && RFBP != RTBP0 && RFPSM == PSMCT16S && RTPSM == PSMCT16S)
{
if (r.m_vt.m_max.p.x == 64 && r.m_vt.m_max.p.y == 64 && r.m_index.tail == 128)
{
const GSVector4i draw_size(r.m_vt.m_min.p.x, r.m_vt.m_min.p.y/2, r.m_vt.m_max.p.x, r.m_vt.m_max.p.y/2);
const GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y/2, r.m_vt.m_max.t.x, r.m_vt.m_max.t.y/2);
r.m_cached_ctx.TEX0.PSM = PSMCT32;
r.m_cached_ctx.FRAME.PSM = PSMCT32;
r.ReplaceVerticesWithSprite(draw_size, read_size, GSVector2i(read_size.width(), read_size.height()), draw_size);
}
}
// Following the previous draw, it tries to copy everything read from depth and offset it by 2, for the alternate line channel shuffle (skipped above).
if (RTBP0 == (RFBP - 0x20) && r.m_vt.m_max.p.x == 64 && r.m_vt.m_max.p.y == 34 && r.m_index.tail == 2)
{
GSVector4i draw_size(r.m_vt.m_min.p.x, r.m_vt.m_min.p.y - 2.0f, r.m_vt.m_max.p.x, r.m_vt.m_max.p.y - 2.0f);
GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y, r.m_vt.m_max.t.x, r.m_vt.m_max.t.y);
r.ReplaceVerticesWithSprite(draw_size, read_size, GSVector2i(read_size.width(), read_size.height()), draw_size);
// Fix up the shuffle from last draw.
{
GIFRegTEX0 RTLookup = GIFRegTEX0::Create(RTBP0, RFBW, RFPSM);
GSTextureCache::Source* src = g_texture_cache->LookupSource(true, RTLookup, r.m_cached_ctx.TEXA, r.m_cached_ctx.CLAMP, GSVector4i(0,0,1,1), nullptr, true, false, r.m_cached_ctx.FRAME, true, true);
GSTextureCache::Target* rt = g_texture_cache->LookupTarget(GIFRegTEX0::Create(RTBP0, RFBW, RFPSM),
GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true, 0, false, false, true, true, GSVector4i(0,0,1,1), true, false, true, src);
if (!rt)
return false;
GSLocalMemory::psm_t rt_psm = GSLocalMemory::m_psm[RFPSM];
int page_offset = (RTBP0 - rt->m_TEX0.TBP0) >> 5;
int vertical_offset = page_offset / std::max(rt->m_TEX0.TBW, 1U) * rt_psm.pgs.y;
int horizontal_offset = page_offset % std::max(rt->m_TEX0.TBW, 1U) * rt_psm.pgs.x;
draw_size = draw_size + GSVector4i(horizontal_offset, vertical_offset, horizontal_offset, vertical_offset);
rt->UnscaleRTAlpha();
// Shuffle the blue channel in to red, leave green as-is.
GSHWDrawConfig& config = r.BeginHLEHardwareDraw(
rt->GetTexture(), nullptr, rt->GetScale(), rt->GetTexture(), rt->GetScale(), draw_size);
config.ps.shuffle = 1;
config.ps.dst_fmt = GSLocalMemory::PSM_FMT_32;
config.ps.write_rg = 0;
config.ps.shuffle_same = 0;
config.ps.real16src = 0;
config.ps.shuffle_across = 1;
config.ps.process_rg = r.SHUFFLE_WRITE;
config.ps.process_ba = r.SHUFFLE_READ;
config.colormask.wrgba = 0;
config.colormask.wr = 1;
config.ps.rta_correction = 0;
config.ps.rta_source_correction = 0;
config.ps.tfx = TFX_DECAL;
config.ps.tcc = true;
r.EndHLEHardwareDraw(true);
rt->m_alpha_min = 0;
rt->m_alpha_max = 255;
rt = nullptr;
src = nullptr;
}
}
}
return true;
}
// Channel effect not properly supported yet
bool GSHwHack::GSC_Manhunt2(GSRendererHW& r, int& skip)
{
@ -1382,6 +1466,7 @@ bool GSHwHack::MV_Ico(GSRendererHW& r)
#define CRC_F(name) { #name, &GSHwHack::name }
const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_functions[] = {
CRC_F(GSC_IRem),
CRC_F(GSC_Manhunt2),
CRC_F(GSC_MidnightClub3),
CRC_F(GSC_SacredBlaze),

View File

@ -6,6 +6,7 @@
class GSHwHack
{
public:
static bool GSC_IRem(GSRendererHW& r, int& skip);
static bool GSC_Manhunt2(GSRendererHW& r, int& skip);
static bool GSC_SacredBlaze(GSRendererHW& r, int& skip);
static bool GSC_GuitarHero(GSRendererHW& r, int& skip);