GS/HW: Make Haunting Ground render fix invalidate depth as well

Fixes depth leaking into the image.
This commit is contained in:
Stenzek 2023-06-14 23:56:08 +10:00 committed by Connor McLaughlin
parent 9d1c60239e
commit 85b41e23f0
6 changed files with 74 additions and 30 deletions

View File

@ -196,6 +196,16 @@ u32 GSUtil::GetChannelMask(u32 spsm)
} }
} }
u32 GSUtil::GetChannelMask(u32 spsm, u32 fbmsk)
{
u32 mask = GetChannelMask(spsm);
mask &= (fbmsk & 0xFF) ? (~0x1 & 0xf) : 0xf;
mask &= (fbmsk & 0xFF00) ? (~0x2 & 0xf) : 0xf;
mask &= (fbmsk & 0xFF0000) ? (~0x4 & 0xf) : 0xf;
mask &= (fbmsk & 0xFF000000) ? (~0x8 & 0xf) : 0xf;
return mask;
}
GSRendererType GSUtil::GetPreferredRenderer() GSRendererType GSUtil::GetPreferredRenderer()
{ {
#if defined(__APPLE__) #if defined(__APPLE__)

View File

@ -34,6 +34,7 @@ public:
static bool HasCompatibleBits(u32 spsm, u32 dpsm); static bool HasCompatibleBits(u32 spsm, u32 dpsm);
static bool HasSameSwizzleBits(u32 spsm, u32 dpsm); static bool HasSameSwizzleBits(u32 spsm, u32 dpsm);
static u32 GetChannelMask(u32 spsm); static u32 GetChannelMask(u32 spsm);
static u32 GetChannelMask(u32 spsm, u32 fbmsk);
static GSRendererType GetPreferredRenderer(); static GSRendererType GetPreferredRenderer();
}; };

View File

@ -19,6 +19,7 @@
union RGBAMask union RGBAMask
{ {
u32 _u32;
struct struct
{ {
u32 r : 1; u32 r : 1;
@ -26,7 +27,6 @@ union RGBAMask
u32 b : 1; u32 b : 1;
u32 a : 1; u32 a : 1;
} c; } c;
u32 _u32;
}; };
class GSDirtyRect class GSDirtyRect

View File

