Skip to content

Commit be124ce

Browse files
committed
GS: Add backup texture for preserving upper 8 bits of Z during format conversions.
1 parent 33ab6fd commit be124ce

File tree

9 files changed

+133
-14
lines changed

9 files changed

+133
-14
lines changed

bin/resources/shaders/opengl/convert.glsl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ in vec4 PSin_c;
4040

4141
layout(binding = 0) uniform sampler2D TextureSampler;
4242

43+
#if defined(ps_convert_float32_rgba8_2) || defined(ps_depth_copy_2)
44+
layout(binding = 1) uniform sampler2D TextureSampler2;
45+
#endif
46+
4347
// Give a different name so I remember there is a special case!
4448
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
4549
layout(location = 0) out uint SV_Target1;
@@ -52,6 +56,13 @@ vec4 sample_c()
5256
return texture(TextureSampler, PSin_t);
5357
}
5458

59+
#if defined(ps_convert_float32_rgba8_2) || defined(ps_depth_copy_2)
60+
vec4 sample_c2()
61+
{
62+
return texture(TextureSampler2, PSin_t);
63+
}
64+
#endif
65+
5566
#ifdef ps_copy
5667
void ps_copy()
5768
{
@@ -66,6 +77,15 @@ void ps_depth_copy()
6677
}
6778
#endif
6879

80+
#ifdef ps_depth_copy_2
81+
void ps_depth_copy_2()
82+
{
83+
uint d = clamp(uint(sample_c().r * exp2(32.0f)), 0, 0xFFFFFF);
84+
uint d2 = clamp(uint(sample_c2().r * exp2(8.0f)), 0, 0xFF) << 24;
85+
gl_FragDepth = float(d | d2) * exp2(-32.0f);
86+
}
87+
#endif
88+
6989
#ifdef ps_downsample_copy
7090
uniform ivec2 ClampMin;
7191
uniform int DownsampleFactor;
@@ -111,6 +131,16 @@ void ps_convert_float32_rgba8()
111131
}
112132
#endif
113133

134+
#ifdef ps_convert_float32_rgba8_2
135+
void ps_convert_float32_rgba8_2()
136+
{
137+
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
138+
uint d = uint(sample_c().r * exp2(32.0f));
139+
uint d2 = uint(sample_c2().r * exp2(8.0f));
140+
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), clamp(d2, 0, 0xFFu))) / vec4(255.0);
141+
}
142+
#endif
143+
114144
#ifdef ps_convert_float16_rgb5a1
115145
void ps_convert_float16_rgb5a1()
116146
{

pcsx2/GS/Renderers/Common/GSDevice.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const char* shaderName(ShaderConvert value)
5454
case ShaderConvert::FLOAT32_TO_16_BITS: return "ps_convert_float32_32bits";
5555
case ShaderConvert::FLOAT32_TO_32_BITS: return "ps_convert_float32_32bits";
5656
case ShaderConvert::FLOAT32_TO_RGBA8: return "ps_convert_float32_rgba8";
57+
case ShaderConvert::FLOAT32_TO_RGBA8_2: return "ps_convert_float32_rgba8_2";
5758
case ShaderConvert::FLOAT32_TO_RGB8: return "ps_convert_float32_rgba8";
5859
case ShaderConvert::FLOAT16_TO_RGB5A1: return "ps_convert_float16_rgb5a1";
5960
case ShaderConvert::RGBA8_TO_FLOAT32: return "ps_convert_rgba8_float32";
@@ -66,6 +67,7 @@ const char* shaderName(ShaderConvert value)
6667
case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: return "ps_convert_rgb5a1_float16_biln";
6768
case ShaderConvert::FLOAT32_TO_FLOAT24: return "ps_convert_float32_float24";
6869
case ShaderConvert::DEPTH_COPY: return "ps_depth_copy";
70+
case ShaderConvert::DEPTH_COPY_2: return "ps_depth_copy_2";
6971
case ShaderConvert::DOWNSAMPLE_COPY: return "ps_downsample_copy";
7072
case ShaderConvert::RGBA_TO_8I: return "ps_convert_rgba_8i";
7173
case ShaderConvert::RGB5A1_TO_8I: return "ps_convert_rgb5a1_8i";
@@ -610,6 +612,9 @@ void GSDevice::Recycle(GSTexture* t)
610612

611613
t->SetLastFrameUsed(m_frame);
612614

615+
if (t->HasBackup32BitDepth())
616+
t->RemoveBackup32BitDepth();
617+
613618
FastList<GSTexture*>& pool = m_pool[!t->IsTexture()];
614619
pool.push_front(t);
615620
m_pool_memory_usage += t->GetMemUsage();

pcsx2/GS/Renderers/Common/GSDevice.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum class ShaderConvert
3030
FLOAT32_TO_16_BITS,
3131
FLOAT32_TO_32_BITS,
3232
FLOAT32_TO_RGBA8,
33+
FLOAT32_TO_RGBA8_2,
3334
FLOAT32_TO_RGB8,
3435
FLOAT16_TO_RGB5A1,
3536
RGBA8_TO_FLOAT32,
@@ -42,6 +43,7 @@ enum class ShaderConvert
4243
RGB5A1_TO_FLOAT16_BILN,
4344
FLOAT32_TO_FLOAT24,
4445
DEPTH_COPY,
46+
DEPTH_COPY_2,
4547
DOWNSAMPLE_COPY,
4648
RGBA_TO_8I,
4749
RGB5A1_TO_8I,
@@ -69,6 +71,33 @@ enum class ShaderInterlace
6971
Count
7072
};
7173

