GS/HW: Fix Double Half Clear bug + better detect double buffer changes

This commit is contained in:
refractionpcsx2 2023-07-22 22:36:36 +01:00
parent 2f105cbe15
commit b96978494b
3 changed files with 33 additions and 12 deletions

View File

@ -2490,7 +2490,7 @@ void GSRendererHW::Draw()
// Grandia Xtreme, Onimusha Warlord.
if (!new_rect && new_height && old_end_block != rt->m_end_block)
{
old_rt = g_texture_cache->FindTargetOverlap(old_end_block, rt->m_end_block, GSTextureCache::RenderTarget, m_cached_ctx.FRAME.PSM);
old_rt = g_texture_cache->FindTargetOverlap(rt, GSTextureCache::RenderTarget, m_cached_ctx.FRAME.PSM);
if (old_rt && old_rt != rt && GSUtil::HasSharedBits(old_rt->m_TEX0.PSM, rt->m_TEX0.PSM))
{
@ -2528,7 +2528,7 @@ void GSRendererHW::Draw()
if (!new_rect && new_height && old_end_block != ds->m_end_block)
{
old_ds = g_texture_cache->FindTargetOverlap(old_end_block, ds->m_end_block, GSTextureCache::DepthStencil, m_cached_ctx.ZBUF.PSM);
old_ds = g_texture_cache->FindTargetOverlap(ds, GSTextureCache::DepthStencil, m_cached_ctx.ZBUF.PSM);
if (old_ds && old_ds != ds && GSUtil::HasSharedBits(old_ds->m_TEX0.PSM, ds->m_TEX0.PSM))
{
@ -5459,7 +5459,8 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
// GTA: LCS does this setup, along with a few other games. Thankfully if it's a zero clear, we'll clear both
// separately, and the end result is the same because it gets invalidated. That's better than falsely detecting
// double half clears, and ending up with 1024 high render targets which really shouldn't be.
if (frame_psm.fmt != zbuf_psm.fmt && m_cached_ctx.FRAME.FBMSK != ((zbuf_psm.fmt == 1) ? 0xFF000000u : 0))
if ((frame_psm.fmt != zbuf_psm.fmt && m_cached_ctx.FRAME.FBMSK != ((zbuf_psm.fmt == 1) ? 0xFF000000u : 0)) ||
!GSUtil::HasCompatibleBits(m_cached_ctx.FRAME.PSM & ~0x30, m_cached_ctx.ZBUF.PSM & ~0x30)) // Bit depth is not the same (i.e. 32bit + 16bit).
{
GL_INS("Inconsistent FRAME [%s, %08x] and ZBUF [%s] formats, not using double-half clear.",
psm_str(m_cached_ctx.FRAME.PSM), m_cached_ctx.FRAME.FBMSK, psm_str(m_cached_ctx.ZBUF.PSM));

View File

@ -1222,14 +1222,13 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
return src;
}
GSTextureCache::Target* GSTextureCache::FindTargetOverlap(u32 bp, u32 end_block, int type, int psm)
GSTextureCache::Target* GSTextureCache::FindTargetOverlap(Target* target, int type, int psm)
{
u32 end_block_bp = end_block < bp ? (MAX_BP + 1) : end_block;
for (auto t : m_dst[type])
{
// Only checks that the texure starts at the requested bp, which shares data. Size isn't considered.
if (t->m_TEX0.TBP0 >= bp && t->m_TEX0.TBP0 < end_block_bp && GSUtil::HasCompatibleBits(t->m_TEX0.PSM, psm))
if (t != target && t->m_TEX0.TBW == target->m_TEX0.TBW && t->m_TEX0.TBP0 >= target->m_TEX0.TBP0 &&
t->UnwrappedEndBlock() <= target->UnwrappedEndBlock() && GSUtil::HasCompatibleBits(t->m_TEX0.PSM, psm))
return t;
}
return nullptr;
@ -1746,6 +1745,29 @@ void GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
{
dst->UpdateValidity(GSVector4i::loadh(valid_size));
}
for (int type = 0; type < 2; type++)
{
auto& list = m_dst[type];
for (auto i = list.begin(); i != list.end();)
{
auto j = i;
Target* t = *j;
// could be overwriting a double buffer, so if it's the second half of it, just reduce the size down to half.
if (dst != t && t->m_TEX0.TBW == dst->m_TEX0.TBW &&
t->m_TEX0.PSM == dst->m_TEX0.PSM &&
((((t->m_end_block + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == dst->m_TEX0.TBP0)
{
//DevCon.Warning("Found one %x->%x BW %d PSM %x (new target %x->%x BW %d PSM %x)", t->m_TEX0.TBP0, t->m_end_block, t->m_TEX0.TBW, t->m_TEX0.PSM, dst->m_TEX0.TBP0, dst->m_end_block, dst->m_TEX0.TBW, dst->m_TEX0.PSM);
GSVector4i new_valid = t->m_valid;
new_valid.w /= 2;
t->ResizeValidity(new_valid);
return;
}
i++;
}
}
}
GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale)
@ -2958,7 +2980,7 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r
t->m_drawn_since_read.z = targetr.x;
}
if (exact_bp)
if (exact_bp && read_end <= t->m_end_block)
return;
}
}
@ -5149,8 +5171,6 @@ void GSTextureCache::Target::Update()
g_gs_device->DrawMultiStretchRects(drects, ndrects, m_texture, shader);
}
UpdateValidity(total_rect);
// We don't know what the dirty alpha is gonna be, so assume max.
m_alpha_min = 0;
m_alpha_max = 255;
g_gs_device->Recycle(t);

View File

@ -469,14 +469,14 @@ public:
bool CanTranslate(u32 bp, u32 bw, u32 spsm, GSVector4i r, u32 dbp, u32 dpsm, u32 dbw);
GSVector4i TranslateAlignedRectByPage(Target* t, u32 sbp, u32 spsm, u32 sbw, GSVector4i src_r, bool is_invalidation = false);
void DirtyRectByPage(u32 sbp, u32 spsm, u32 sbw, Target* t, GSVector4i src_r);
void DirtyRectByPageOld(u32 sbp, u32 spsm, u32 sbw, Target* t, GSVector4i src_r);
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);
std::shared_ptr<Palette> LookupPaletteObject(const u32* clut, u16 pal, bool need_gs_texture);
Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle);
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, bool palette = false);
Target* FindTargetOverlap(u32 bp, u32 end_block, int type, int psm);
Target* FindTargetOverlap(Target* target, int type, int psm);
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true,
const GSVector4i draw_rc = GSVector4i::zero());