@ -971,12 +971,67 @@ bool GSHwHack::OI_Battlefield2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GS
bool GSHwHack::OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t) bool GSHwHack::OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
{ {
// Haunting Ground clears two targets by doing a 256x448 direct colour write at 0x3000, covering a target at 0x3380. // Haunting Ground clears two targets by doing a direct colour write at 0x3000, covering a target at 0x3380.
// This currently isn't handled in our HLE clears, so we need to manually remove the other target. // To make matters worse, it's masked. This currently isn't handled in our HLE clears, so we need to manually
// remove the other target.
if (rt && !ds && !t && r.IsConstantDirectWriteMemClear()) if (rt && !ds && !t && r.IsConstantDirectWriteMemClear())
{ {
GL_CACHE("GSHwHack::OI_HauntingGround()"); GL_CACHE("GSHwHack::OI_HauntingGround()");
g_texture_cache->InvalidateVideoMemTargets(GSTextureCache::RenderTarget, RFRAME.Block(), RFRAME.FBW, RFRAME.PSM, r.m_r);
const u32 bp = RFBP;
const u32 bw = RFBW;
const u32 psm = RFPSM;
const u32 fbmsk = RFBMSK;
const GSVector4i rc = r.m_r;
for (int type = 0; type < 2; type++)
{
auto& list = g_texture_cache->m_dst[type];
for (auto i = list.begin(); i != list.end();)
{
GSTextureCache::Target* t = *i;
auto ei = i++;
// There's two cases we hit here - when we clear 3380 via 3000, and when we overlap 3000 by writing to 3380.
// The latter is actually only 256x224, which ends at 337F, but because the game's a pain in the ass, it
// shuffles 512x512, causing the target to expand. It'd actually be shuffling junk and wasting draw cycles,
// but when did that stop anyone? So, we can get away with just saying "if it's before, ignore".
if (t->m_TEX0.TBP0 <= bp)
{
// don't remove ourself..
continue;
}
// Has to intersect.
if (!t->Overlaps(bp, bw, psm, rc))
continue;
// Another annoying case. Sometimes it clears with RGB masked, only writing to A. We don't want to kill the
// target in this case, so we'll dirty A instead.
if (fbmsk != 0)
{
GL_CACHE("OI_HauntingGround(%x, %u, %s, %d,%d => %d,%d): Dirty target at %x %u %s %08X", bp, bw,
psm_str(psm), rc.x, rc.y, rc.z, rc.w, t->m_TEX0.TBP0, t->m_TEX0.TBW, psm_str(t->m_TEX0.PSM),
fbmsk);
g_texture_cache->AddDirtyRectTarget(t, rc, psm, bw, RGBAMask{GSUtil::GetChannelMask(psm, fbmsk)});
}
else
{
GL_CACHE("OI_HauntingGround(%x, %u, %s, %d,%d => %d,%d): Removing target at %x %u %s", bp, bw,
psm_str(psm), rc.x, rc.y, rc.z, rc.w, t->m_TEX0.TBP0, t->m_TEX0.TBW, psm_str(t->m_TEX0.PSM));
// Need to also remove any sources which reference this target.
g_texture_cache->InvalidateSourcesFromTarget(t);
list.erase(ei);
delete t;
}
}
}
g_texture_cache->InvalidateVideoMemType(GSTextureCache::DepthStencil, bp);
} }
// Not skipping anything. This is just an invalidation hack. // Not skipping anything. This is just an invalidation hack.

View File

@ -2924,29 +2924,6 @@ void GSTextureCache::InvalidateVideoMemSubTarget(GSTextureCache::Target* rt)
} }
} }
void GSTextureCache::InvalidateVideoMemTargets(int type, u32 bp, u32 bw, u32 psm, const GSVector4i& r)
{
auto& list = m_dst[type];
for (auto i = list.begin(); i != list.end();)
{
GSTextureCache::Target* t = *i;
auto ei = i++;
if (t->m_TEX0.TBP0 != bp && t->Overlaps(bp, bw, psm, r))
{
GL_CACHE("InvalidateVideoMemTargets(%x, %u, %s, %d,%d => %d,%d): Removing target at %x %u %s", bp, bw,
psm_str(psm), r.x, r.y, r.z, r.w, t->m_TEX0.TBP0, t->m_TEX0.TBW, psm_str(t->m_TEX0.PSM));
// Need to also remove any sources which reference this target.
InvalidateSourcesFromTarget(t);
list.erase(ei);
delete t;
}
}
}
void GSTextureCache::InvalidateSourcesFromTarget(const Target* t) void GSTextureCache::InvalidateSourcesFromTarget(const Target* t)
{ {
for (auto it = m_src.m_surfaces.begin(); it != m_src.m_surfaces.end();) for (auto it = m_src.m_surfaces.begin(); it != m_src.m_surfaces.end();)

View File

@ -22,6 +22,8 @@
#include "GS/Renderers/Common/GSDirtyRect.h" #include "GS/Renderers/Common/GSDirtyRect.h"
#include <unordered_set> #include <unordered_set>
class GSHwHack;
// Only for debugging. Reads back every target to local memory after drawing, effectively // Only for debugging. Reads back every target to local memory after drawing, effectively
// disabling caching between draws. // disabling caching between draws.
//#define DISABLE_HW_TEXTURE_CACHE //#define DISABLE_HW_TEXTURE_CACHE
@ -29,6 +31,8 @@
class GSTextureCache class GSTextureCache
{ {
public: public:
friend GSHwHack;
enum enum
{ {
RenderTarget, RenderTarget,
@ -467,9 +471,6 @@ public:
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool eewrite = false, bool target = true); void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool eewrite = false, bool target = true);
void InvalidateLocalMem(const GSOffset& off, const GSVector4i& r, bool full_flush = false); void InvalidateLocalMem(const GSOffset& off, const GSVector4i& r, bool full_flush = false);
/// Removes any targets overlapping the specified BP and rectangle.
void InvalidateVideoMemTargets(int type, u32 bp, u32 bw, u32 psm, const GSVector4i& r);
/// Removes any sources which point to the specified target. /// Removes any sources which point to the specified target.
void InvalidateSourcesFromTarget(const Target* t); void InvalidateSourcesFromTarget(const Target* t);