74+
// Indicates that the shader takes two sources: the normal depth texture and the backup texture to access the saved upper 8 bits.
75+
static inline bool NeedsBackup32BitDepth(ShaderConvert shader)
76+
{
77+
switch (shader)
78+
{
79+
case ShaderConvert::DEPTH_COPY_2:
80+
case ShaderConvert::FLOAT32_TO_RGBA8_2:
81+
return true;
82+
default:
83+
return false;
84+
}
85+
}
86+
87+
// Get the equivalent shader that allows restoring the upper 8 bits of depth with the backup texture.
88+
static inline ShaderConvert GetShaderWithBackup32BitDepth(ShaderConvert shader)
89+
{
90+
switch (shader)
91+
{
92+
case ShaderConvert::DEPTH_COPY:
93+
return ShaderConvert::DEPTH_COPY_2;
94+
case ShaderConvert::FLOAT32_TO_RGBA8:
95+
return ShaderConvert::FLOAT32_TO_RGBA8_2;
96+
default:
97+
return shader;
98+
}
99+
}
100+
72101
static inline bool HasDepthOutput(ShaderConvert shader)
73102
{
74103
switch (shader)
@@ -83,6 +112,7 @@ static inline bool HasDepthOutput(ShaderConvert shader)
83112
case ShaderConvert::RGB5A1_TO_FLOAT16_BILN:
84113
case ShaderConvert::FLOAT32_TO_FLOAT24:
85114
case ShaderConvert::DEPTH_COPY:
115+
case ShaderConvert::DEPTH_COPY_2:
86116
return true;
87117
default:
88118
return false;

pcsx2/GS/Renderers/Common/GSTexture.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
GSTexture::GSTexture() = default;
1616

17-
GSTexture::~GSTexture() = default;
18-
1917
bool GSTexture::Save(const std::string& fn)
2018
{
2119
// Depth textures need special treatment - we have a stencil component.

pcsx2/GS/Renderers/Common/GSTexture.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,16 @@ class GSTexture
7272
bool m_needs_mipmaps_generated = true;
7373
ClearValue m_clear_value = {};
7474

75+
// Used to store full 32 bit range depth for depth textures in case the upper 8 bits
76+
// needs to be used later.
77+
GSTexture* m_backup_32_bit_depth = nullptr;
7578
public:
7679
GSTexture();
77-
virtual ~GSTexture();
80+
virtual ~GSTexture()
81+
{
82+
if (m_backup_32_bit_depth)
83+
delete m_backup_32_bit_depth;
84+
}
7885

7986
// Returns the native handle of a texture.
8087
virtual void* GetNativeHandle() const = 0;
@@ -161,6 +168,29 @@ class GSTexture
161168

162169
// Helper routines for formats/types
163170
static bool IsCompressedFormat(Format format) { return (format >= Format::BC1 && format <= Format::BC7); }
171+
172+
bool HasBackup32BitDepth()
173+
{
174+
return m_backup_32_bit_depth != nullptr;
175+
}
176+
177+
void SetBackup32BitDepth(GSTexture* tex)
178+
{
179+
pxAssert(m_backup_32_bit_depth == nullptr);
180+
m_backup_32_bit_depth = tex;
181+
}
182+
183+
void RemoveBackup32BitDepth()
184+
{
185+
if (m_backup_32_bit_depth)
186+
delete m_backup_32_bit_depth;
187+
m_backup_32_bit_depth = nullptr;
188+
}
189+
190+
GSTexture* GetBackup32BitDepth()
191+
{
192+
return m_backup_32_bit_depth;
193+
}
164194
};
165195

166196
class GSDownloadTexture

pcsx2/GS/Renderers/HW/GSRendererHW.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7485,8 +7485,9 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
74857485
// Not gonna spend too much time with this, it's not likely to be used much, can't be less accurate than it was.
74867486
if (ds)
74877487
{
7488-
ds->m_alpha_max = std::max(static_cast<u32>(ds->m_alpha_max), static_cast<u32>(m_vt.m_max.p.z) >> 24);
7489-
ds->m_alpha_min = std::min(static_cast<u32>(ds->m_alpha_min), static_cast<u32>(m_vt.m_min.p.z) >> 24);
7488+
// Clamp to prevent overflow with float -> int conversion.
7489+
ds->m_alpha_max = std::max(static_cast<u32>(ds->m_alpha_max), std::clamp(static_cast<u32>(m_vt.m_max.p.z * 0x1.0fp-24), 0u, 255u));
7490+
ds->m_alpha_min = std::min(static_cast<u32>(ds->m_alpha_min), std::clamp(static_cast<u32>(m_vt.m_min.p.z * 0x1.0fp-24), 0u, 255u));
74907491
GL_INS("HW: New DS Alpha Range: %d-%d", ds->m_alpha_min, ds->m_alpha_max);
74917492

74927493
if (GSLocalMemory::m_psm[ds->m_TEX0.PSM].bpp == 16)

pcsx2/GS/Renderers/HW/GSTextureCache.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,20 +2657,29 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
26572657
else if (dst->m_scale != scale)
26582658
scale = dst->m_scale;
26592659

2660-
// Game is changing from 32bit deptth to 24bit, meaning any top values in the depth will no longer be valid, I hope no games rely on these values being maintained, else we're screwed.
26612660
if (type == DepthStencil && dst->m_type == DepthStencil && GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32 && GSLocalMemory::m_psm[TEX0.PSM].trbpp == 24 && dst->m_alpha_max > 0)
26622661
{
2662+
// Game is changing from 32bit depth to 24bit, so backup the original 32 bit texture to preserve the upper 8 bits of Z.
26632663
calcRescale(dst);
26642664
GSTexture* tex = g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, false);
26652665
if (!tex)
26662666
return nullptr;
26672667
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, ShaderConvert::FLOAT32_TO_FLOAT24, false);
26682668
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
2669+
tex->SetBackup32BitDepth(dst->m_texture);
2670+
dst->m_texture = tex;
2671+
}
2672+
else if (type == DepthStencil && dst->m_type == DepthStencil && GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 24 && GSLocalMemory::m_psm[TEX0.PSM].trbpp == 32 && dst->m_texture->HasBackup32BitDepth())
2673+
{
2674+
// Game is changing from 24bit depth to 32bit, so restore the backed up upper 8 bits (if it exists).
2675+
calcRescale(dst);
2676+
GSTexture* tex = g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, false);
2677+
if (!tex)
2678+
return nullptr;
2679+
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, ShaderConvert::DEPTH_COPY, false); // Depth copy will automatically use the backed up data.
2680+
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
26692681
g_gs_device->Recycle(dst->m_texture);
2670-
26712682
dst->m_texture = tex;
2672-
dst->m_alpha_min = 0;
2673-
dst->m_alpha_max = 0;
26742683
}
26752684
else if ((used || type == GSTextureCache::DepthStencil) && (std::abs(static_cast<s16>(GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp - GSLocalMemory::m_psm[TEX0.PSM].bpp)) == 16))
26762685
{
@@ -3125,6 +3134,15 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
31253134
dst_match->UnscaleRTAlpha();
31263135
g_gs_device->StretchRect(dst_match->m_texture, sRect, dst->m_texture, dRect, shader, false);
31273136
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
3137+
3138+
if (shader == ShaderConvert::RGBA8_TO_FLOAT24)
3139+
{
3140+
// Copy all 32 bits of color into the back up texture in case the game converts to 32bit depth later.
3141+
GSTexture* tex = g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, false);
3142+
g_gs_device->StretchRect(dst_match->m_texture, sRect, tex, dRect, ShaderConvert::RGBA8_TO_FLOAT32, false);
3143+
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
3144+
dst->m_texture->SetBackup32BitDepth(tex);
3145+
}
31283146
}
31293147
}
31303148

pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,7 +1452,9 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
14521452
{
14531453
pxAssert(dTex->IsDepthStencil() == HasDepthOutput(shader));
14541454
pxAssert(linear ? SupportsBilinear(shader) : SupportsNearest(shader));
1455-
StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[(int)shader], false, OMColorMaskSelector(ShaderConvertWriteMask(shader)), linear);
1455+
if (sTex->HasBackup32BitDepth())
1456+
shader = GetShaderWithBackup32BitDepth(shader);
1457+
StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[(int)shader], false, OMColorMaskSelector(ShaderConvertWriteMask(shader)), linear, sTex->HasBackup32BitDepth());
14561458
}
14571459

14581460
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool linear)
@@ -1469,12 +1471,14 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
14691471
cms.wb = blue;
14701472
cms.wa = alpha;
14711473

1472-
StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[(int)shader], false, cms, false);
1474+
if (sTex->HasBackup32BitDepth())
1475+
shader = GetShaderWithBackup32BitDepth(shader);
1476+
StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[(int)shader], false, cms, false, sTex->HasBackup32BitDepth());
14731477
}
14741478

1475-
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear)
1479+
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear, bool useBackup32BitDepth)
14761480
{
1477-
CommitClear(sTex, true);
1481+
CommitClear(sTex, true); // FIXME: What to do about clear when have a backup depth?
14781482

14791483
const bool draw_in_depth = dTex->IsDepthStencil();
14801484

@@ -1483,6 +1487,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
14831487
// ************************************
14841488

14851489
GL_PUSH("StretchRect from %d to %d", static_cast<GSTextureOGL*>(sTex)->GetID(), static_cast<GSTextureOGL*>(dTex)->GetID());
1490+
14861491
if (draw_in_depth)
14871492
OMSetRenderTargets(nullptr, dTex);
14881493
else
@@ -1507,6 +1512,8 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
15071512
// ************************************
15081513

15091514
PSSetShaderResource(0, sTex);
1515+
if (useBackup32BitDepth)
1516+
PSSetShaderResource(1, sTex->GetBackup32BitDepth());
15101517
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt);
15111518

15121519
// ************************************

pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ class GSDeviceOGL final : public GSDevice
320320
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true) override;
321321
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool linear = true);
322322
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, ShaderConvert shader = ShaderConvert::COPY) override;
323-
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear = true);
323+
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear = true, bool useBackup32BitDepth = false);
324324
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) override;
325325
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
326326
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;

0 commit comments

Comments
 (0)