mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Texture cache improvements
GS/HW: Only use temporary source for recursive draw .. and don't insert it into the page map. GS/HW: Lookup page list for depth sources GS/HW: Avoid target copies by using shader sampling GS/HW: Make texture cache a global pointer GS/HW: Remove GetID() from GSTexture It only made sense for OpenGL, was always zero in Vulkan. GS/HW: Rewrite texture sampling hazard detection Also avoid redundant channel shuffle setup. GS/HW: Turn Haunting Ground CRC into an OI fix
This commit is contained in:
parent
ed90c8868f
commit
faecc6913b
|
@ -16193,6 +16193,7 @@ SLES-52877:
|
|||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes blurriness.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
SLES-52882:
|
||||
name: "Stolen"
|
||||
region: "PAL-M5"
|
||||
|
@ -31346,6 +31347,7 @@ SLPM-65913:
|
|||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes blurriness.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
SLPM-65914:
|
||||
name: "Nana"
|
||||
region: "NTSC-J"
|
||||
|
@ -34169,6 +34171,7 @@ SLPM-66638:
|
|||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes blurriness.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
SLPM-66639:
|
||||
name: "Street Fighter III - 3rd Strike [Capcom the Best]"
|
||||
region: "NTSC-J"
|
||||
|
@ -46709,6 +46712,7 @@ SLUS-21075:
|
|||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes blurriness.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
SLUS-21076:
|
||||
name: "Atari Anthology"
|
||||
region: "NTSC-U"
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#define PS_LTF 1
|
||||
#define PS_TCOFFSETHACK 0
|
||||
#define PS_POINT_SAMPLER 0
|
||||
#define PS_REGION_RECT 0
|
||||
#define PS_SHUFFLE 0
|
||||
#define PS_READ_BA 0
|
||||
#define PS_READ16_SRC 0
|
||||
|
@ -178,6 +179,8 @@ float4 sample_c(float2 uv, float uv_w)
|
|||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return RtTexture.Load(int3(int2(uv * WH.zw), 0));
|
||||
#elif PS_REGION_RECT == 1
|
||||
return Texture.Load(int3(int2(uv), 0));
|
||||
#else
|
||||
if (PS_POINT_SAMPLER)
|
||||
{
|
||||
|
@ -241,7 +244,15 @@ float4 clamp_wrap_uv(float4 uv)
|
|||
|
||||
if(PS_WMS == PS_WMT)
|
||||
{
|
||||
if(PS_WMS == 2)
|
||||
if(PS_REGION_RECT != 0 && PS_WMS == 0)
|
||||
{
|
||||
uv = frac(uv);
|
||||
}
|
||||
else if(PS_REGION_RECT != 0 && PS_WMS == 1)
|
||||
{
|
||||
uv = saturate(uv);
|
||||
}
|
||||
else if(PS_WMS == 2)
|
||||
{
|
||||
uv = clamp(uv, MinMax.xyxy, MinMax.zwzw);
|
||||
}
|
||||
|
@ -257,7 +268,15 @@ float4 clamp_wrap_uv(float4 uv)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(PS_WMS == 2)
|
||||
if(PS_REGION_RECT != 0 && PS_WMS == 0)
|
||||
{
|
||||
uv.xz = frac(uv.xz);
|
||||
}
|
||||
else if(PS_REGION_RECT != 0 && PS_WMS == 1)
|
||||
{
|
||||
uv.xz = saturate(uv.xz);
|
||||
}
|
||||
else if(PS_WMS == 2)
|
||||
{
|
||||
uv.xz = clamp(uv.xz, MinMax.xx, MinMax.zz);
|
||||
}
|
||||
|
@ -268,7 +287,15 @@ float4 clamp_wrap_uv(float4 uv)
|
|||
#endif
|
||||
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & asuint(MinMax.xx)) | asuint(MinMax.zz)) / tex_size.xx;
|
||||
}
|
||||
if(PS_WMT == 2)
|
||||
if(PS_REGION_RECT != 0 && PS_WMT == 0)
|
||||
{
|
||||
uv.yw = frac(uv.yw);
|
||||
}
|
||||
else if(PS_REGION_RECT != 0 && PS_WMT == 1)
|
||||
{
|
||||
uv.yw = saturate(uv.yw);
|
||||
}
|
||||
else if(PS_WMT == 2)
|
||||
{
|
||||
uv.yw = clamp(uv.yw, MinMax.yy, MinMax.ww);
|
||||
}
|
||||
|
@ -281,6 +308,12 @@ float4 clamp_wrap_uv(float4 uv)
|
|||
}
|
||||
}
|
||||
|
||||
if(PS_REGION_RECT != 0)
|
||||
{
|
||||
// Normalized -> Integer Coordinates.
|
||||
uv = clamp(uv * WH.zwzw + STRange.xyxy, STRange.xyxy, STRange.zwzw);
|
||||
}
|
||||
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
@ -564,7 +597,7 @@ float4 sample_color(float2 st, float uv_w)
|
|||
float4x4 c;
|
||||
float2 dd;
|
||||
|
||||
if (PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_WMS < 2 && PS_WMT < 2)
|
||||
if (PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_REGION_RECT == 0 && PS_WMS < 2 && PS_WMT < 2)
|
||||
{
|
||||
c[0] = sample_c(st, uv_w);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,8 @@ vec4 sample_c(vec2 uv)
|
|||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return fetch_rt();
|
||||
#elif PS_REGION_RECT
|
||||
return texelFetch(TextureSampler, ivec2(uv), 0);
|
||||
#else
|
||||
|
||||
#if PS_POINT_SAMPLER
|
||||
|
@ -163,7 +165,11 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
|
||||
#if PS_WMS == PS_WMT
|
||||
|
||||
#if PS_WMS == 2
|
||||
#if PS_REGION_RECT == 1 && PS_WMS == 0
|
||||
uv_out = fract(uv);
|
||||
#elif PS_REGION_RECT == 1 && PS_WMS == 1
|
||||
uv_out = clamp(uv, vec4(0.0f), vec4(1.0f));
|
||||
#elif PS_WMS == 2
|
||||
uv_out = clamp(uv, MinMax.xyxy, MinMax.zwzw);
|
||||
#elif PS_WMS == 3
|
||||
#if PS_FST == 0
|
||||
|
@ -176,7 +182,13 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
|
||||
#else // PS_WMS != PS_WMT
|
||||
|
||||
#if PS_WMS == 2
|
||||
#if PS_REGION_RECT == 1 && PS_WMS == 0
|
||||
uv.xz = fract(uv.xz);
|
||||
|
||||
#elif PS_REGION_RECT == 1 && PS_WMS == 1
|
||||
uv.xz = clamp(uv.xz, vec2(0.0f), vec2(1.0f));
|
||||
|
||||
#elif PS_WMS == 2
|
||||
uv_out.xz = clamp(uv.xz, MinMax.xx, MinMax.zz);
|
||||
|
||||
#elif PS_WMS == 3
|
||||
|
@ -187,7 +199,13 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
|
||||
#endif
|
||||
|
||||
#if PS_WMT == 2
|
||||
#if PS_REGION_RECT == 1 && PS_WMT == 0
|
||||
uv_out.yw = fract(uv.yw);
|
||||
|
||||
#elif PS_REGION_RECT == 1 && PS_WMT == 1
|
||||
uv_out.yw = clamp(uv.yw, vec2(0.0f), vec2(1.0f));
|
||||
|
||||
#elif PS_WMT == 2
|
||||
uv_out.yw = clamp(uv.yw, MinMax.yy, MinMax.ww);
|
||||
|
||||
#elif PS_WMT == 3
|
||||
|
@ -197,6 +215,11 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if PS_REGION_RECT == 1
|
||||
// Normalized -> Integer Coordinates.
|
||||
uv_out = clamp(uv_out * WH.zwzw + STRange.xyxy, STRange.xyxy, STRange.zwzw);
|
||||
#endif
|
||||
|
||||
return uv_out;
|
||||
|
@ -473,7 +496,7 @@ vec4 sample_color(vec2 st)
|
|||
vec2 dd;
|
||||
|
||||
// FIXME I'm not sure this condition is useful (I think code will be optimized)
|
||||
#if (PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_WMS < 2 && PS_WMT < 2)
|
||||
#if (PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_REGION_RECT == 0 && PS_WMS < 2 && PS_WMT < 2)
|
||||
// No software LTF and pure 32 bits RGBA texure without special texture wrapping
|
||||
c[0] = sample_c(st);
|
||||
#ifdef TEX_COORD_DEBUG
|
||||
|
|
|
@ -415,6 +415,8 @@ vec4 sample_c(vec2 uv)
|
|||
{
|
||||
#if PS_TEX_IS_FB
|
||||
return sample_from_rt();
|
||||
#elif PS_REGION_RECT
|
||||
return texelFetch(Texture, ivec2(uv), 0);
|
||||
#else
|
||||
#if PS_POINT_SAMPLER
|
||||
// Weird issue with ATI/AMD cards,
|
||||
|
@ -477,7 +479,15 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
|
||||
#if PS_WMS == PS_WMT
|
||||
{
|
||||
#if PS_WMS == 2
|
||||
#if PS_REGION_RECT == 1 && PS_WMS == 0
|
||||
{
|
||||
uv = fract(uv);
|
||||
}
|
||||
#elif PS_REGION_RECT == 1 && PS_WMS == 1
|
||||
{
|
||||
uv = clamp(uv, vec4(0.0f), vec4(1.0f));
|
||||
}
|
||||
#elif PS_WMS == 2
|
||||
{
|
||||
uv = clamp(uv, MinMax.xyxy, MinMax.zwzw);
|
||||
}
|
||||
|
@ -494,7 +504,15 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
}
|
||||
#else
|
||||
{
|
||||
#if PS_WMS == 2
|
||||
#if PS_REGION_RECT == 1 && PS_WMS == 0
|
||||
{
|
||||
uv.xz = fract(uv.xz);
|
||||
}
|
||||
#elif PS_REGION_RECT == 1 && PS_WMS == 1
|
||||
{
|
||||
uv.xz = clamp(uv.xz, vec2(0.0f), vec2(1.0f));
|
||||
}
|
||||
#elif PS_WMS == 2
|
||||
{
|
||||
uv.xz = clamp(uv.xz, MinMax.xx, MinMax.zz);
|
||||
}
|
||||
|
@ -506,7 +524,15 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
|
||||
}
|
||||
#endif
|
||||
#if PS_WMT == 2
|
||||
#if PS_REGION_RECT == 1 && PS_WMT == 0
|
||||
{
|
||||
uv.yw = fract(uv.yw);
|
||||
}
|
||||
#elif PS_REGION_RECT == 1 && PS_WMT == 1
|
||||
{
|
||||
uv.yw = clamp(uv.yw, vec2(0.0f), vec2(1.0f));
|
||||
}
|
||||
#elif PS_WMT == 2
|
||||
{
|
||||
uv.yw = clamp(uv.yw, MinMax.yy, MinMax.ww);
|
||||
}
|
||||
|
@ -521,6 +547,11 @@ vec4 clamp_wrap_uv(vec4 uv)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if PS_REGION_RECT == 1
|
||||
// Normalized -> Integer Coordinates.
|
||||
uv = clamp(uv * WH.zwzw + STRange.xyxy, STRange.xyxy, STRange.zwzw);
|
||||
#endif
|
||||
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
@ -797,7 +828,7 @@ vec4 sample_color(vec2 st)
|
|||
mat4 c;
|
||||
vec2 dd;
|
||||
|
||||
#if PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_WMS < 2 && PS_WMT < 2
|
||||
#if PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_REGION_RECT == 0 && PS_WMS < 2 && PS_WMT < 2
|
||||
{
|
||||
c[0] = sample_c(st);
|
||||
}
|
||||
|
|
|
@ -282,7 +282,7 @@ bool GSreopen(bool recreate_display, bool recreate_renderer, const Pcsx2Config::
|
|||
if (recreate_display)
|
||||
{
|
||||
g_gs_device->ResetAPIState();
|
||||
if (Host::BeginPresentFrame(false) == HostDisplay::PresentResult::OK)
|
||||
if (Host::BeginPresentFrame(true) == HostDisplay::PresentResult::OK)
|
||||
Host::EndPresentFrame();
|
||||
}
|
||||
|
||||
|
@ -643,12 +643,12 @@ void GSgetStats(std::string& info)
|
|||
|
||||
void GSgetMemoryStats(std::string& info)
|
||||
{
|
||||
if (GSConfig.Renderer == GSRendererType::SW || GSConfig.Renderer == GSRendererType::Null)
|
||||
if (!g_texture_cache)
|
||||
return;
|
||||
|
||||
const u64 targets = GSRendererHW::GetInstance()->GetTextureCache()->GetTargetMemoryUsage();
|
||||
const u64 sources = GSRendererHW::GetInstance()->GetTextureCache()->GetSourceMemoryUsage();
|
||||
const u64 hashcache = GSRendererHW::GetInstance()->GetTextureCache()->GetHashCacheMemoryUsage();
|
||||
const u64 targets = g_texture_cache->GetTargetMemoryUsage();
|
||||
const u64 sources = g_texture_cache->GetSourceMemoryUsage();
|
||||
const u64 hashcache = g_texture_cache->GetHashCacheMemoryUsage();
|
||||
const u64 pool = g_gs_device->GetPoolMemoryUsage();
|
||||
const u64 total = targets + sources + hashcache + pool;
|
||||
|
||||
|
|
|
@ -24,11 +24,6 @@ const CRC::Game CRC::m_games[] =
|
|||
{
|
||||
// Note: IDs 0x7ACF7E03, 0x7D4EA48F, 0x37C53760 - shouldn't be added as it's from the multiloaders when packing games.
|
||||
{0x00000000, NoTitle /* NoRegion */},
|
||||
{0x08C1ED4D, HauntingGround /* EU */},
|
||||
{0x2CD5794C, HauntingGround /* EU */},
|
||||
{0x867BB945, HauntingGround /* JP */},
|
||||
{0xE263BC4B, HauntingGround /* JP */},
|
||||
{0x901AAC09, HauntingGround /* US */},
|
||||
{0x6F8545DB, ICO /* US */},
|
||||
{0x48CDF317, ICO /* US */}, // Demo
|
||||
{0xB01A4C95, ICO /* JP */},
|
||||
|
|
|
@ -24,7 +24,6 @@ public:
|
|||
{
|
||||
NoTitle,
|
||||
GetawayGames,
|
||||
HauntingGround,
|
||||
ICO,
|
||||
KOF2002,
|
||||
PolyphonyDigitalGames,
|
||||
|
|
|
@ -3357,7 +3357,7 @@ static bool UsesRegionRepeat(int fix, int msk, int min, int max, int* min_out, i
|
|||
return sets_bits || clears_bits;
|
||||
}
|
||||
|
||||
GSState::TextureMinMaxResult GSState::GetTextureMinMax(const GIFRegTEX0& TEX0, const GIFRegCLAMP& CLAMP, bool linear)
|
||||
GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCLAMP CLAMP, bool linear, bool clamp_to_tsize)
|
||||
{
|
||||
// TODO: some of the +1s can be removed if linear == false
|
||||
|
||||
|
@ -3366,21 +3366,18 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(const GIFRegTEX0& TEX0, c
|
|||
|
||||
const int w = 1 << tw;
|
||||
const int h = 1 << th;
|
||||
const int tw_mask = w - 1;
|
||||
const int th_mask = h - 1;
|
||||
const int tw_mask = (1 << tw) - 1;
|
||||
const int th_mask = (1 << th) - 1;
|
||||
|
||||
const GSVector4i tr(0, 0, w, h);
|
||||
GSVector4i tr(0, 0, w, h);
|
||||
|
||||
const int wms = CLAMP.WMS;
|
||||
const int wmt = CLAMP.WMT;
|
||||
|
||||
const int minu = (int)CLAMP.MINU;
|
||||
const int minv = (int)CLAMP.MINV;
|
||||
|
||||
// For the FixedTEX0 case, in hardware, we handle this in the texture cache. Don't OR the bits in here, otherwise
|
||||
// we'll end up with an invalid rectangle, we want the passed-in rectangle to be relative to the normalized size.
|
||||
const int maxu = (wms != CLAMP_REGION_REPEAT || (int)CLAMP.MAXU < w) ? (int)CLAMP.MAXU : 0;
|
||||
const int maxv = (wmt != CLAMP_REGION_REPEAT || (int)CLAMP.MAXV < h) ? (int)CLAMP.MAXV : 0;
|
||||
const int maxu = (int)CLAMP.MAXU;
|
||||
const int maxv = (int)CLAMP.MAXV;
|
||||
|
||||
GSVector4i vr = tr;
|
||||
|
||||
|
@ -3391,10 +3388,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(const GIFRegTEX0& TEX0, c
|
|||
case CLAMP_CLAMP:
|
||||
break;
|
||||
case CLAMP_REGION_CLAMP:
|
||||
if (vr.x < minu)
|
||||
vr.x = minu;
|
||||
if (vr.z > maxu + 1)
|
||||
vr.z = maxu + 1;
|
||||
vr.x = minu;
|
||||
vr.z = maxu + 1;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
vr.x = maxu;
|
||||
|
@ -3411,10 +3406,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(const GIFRegTEX0& TEX0, c
|
|||
case CLAMP_CLAMP:
|
||||
break;
|
||||
case CLAMP_REGION_CLAMP:
|
||||
if (vr.y < minv)
|
||||
vr.y = minv;
|
||||
if (vr.w > maxv + 1)
|
||||
vr.w = maxv + 1;
|
||||
vr.y = minv;
|
||||
vr.w = maxv + 1;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
vr.y = maxv;
|
||||
|
@ -3424,6 +3417,13 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(const GIFRegTEX0& TEX0, c
|
|||
__assume(0);
|
||||
}
|
||||
|
||||
// Software renderer fixes TEX0 so that TW/TH contain MAXU/MAXV.
|
||||
// Hardware renderer doesn't, and handles it in the texture cache, so don't clamp here.
|
||||
if (clamp_to_tsize)
|
||||
vr = vr.rintersect(tr);
|
||||
else
|
||||
tr = tr.runion(vr);
|
||||
|
||||
u8 uses_border = 0;
|
||||
|
||||
if (m_vt.m_max.t.x >= FLT_MAX || m_vt.m_min.t.x <= -FLT_MAX ||
|
||||
|
@ -3886,6 +3886,33 @@ GIFRegTEX0 GSState::GetTex0Layer(u32 lod)
|
|||
return TEX0;
|
||||
}
|
||||
|
||||
bool GSState::IsTBPFrameOrZ(u32 tbp) const
|
||||
{
|
||||
GSDrawingContext* context = m_context;
|
||||
const bool is_frame = (context->FRAME.Block() == tbp);
|
||||
const bool is_z = (context->ZBUF.Block() == tbp);
|
||||
if (!is_frame && !is_z)
|
||||
return false;
|
||||
|
||||
const u32 fm = context->FRAME.FBMSK;
|
||||
const u32 zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
|
||||
const u32 fm_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk;
|
||||
|
||||
const u32 max_z = (0xFFFFFFFF >> (GSLocalMemory::m_psm[context->ZBUF.PSM].fmt * 8));
|
||||
const bool no_rt = (context->ALPHA.IsCd() && PRIM->ABE && (context->FRAME.PSM == 1))
|
||||
|| (!context->TEST.DATE && (context->FRAME.FBMSK & GSLocalMemory::m_psm[context->FRAME.PSM].fmsk) == GSLocalMemory::m_psm[context->FRAME.PSM].fmsk);
|
||||
const bool no_ds = (
|
||||
// Depth is always pass/fail (no read) and write are discarded.
|
||||
(zm != 0 && context->TEST.ZTST <= ZTST_ALWAYS) ||
|
||||
// Depth test will always pass
|
||||
(zm != 0 && context->TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[0].XYZ.Z, max_z) == max_z) ||
|
||||
// Depth will be written through the RT
|
||||
(!no_rt && context->FRAME.FBP == context->ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && context->TEST.ZTE));
|
||||
|
||||
// Relying a lot on the optimizer here... I don't like it.
|
||||
return (is_frame && !no_rt) || (is_z && !no_ds);
|
||||
}
|
||||
|
||||
// GSTransferBuffer
|
||||
|
||||
GSState::GSTransferBuffer::GSTransferBuffer()
|
||||
|
|
|
@ -199,7 +199,7 @@ protected:
|
|||
GSVector4i coverage; ///< Part of the texture used
|
||||
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(GIFRegTEX0 TEX0, GIFRegCLAMP CLAMP, bool linear, bool clamp_to_tsize);
|
||||
bool TryAlphaTest(u32& fm, const u32 fm_mask, u32& zm);
|
||||
bool IsOpaque();
|
||||
bool IsMipMapDraw();
|
||||
|
@ -918,4 +918,7 @@ public:
|
|||
|
||||
PRIM_OVERLAP PrimitiveOverlap();
|
||||
GIFRegTEX0 GetTex0Layer(u32 lod);
|
||||
|
||||
/// Returns true if the specified texture address matches the frame or Z buffer.
|
||||
bool IsTBPFrameOrZ(u32 tbp) const;
|
||||
};
|
||||
|
|
|
@ -449,11 +449,22 @@ bool GSDevice::ResizeTexture(GSTexture** t, GSTexture::Type type, int w, int h,
|
|||
{
|
||||
const GSTexture::Format fmt = t2 ? t2->GetFormat() : GetDefaultTextureFormat(type);
|
||||
const int levels = t2 ? (t2->IsMipmap() ? MipmapLevelsForSize(w, h) : 1) : 1;
|
||||
delete t2;
|
||||
|
||||
t2 = FetchSurface(type, w, h, levels, fmt, clear, prefer_reuse);
|
||||
GSTexture* new_t = FetchSurface(type, w, h, levels, fmt, clear, prefer_reuse);
|
||||
if (new_t)
|
||||
{
|
||||
if (t2)
|
||||
{
|
||||
// TODO: We probably want to make this optional if we're overwriting it...
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, t2->GetWidth(), t2->GetHeight());
|
||||
StretchRect(m_current, sRect, new_t, dRect, ShaderConvert::COPY, true);
|
||||
Recycle(t2);
|
||||
}
|
||||
|
||||
*t = t2;
|
||||
t2 = new_t;
|
||||
*t = t2;
|
||||
}
|
||||
}
|
||||
|
||||
return t2 != NULL;
|
||||
|
|
|
@ -296,7 +296,6 @@ struct alignas(16) GSHWDrawConfig
|
|||
{
|
||||
struct
|
||||
{
|
||||
// *** Word 1
|
||||
// Format
|
||||
u32 aem_fmt : 2;
|
||||
u32 pal_fmt : 2;
|
||||
|
@ -328,9 +327,6 @@ struct alignas(16) GSHWDrawConfig
|
|||
u32 write_rg : 1;
|
||||
u32 fbmask : 1;
|
||||
|
||||
//u32 _free1:0;
|
||||
|
||||
// *** Word 2
|
||||
// Blend and Colclip
|
||||
u32 blend_a : 2;
|
||||
u32 blend_b : 2;
|
||||
|
@ -366,6 +362,7 @@ struct alignas(16) GSHWDrawConfig
|
|||
u32 automatic_lod : 1;
|
||||
u32 manual_lod : 1;
|
||||
u32 point_sampler : 1;
|
||||
u32 region_rect : 1;
|
||||
|
||||
// Scan mask
|
||||
u32 scanmsk : 2;
|
||||
|
@ -862,6 +859,9 @@ public:
|
|||
/// Converts a colour format to an indexed format texture.
|
||||
virtual void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) {}
|
||||
|
||||
/// Converts a colour format to an indexed format texture.
|
||||
virtual void ConvertToIndexedTexture(GSTexture* sTex, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) {}
|
||||
|
||||
virtual void RenderHW(GSHWDrawConfig& config) {}
|
||||
|
||||
__fi FeatureSupport Features() const { return m_features; }
|
||||
|
|
|
@ -91,7 +91,6 @@ public:
|
|||
virtual void GenerateMipmap() {}
|
||||
virtual bool Save(const std::string& fn);
|
||||
virtual void Swap(GSTexture* tex);
|
||||
virtual u32 GetID() { return 0; }
|
||||
|
||||
__fi int GetWidth() const { return m_size.x; }
|
||||
__fi int GetHeight() const { return m_size.y; }
|
||||
|
|
|
@ -1458,7 +1458,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
PSSetShaderResources(config.tex, config.pal);
|
||||
|
||||
GSTexture* rt_copy = nullptr;
|
||||
GSTexture* ds_copy = nullptr;
|
||||
if (config.require_one_barrier || (config.tex && config.tex == config.rt)) // Used as "bind rt" flag when texture barrier is unsupported
|
||||
{
|
||||
// Bind the RT.This way special effect can use it.
|
||||
|
@ -1475,15 +1474,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
if (config.tex && config.tex == config.ds)
|
||||
{
|
||||
// mainly for ico (depth buffer used as texture)
|
||||
// binding to 0 here is safe, because config.tex can't equal both tex and rt
|
||||
CloneTexture(config.ds, &ds_copy, config.drawarea);
|
||||
if (ds_copy)
|
||||
PSSetShaderResource(0, ds_copy);
|
||||
}
|
||||
|
||||
SetupVS(config.vs, &config.cb_vs);
|
||||
SetupGS(config.gs);
|
||||
SetupPS(config.ps, &config.cb_ps, config.sampler);
|
||||
|
@ -1556,8 +1546,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
|||
|
||||
if (rt_copy)
|
||||
Recycle(rt_copy);
|
||||
if (ds_copy)
|
||||
Recycle(ds_copy);
|
||||
if (primid_tex)
|
||||
Recycle(primid_tex);
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
|
|||
sm.AddMacro("PS_LTF", sel.ltf);
|
||||
sm.AddMacro("PS_TCOFFSETHACK", sel.tcoffsethack);
|
||||
sm.AddMacro("PS_POINT_SAMPLER", sel.point_sampler);
|
||||
sm.AddMacro("PS_REGION_RECT", sel.region_rect);
|
||||
sm.AddMacro("PS_SHUFFLE", sel.shuffle);
|
||||
sm.AddMacro("PS_READ_BA", sel.read_ba);
|
||||
sm.AddMacro("PS_READ16_SRC", sel.real16src);
|
||||
|
|
|
@ -1622,6 +1622,7 @@ const ID3DBlob* GSDevice12::GetTFXPixelShader(const GSHWDrawConfig::PSSelector&
|
|||
sm.AddMacro("PS_LTF", sel.ltf);
|
||||
sm.AddMacro("PS_TCOFFSETHACK", sel.tcoffsethack);
|
||||
sm.AddMacro("PS_POINT_SAMPLER", sel.point_sampler);
|
||||
sm.AddMacro("PS_REGION_RECT", sel.region_rect);
|
||||
sm.AddMacro("PS_SHUFFLE", sel.shuffle);
|
||||
sm.AddMacro("PS_READ_BA", sel.read_ba);
|
||||
sm.AddMacro("PS_READ16_SRC", sel.real16src);
|
||||
|
@ -2582,7 +2583,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
|
||||
GSTexture12* draw_rt_clone = nullptr;
|
||||
GSTexture12* hdr_rt = nullptr;
|
||||
GSTexture12* copy_ds = nullptr;
|
||||
|
||||
// Switch to hdr target for colclip rendering
|
||||
if (pipe.ps.hdr)
|
||||
|
@ -2634,30 +2634,9 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
if (config.tex)
|
||||
{
|
||||
if (config.tex == config.ds)
|
||||
{
|
||||
// requires a copy of the depth buffer. this is mainly for ico.
|
||||
copy_ds = static_cast<GSTexture12*>(CreateDepthStencil(rtsize.x, rtsize.y, GSTexture::Format::DepthStencil, false));
|
||||
if (copy_ds)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
GL_PUSH("Copy depth to temp texture for shuffle {%d,%d %dx%d}",
|
||||
config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
|
||||
pxAssert(copy_ds->GetState() == GSTexture::State::Invalidated);
|
||||
CopyRect(config.ds, copy_ds, GSVector4i(config.ds->GetSize()).zwxy(), 0, 0);
|
||||
PSSetShaderResource(0, copy_ds, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear texture binding when it's bound to RT or DS
|
||||
else if (m_tfx_textures[0] &&
|
||||
((config.rt && static_cast<GSTexture12*>(config.rt)->GetSRVDescriptor() == m_tfx_textures[0]) ||
|
||||
(config.ds && static_cast<GSTexture12*>(config.ds)->GetSRVDescriptor() == m_tfx_textures[0])))
|
||||
if (((config.rt && static_cast<GSTexture12*>(config.rt)->GetSRVDescriptor() == m_tfx_textures[0]) ||
|
||||
(config.ds && static_cast<GSTexture12*>(config.ds)->GetSRVDescriptor() == m_tfx_textures[0])))
|
||||
{
|
||||
PSSetShaderResource(0, nullptr, false);
|
||||
}
|
||||
|
@ -2748,9 +2727,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
if (copy_ds)
|
||||
Recycle(copy_ds);
|
||||
|
||||
if (draw_rt_clone)
|
||||
Recycle(draw_rt_clone);
|
||||
|
||||
|
|
|
@ -110,6 +110,9 @@ bool GSHwHack::GSC_Manhunt2(GSRendererHW& r, const GSFrameInfo& fi, int& skip)
|
|||
|
||||
bool GSHwHack::GSC_CrashBandicootWoC(GSRendererHW& r, const GSFrameInfo& fi, int& skip)
|
||||
{
|
||||
if (s_nativeres)
|
||||
return false;
|
||||
|
||||
// Channel effect not properly supported - Removes fog to fix the fog wall issue on Direct3D at any resolution, and while upscaling on every Hardware renderer.
|
||||
if (skip == 0)
|
||||
{
|
||||
|
@ -548,6 +551,18 @@ bool GSHwHack::GSC_UrbanReign(GSRendererHW& r, const GSFrameInfo& fi, int& skip)
|
|||
{
|
||||
skip = 1; // Black shadow
|
||||
}
|
||||
|
||||
// Urban Reign downsamples the framebuffer with page-wide columns at a time, and offsets the TBP0 forward as such,
|
||||
// which would be fine, except their texture coordinates appear to be off by one. Which prevents the page translation
|
||||
// from matching the last column, because it's trying to fit the last 65 columns of a 640x448 (effectively 641x448)
|
||||
// texture into a 640x448 render target.
|
||||
if (fi.TME && fi.TBP0 != fi.FBP && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMCT32 &&
|
||||
RCONTEXT->FRAME.FBW == (RCONTEXT->TEX0.TBW / 2) && RCONTEXT->CLAMP.WMS == CLAMP_REGION_CLAMP &&
|
||||
RCONTEXT->CLAMP.WMT == CLAMP_REGION_CLAMP && ((r.m_vt.m_max.t == GSVector4(64.0f, 448.0f)).mask() == 0x3))
|
||||
{
|
||||
GL_CACHE("GSC_UrbanReign: Fix region clamp to 64 wide");
|
||||
r.m_context->CLAMP.MAXU = 63;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -810,7 +825,7 @@ bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds
|
|||
const u32 c = vi.RGBAQ.U32[0];
|
||||
r.m_mem.WritePixel32(x, y, c, FBP, FBW);
|
||||
}
|
||||
r.m_tc->InvalidateVideoMem(r.m_context->offset.fb, r.m_r);
|
||||
g_texture_cache->InvalidateVideoMem(r.m_context->offset.fb, r.m_r);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -981,7 +996,7 @@ bool GSHwHack::OI_RozenMaidenGebetGarden(GSRendererHW& r, GSTexture* rt, GSTextu
|
|||
TEX0.TBW = RCONTEXT->FRAME.FBW;
|
||||
TEX0.PSM = RCONTEXT->FRAME.PSM;
|
||||
|
||||
if (GSTextureCache::Target* tmp_rt = r.m_tc->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true))
|
||||
if (GSTextureCache::Target* tmp_rt = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true))
|
||||
{
|
||||
GL_INS("OI_RozenMaidenGebetGarden FB clear");
|
||||
g_gs_device->ClearRenderTarget(tmp_rt->m_texture, 0);
|
||||
|
@ -999,7 +1014,7 @@ bool GSHwHack::OI_RozenMaidenGebetGarden(GSRendererHW& r, GSTexture* rt, GSTextu
|
|||
TEX0.TBW = RCONTEXT->FRAME.FBW;
|
||||
TEX0.PSM = RCONTEXT->ZBUF.PSM;
|
||||
|
||||
if (GSTextureCache::Target* tmp_ds = r.m_tc->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil, true))
|
||||
if (GSTextureCache::Target* tmp_ds = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil, true))
|
||||
{
|
||||
GL_INS("OI_RozenMaidenGebetGarden ZB clear");
|
||||
g_gs_device->ClearDepth(tmp_ds->m_texture);
|
||||
|
@ -1032,7 +1047,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
|||
|
||||
GL_INS("OI_SonicUnleashed replace draw by a copy");
|
||||
|
||||
GSTextureCache::Target* src = r.m_tc->LookupTarget(Texture, GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true);
|
||||
GSTextureCache::Target* src = g_texture_cache->LookupTarget(Texture, GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true);
|
||||
|
||||
const GSVector2i src_size(src->m_texture->GetSize());
|
||||
GSVector2i rt_size(rt->GetSize());
|
||||
|
@ -1040,7 +1055,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
|||
// This is awful, but so is the CRC hack... it's a texture shuffle split horizontally instead of vertically.
|
||||
if (rt_size.x < src_size.x || rt_size.y < src_size.y)
|
||||
{
|
||||
GSTextureCache::Target* rt_again = r.m_tc->LookupTarget(Frame, src_size, src->m_scale, GSTextureCache::RenderTarget, true);
|
||||
GSTextureCache::Target* rt_again = g_texture_cache->LookupTarget(Frame, src_size, src->m_scale, GSTextureCache::RenderTarget, true);
|
||||
if (rt_again->m_unscaled_size.x < src->m_unscaled_size.x || rt_again->m_unscaled_size.y < src->m_unscaled_size.y)
|
||||
{
|
||||
rt_again->ResizeTexture(std::max(rt_again->m_unscaled_size.x, src->m_unscaled_size.x),
|
||||
|
@ -1122,7 +1137,7 @@ bool GSHwHack::GSC_Battlefield2(GSRendererHW& r, const GSFrameInfo& fi, int& ski
|
|||
GIFRegTEX0 TEX0 = {};
|
||||
TEX0.TBP0 = fi.FBP;
|
||||
TEX0.TBW = 8;
|
||||
GSTextureCache::Target* dst = r.m_tc->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil, true);
|
||||
GSTextureCache::Target* dst = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil, true);
|
||||
if (dst)
|
||||
{
|
||||
g_gs_device->ClearDepth(dst->m_texture);
|
||||
|
@ -1144,10 +1159,25 @@ bool GSHwHack::OI_Battlefield2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GS
|
|||
g_gs_device->CopyRect(t->m_texture, rt, rc, 0, 0);
|
||||
}
|
||||
|
||||
r.m_tc->InvalidateTemporarySource();
|
||||
g_texture_cache->InvalidateTemporarySource();
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
// This currently isn't handled in our HLE clears, so we need to manually remove the other target.
|
||||
if (rt && !ds && !t && r.IsConstantDirectWriteMemClear(true))
|
||||
{
|
||||
GL_CACHE("GSHwHack::OI_HauntingGround()");
|
||||
g_texture_cache->InvalidateVideoMemTargets(GSTextureCache::RenderTarget, RCONTEXT->FRAME.Block(),
|
||||
RCONTEXT->FRAME.FBW, RCONTEXT->FRAME.PSM, r.m_r);
|
||||
}
|
||||
|
||||
// Not skipping anything. This is just an invalidation hack.
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef RCONTEXT
|
||||
#undef RPRIM
|
||||
|
||||
|
@ -1224,6 +1254,7 @@ const GSHwHack::Entry<GSRendererHW::OI_Ptr> GSHwHack::s_before_draw_functions[]
|
|||
CRC_F(OI_ArTonelico2, CRCHackLevel::Minimum),
|
||||
CRC_F(OI_BurnoutGames, CRCHackLevel::Minimum),
|
||||
CRC_F(OI_Battlefield2, CRCHackLevel::Minimum),
|
||||
CRC_F(OI_HauntingGround, CRCHackLevel::Minimum)
|
||||
};
|
||||
|
||||
#undef CRC_F
|
||||
|
|
|
@ -62,8 +62,8 @@ public:
|
|||
static bool OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_ArTonelico2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_BurnoutGames(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
||||
static bool OI_Battlefield2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
||||
template <typename F>
|
||||
struct Entry
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -84,14 +84,21 @@ private:
|
|||
template <bool linear>
|
||||
void RoundSpriteOffset();
|
||||
|
||||
void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex);
|
||||
void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm);
|
||||
|
||||
void ResetStates();
|
||||
void SetupIA(float target_scale, float sx, float sy);
|
||||
void EmulateTextureShuffleAndFbmask();
|
||||
void EmulateChannelShuffle(const GSTextureCache::Source* tex);
|
||||
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only);
|
||||
void EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass);
|
||||
void EmulateTextureSampler(const GSTextureCache::Source* tex);
|
||||
|
||||
void EmulateTextureSampler(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
||||
GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTexture*& src_copy);
|
||||
void HandleTextureHazards(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
||||
const GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTextureCache::SourceRegion& source_region,
|
||||
bool& target_region, GSVector2i& unscaled_size, float& scale, GSTexture*& src_copy);
|
||||
bool CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex) const;
|
||||
|
||||
void EmulateZbuffer();
|
||||
void EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2);
|
||||
|
||||
|
@ -101,9 +108,7 @@ private:
|
|||
bool IsSplitTextureShuffle();
|
||||
GSVector4i GetSplitTextureShuffleDrawRect() const;
|
||||
|
||||
GSTextureCache* m_tc;
|
||||
GSVector4i m_r = {};
|
||||
GSTextureCache::Source* m_src = nullptr;
|
||||
|
||||
// CRC Hacks
|
||||
bool IsBadFrame();
|
||||
|
@ -120,7 +125,6 @@ private:
|
|||
u32 m_last_channel_shuffle_fbmsk = 0;
|
||||
bool m_channel_shuffle = false;
|
||||
|
||||
bool m_tex_is_fb = false;
|
||||
bool m_userhacks_tcoffset = false;
|
||||
float m_userhacks_tcoffset_x = 0.0f;
|
||||
float m_userhacks_tcoffset_y = 0.0f;
|
||||
|
@ -143,7 +147,6 @@ public:
|
|||
virtual ~GSRendererHW() override;
|
||||
|
||||
__fi static GSRendererHW* GetInstance() { return static_cast<GSRendererHW*>(g_gs_renderer.get()); }
|
||||
__fi GSTextureCache* GetTextureCache() const { return m_tc; }
|
||||
|
||||
void Destroy() override;
|
||||
|
||||
|
@ -177,9 +180,6 @@ public:
|
|||
void ReadbackTextureCache() override;
|
||||
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size) override;
|
||||
|
||||
// Called by the texture cache to know if current texture is useful
|
||||
bool UpdateTexIsFB(GSTextureCache::Target* src, const GIFRegTEX0& TEX0);
|
||||
|
||||
// Called by the texture cache when optimizing the copy range for sources
|
||||
bool IsPossibleTextureShuffle(GSTextureCache::Target* dst, const GIFRegTEX0& TEX0) const;
|
||||
/// Called by the texture cache to know for certain whether there is a channel shuffle.
|
||||
bool TestChannelShuffle(GSTextureCache::Target* src);
|
||||
};
|
||||
|
|
|
@ -199,7 +199,7 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc)
|
|||
|
||||
GIFRegTEX0 TEX0 = context->GetSizeFixedTEX0(vt.m_min.t.xyxy(vt.m_max.t), vt.IsLinear(), mipmap);
|
||||
|
||||
const GSVector4i r = hw.GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf).coverage;
|
||||
const GSVector4i r = hw.GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf, true).coverage;
|
||||
|
||||
if (!hw.m_sw_texture[0])
|
||||
hw.m_sw_texture[0] = std::make_unique<GSTextureCacheSW::Texture>(0, TEX0, env.TEXA);
|
||||
|
@ -300,7 +300,7 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc)
|
|||
else
|
||||
hw.m_sw_texture[i]->Reset(gd.sel.tw + 3, MIP_TEX0, env.TEXA);
|
||||
|
||||
GSVector4i r = hw.GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf).coverage;
|
||||
GSVector4i r = hw.GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf, true).coverage;
|
||||
hw.m_sw_texture[i]->Update(r);
|
||||
gd.tex[i] = hw.m_sw_texture[i]->m_buff;
|
||||
}
|
||||
|
@ -554,7 +554,7 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc)
|
|||
static_cast<GSSingleRasterizer*>(hw.m_sw_rasterizer.get())->Draw(data);
|
||||
|
||||
if (invalidate_tc)
|
||||
hw.m_tc->InvalidateVideoMem(context->offset.fb, bbox);
|
||||
g_texture_cache->InvalidateVideoMem(context->offset.fb, bbox);
|
||||
|
||||
return true;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -64,10 +64,14 @@ public:
|
|||
u32 GetHeight() const { return (GetMaxY() - GetMinY()); }
|
||||
|
||||
/// Returns true if the area of the region exceeds the TW/TH size (i.e. "fixed tex0").
|
||||
bool IsFixedTEX0(GIFRegTEX0 TEX0) const;
|
||||
bool IsFixedTEX0(int tw, int th) const;
|
||||
bool IsFixedTEX0W(int tw) const;
|
||||
bool IsFixedTEX0H(int th) const;
|
||||
|
||||
/// Returns the size that the region occupies.
|
||||
GSVector2i GetSize(int tw, int th) const;
|
||||
|
||||
/// Returns the rectangle relative to the texture base pointer that the region occupies.
|
||||
GSVector4i GetRect(int tw, int th) const;
|
||||
|
||||
|
@ -80,6 +84,9 @@ public:
|
|||
|
||||
/// Adjusts the texture base pointer and block width relative to the region.
|
||||
void AdjustTEX0(GIFRegTEX0* TEX0) const;
|
||||
|
||||
/// Creates a new source region based on the CLAMP register.
|
||||
static SourceRegion Create(GIFRegTEX0 TEX0, GIFRegCLAMP CLAMP);
|
||||
};
|
||||
|
||||
using HashType = u64;
|
||||
|
@ -146,8 +153,6 @@ public:
|
|||
/// Can be used for overlap tests.
|
||||
u32 UnwrappedEndBlock() const { return (m_end_block + (Wraps() ? MAX_BLOCKS : 0)); }
|
||||
|
||||
void UpdateAge();
|
||||
|
||||
bool Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
|
||||
bool Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
|
||||
};
|
||||
|
@ -196,58 +201,6 @@ public:
|
|||
bool operator()(const PaletteKey& lhs, const PaletteKey& rhs) const;
|
||||
};
|
||||
|
||||
class Source : public Surface
|
||||
{
|
||||
struct
|
||||
{
|
||||
GSVector4i* rect;
|
||||
u32 count;
|
||||
} m_write = {};
|
||||
|
||||
void PreloadLevel(int level);
|
||||
|
||||
void Write(const GSVector4i& r, int layer);
|
||||
void Flush(u32 count, int layer);
|
||||
|
||||
public:
|
||||
HashCacheEntry* m_from_hash_cache = nullptr;
|
||||
std::shared_ptr<Palette> m_palette_obj;
|
||||
std::unique_ptr<u32[]> m_valid;// each u32 bits map to the 32 blocks of that page
|
||||
GSTexture* m_palette = nullptr;
|
||||
GSVector4i m_valid_rect = {};
|
||||
GSVector2i m_lod = {};
|
||||
SourceRegion m_region = {};
|
||||
u8 m_valid_hashes = 0;
|
||||
u8 m_complete_layers = 0;
|
||||
bool m_target = false;
|
||||
bool m_repeating = false;
|
||||
std::vector<GSVector2i>* m_p2t = nullptr;
|
||||
// Keep a trace of the target origin. There is no guarantee that pointer will
|
||||
// still be valid on future. However it ought to be good when the source is created
|
||||
// so it can be used to access un-converted data for the current draw call.
|
||||
GSTexture** m_from_target = nullptr;
|
||||
GIFRegTEX0 m_from_target_TEX0 = {}; // TEX0 of the target texture, if any, else equal to texture TEX0
|
||||
GIFRegTEX0 m_layer_TEX0[7] = {}; // Detect already loaded value
|
||||
HashType m_layer_hash[7] = {};
|
||||
// Keep a GSTextureCache::SourceMap::m_map iterator to allow fast erase
|
||||
// Deliberately not initialized to save cycles.
|
||||
std::array<u16, MAX_PAGES> m_erase_it;
|
||||
GSOffset::PageLooper m_pages;
|
||||
|
||||
public:
|
||||
Source(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
|
||||
virtual ~Source();
|
||||
|
||||
__fi bool CanPreload() const { return CanPreloadTextureSize(m_TEX0.TW, m_TEX0.TH); }
|
||||
|
||||
void SetPages();
|
||||
|
||||
void Update(const GSVector4i& rect, int layer = 0);
|
||||
void UpdateLayer(const GIFRegTEX0& TEX0, const GSVector4i& rect, int layer = 0);
|
||||
|
||||
bool ClutMatch(const PaletteKey& palette_key);
|
||||
};
|
||||
|
||||
class Target : public Surface
|
||||
{
|
||||
public:
|
||||
|
@ -282,6 +235,63 @@ public:
|
|||
bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true);
|
||||
};
|
||||
|
||||
class Source : public Surface
|
||||
{
|
||||
struct
|
||||
{
|
||||
GSVector4i* rect;
|
||||
u32 count;
|
||||
} m_write = {};
|
||||
|
||||
void PreloadLevel(int level);
|
||||
|
||||
void Write(const GSVector4i& r, int layer);
|
||||
void Flush(u32 count, int layer);
|
||||
|
||||
public:
|
||||
HashCacheEntry* m_from_hash_cache = nullptr;
|
||||
std::shared_ptr<Palette> m_palette_obj;
|
||||
std::unique_ptr<u32[]> m_valid;// each u32 bits map to the 32 blocks of that page
|
||||
GSTexture* m_palette = nullptr;
|
||||
GSVector4i m_valid_rect = {};
|
||||
GSVector2i m_lod = {};
|
||||
SourceRegion m_region = {};
|
||||
u8 m_valid_hashes = 0;
|
||||
u8 m_complete_layers = 0;
|
||||
bool m_target = false;
|
||||
bool m_repeating = false;
|
||||
std::vector<GSVector2i>* m_p2t = nullptr;
|
||||
// Keep a trace of the target origin. There is no guarantee that pointer will
|
||||
// still be valid on future. However it ought to be good when the source is created
|
||||
// so it can be used to access un-converted data for the current draw call.
|
||||
Target* m_from_target = nullptr;
|
||||
GIFRegTEX0 m_from_target_TEX0 = {}; // TEX0 of the target texture, if any, else equal to texture TEX0
|
||||
GIFRegTEX0 m_layer_TEX0[7] = {}; // Detect already loaded value
|
||||
HashType m_layer_hash[7] = {};
|
||||
// Keep a GSTextureCache::SourceMap::m_map iterator to allow fast erase
|
||||
// Deliberately not initialized to save cycles.
|
||||
std::array<u16, MAX_PAGES> m_erase_it;
|
||||
GSOffset::PageLooper m_pages;
|
||||
|
||||
public:
|
||||
Source(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
|
||||
virtual ~Source();
|
||||
|
||||
__fi bool CanPreload() const { return CanPreloadTextureSize(m_TEX0.TW, m_TEX0.TH); }
|
||||
__fi bool IsFromTarget() const { return m_target; }
|
||||
|
||||
__fi const SourceRegion& GetRegion() const { return m_region; }
|
||||
__fi GSVector2i GetRegionSize() const { return m_region.GetSize(m_unscaled_size.x, m_unscaled_size.y); }
|
||||
__fi GSVector4i GetRegionRect() const { return m_region.GetRect(m_unscaled_size.x, m_unscaled_size.y); }
|
||||
|
||||
void SetPages();
|
||||
|
||||
void Update(const GSVector4i& rect, int layer = 0);
|
||||
void UpdateLayer(const GIFRegTEX0& TEX0, const GSVector4i& rect, int layer = 0);
|
||||
|
||||
bool ClutMatch(const PaletteKey& palette_key);
|
||||
};
|
||||
|
||||
class PaletteMap
|
||||
{
|
||||
private:
|
||||
|
@ -328,7 +338,7 @@ public:
|
|||
|
||||
struct
|
||||
{
|
||||
u32 fbp : 14;
|
||||
u32 bp : 14;
|
||||
u32 fbw : 6;
|
||||
u32 psm : 6;
|
||||
u32 pad : 6;
|
||||
|
@ -434,20 +444,27 @@ public:
|
|||
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, bool palette = false);
|
||||
|
||||
Target* FindTargetOverlap(u32 bp, u32 end_block, int type, int psm);
|
||||
Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, float scale, int type, bool used, u32 fbmask = 0, const bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool is_clear = false);
|
||||
Target* LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, float scale);
|
||||
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used, u32 fbmask = 0, const bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool is_clear = false);
|
||||
Target* LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale);
|
||||
|
||||
/// Looks up a target in the cache, and only returns it if the BP/BW/PSM match exactly.
|
||||
Target* GetExactTarget(u32 BP, u32 BW, u32 PSM) const;
|
||||
Target* GetTargetWithSharedBits(u32 BP, u32 PSM) const;
|
||||
|
||||
u32 GetTargetHeight(u32 fbp, u32 fbw, u32 psm, u32 min_height);
|
||||
u32 GetTargetHeight(u32 bp, u32 fbw, u32 psm, u32 min_height);
|
||||
bool Has32BitTarget(u32 bp);
|
||||
|
||||
void InvalidateVideoMemType(int type, u32 bp);
|
||||
void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt);
|
||||
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool eewrite = false, bool target = true);
|
||||
void InvalidateLocalMem(const GSOffset& off, const GSVector4i& r);
|
||||
|
||||
/// 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.
|
||||
void InvalidateSourcesFromTarget(const Target* t);
|
||||
|
||||
bool Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u32 DBW, u32 DPSM, int dx, int dy, int w, int h);
|
||||
bool ShuffleMove(u32 BP, u32 BW, u32 PSM, int sx, int sy, int dx, int dy, int w, int h);
|
||||
|
||||
|
@ -470,3 +487,5 @@ public:
|
|||
/// Injects a texture into the hash cache, by using GSTexture::Swap(), transitively applying to all sources. Ownership of tex is transferred.
|
||||
void InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex);
|
||||
};
|
||||
|
||||
extern std::unique_ptr<GSTextureCache> g_texture_cache;
|
||||
|
|
|
@ -130,9 +130,6 @@ namespace GSTextureReplacements
|
|||
|
||||
static std::string s_current_serial;
|
||||
|
||||
/// Backreference to the texture cache so we can inject replacements.
|
||||
static GSTextureCache* s_tc;
|
||||
|
||||
/// Textures that have been dumped, to save stat() calls.
|
||||
static std::unordered_set<TextureName> s_dumped_textures;
|
||||
|
||||
|
@ -302,9 +299,8 @@ std::string GSTextureReplacements::GetDumpFilename(const TextureName& name, u32
|
|||
return ret;
|
||||
}
|
||||
|
||||
void GSTextureReplacements::Initialize(GSTextureCache* tc)
|
||||
void GSTextureReplacements::Initialize()
|
||||
{
|
||||
s_tc = tc;
|
||||
s_current_serial = VMManager::GetGameSerial();
|
||||
|
||||
if (GSConfig.DumpReplaceableTextures || GSConfig.LoadTextureReplacements)
|
||||
|
@ -315,9 +311,6 @@ void GSTextureReplacements::Initialize(GSTextureCache* tc)
|
|||
|
||||
void GSTextureReplacements::GameChanged()
|
||||
{
|
||||
if (!s_tc)
|
||||
return;
|
||||
|
||||
std::string new_serial(VMManager::GetGameSerial());
|
||||
if (s_current_serial == new_serial)
|
||||
return;
|
||||
|
@ -420,7 +413,6 @@ void GSTextureReplacements::Shutdown()
|
|||
std::string().swap(s_current_serial);
|
||||
ClearReplacementTextures();
|
||||
ClearDumpedTextureList();
|
||||
s_tc = nullptr;
|
||||
}
|
||||
|
||||
u32 GSTextureReplacements::CalcMipmapLevelsForReplacement(u32 width, u32 height)
|
||||
|
@ -637,7 +629,7 @@ void GSTextureReplacements::ProcessAsyncLoadedTextures()
|
|||
// upload and inject into TC
|
||||
GSTexture* tex = CreateReplacementTexture(it->second, mipmap);
|
||||
if (tex)
|
||||
s_tc->InjectHashCacheTexture(HashCacheKeyFromTextureName(name), tex);
|
||||
g_texture_cache->InjectHashCacheTexture(HashCacheKeyFromTextureName(name), tex);
|
||||
}
|
||||
s_async_loaded_textures.clear();
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace GSTextureReplacements
|
|||
std::vector<MipData> mips;
|
||||
};
|
||||
|
||||
void Initialize(GSTextureCache* tc);
|
||||
void Initialize();
|
||||
void GameChanged();
|
||||
void ReloadReplacementMap();
|
||||
void UpdateConfig(Pcsx2Config::GSOptions& old_config);
|
||||
|
|
|
@ -1027,6 +1027,7 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
|
|||
+ fmt::format("#define PS_DATE {}\n", sel.date)
|
||||
+ fmt::format("#define PS_TCOFFSETHACK {}\n", sel.tcoffsethack)
|
||||
+ fmt::format("#define PS_POINT_SAMPLER {}\n", sel.point_sampler)
|
||||
+ fmt::format("#define PS_REGION_RECT {}\n", sel.region_rect)
|
||||
+ fmt::format("#define PS_BLEND_A {}\n", sel.blend_a)
|
||||
+ fmt::format("#define PS_BLEND_B {}\n", sel.blend_b)
|
||||
+ fmt::format("#define PS_BLEND_C {}\n", sel.blend_c)
|
||||
|
@ -1164,7 +1165,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
|
|||
// Init
|
||||
// ************************************
|
||||
|
||||
GL_PUSH("StretchRect from %d to %d", sTex->GetID(), dTex->GetID());
|
||||
GL_PUSH("StretchRect from %d to %d", static_cast<GSTextureOGL*>(sTex)->GetID(), static_cast<GSTextureOGL*>(dTex)->GetID());
|
||||
if (draw_in_depth)
|
||||
OMSetRenderTargets(NULL, dTex);
|
||||
else
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
return (m_int_type == GL_UNSIGNED_BYTE || m_int_type == GL_UNSIGNED_SHORT || m_int_type == GL_UNSIGNED_INT);
|
||||
}
|
||||
|
||||
u32 GetID() final { return m_texture_id; }
|
||||
u32 GetID() { return m_texture_id; }
|
||||
bool HasBeenCleaned() { return m_clean; }
|
||||
void WasAttached() { m_clean = false; }
|
||||
void WasCleaned() { m_clean = true; }
|
||||
|
|
|
@ -1065,7 +1065,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
|||
|
||||
GIFRegTEX0 TEX0 = m_context->GetSizeFixedTEX0(m_vt.m_min.t.xyxy(m_vt.m_max.t), m_vt.IsLinear(), mipmap);
|
||||
|
||||
GSVector4i r = GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf).coverage;
|
||||
GSVector4i r = GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf, true).coverage;
|
||||
|
||||
GSTextureCacheSW::Texture* t = m_tc->Lookup(TEX0, env.TEXA);
|
||||
|
||||
|
@ -1171,7 +1171,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
|||
return false;
|
||||
}
|
||||
|
||||
GSVector4i r = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf).coverage;
|
||||
GSVector4i r = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf, true).coverage;
|
||||
|
||||
data->SetSource(t, r, i);
|
||||
}
|
||||
|
|
|
@ -2085,6 +2085,7 @@ VkShaderModule GSDeviceVK::GetTFXFragmentShader(const GSHWDrawConfig::PSSelector
|
|||
AddMacro(ss, "PS_DATE", sel.date);
|
||||
AddMacro(ss, "PS_TCOFFSETHACK", sel.tcoffsethack);
|
||||
AddMacro(ss, "PS_POINT_SAMPLER", sel.point_sampler);
|
||||
AddMacro(ss, "PS_REGION_RECT", sel.region_rect);
|
||||
AddMacro(ss, "PS_BLEND_A", sel.blend_a);
|
||||
AddMacro(ss, "PS_BLEND_B", sel.blend_b);
|
||||
AddMacro(ss, "PS_BLEND_C", sel.blend_c);
|
||||
|
@ -3058,7 +3059,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
GSTextureVK* draw_ds = static_cast<GSTextureVK*>(config.ds);
|
||||
GSTextureVK* draw_rt_clone = nullptr;
|
||||
GSTextureVK* hdr_rt = nullptr;
|
||||
GSTextureVK* copy_ds = nullptr;
|
||||
|
||||
// Switch to hdr target for colclip rendering
|
||||
if (pipe.ps.hdr)
|
||||
|
@ -3109,26 +3109,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
if (config.tex)
|
||||
{
|
||||
if (config.tex == config.ds)
|
||||
{
|
||||
// requires a copy of the depth buffer. this is mainly for ico.
|
||||
copy_ds = static_cast<GSTextureVK*>(CreateDepthStencil(rtsize.x, rtsize.y, GSTexture::Format::DepthStencil, false));
|
||||
if (copy_ds)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
GL_PUSH("Copy depth to temp texture for shuffle {%d,%d %dx%d}",
|
||||
config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
|
||||
pxAssert(copy_ds->GetState() == GSTexture::State::Invalidated);
|
||||
CopyRect(config.ds, copy_ds, GSVector4i(config.ds->GetSize()).zwxy(), 0, 0);
|
||||
PSSetShaderResource(0, copy_ds, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear texture binding when it's bound to RT or DS
|
||||
if (!config.tex && ((config.rt && static_cast<GSTextureVK*>(config.rt)->GetView() == m_tfx_textures[0]) ||
|
||||
(config.ds && static_cast<GSTextureVK*>(config.ds)->GetView() == m_tfx_textures[0])))
|
||||
|
@ -3258,9 +3238,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
|||
}
|
||||
}
|
||||
|
||||
if (copy_ds)
|
||||
Recycle(copy_ds);
|
||||
|
||||
if (draw_rt_clone)
|
||||
Recycle(draw_rt_clone);
|
||||
|
||||
|
|
Loading…
Reference in New Issue