Skip to content

Commit 58dc756

Browse files
committed
GPU/HW: Add in-pass clear depth pipeline
Instead of clearing the entire buffer, we only need to wipe out the current drawing area. Saves a decent chunk of memory bandwidth in games that end up spamming clears.
1 parent ee6887b commit 58dc756

4 files changed

Lines changed: 85 additions & 13 deletions

File tree

src/core/gpu_hw.cpp

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
1+
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
22
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
33

44
#include "gpu_hw.h"
@@ -8,6 +8,7 @@
88
#include "gpu_hw_shadergen.h"
99
#include "gpu_presenter.h"
1010
#include "gpu_sw_rasterizer.h"
11+
#include "gte_types.h"
1112
#include "host.h"
1213
#include "imgui_overlays.h"
1314
#include "settings.h"
@@ -580,7 +581,7 @@ bool GPU_HW::UpdateSettings(const GPUSettings& old_settings, Error* error)
580581
else if (m_vram_depth_texture && depth_buffer_changed)
581582
{
582583
if (m_pgxp_depth_buffer)
583-
ClearDepthBuffer();
584+
ClearDepthBuffer(false);
584585
else if (m_write_mask_as_depth)
585586
UpdateDepthBufferFromMaskBit();
586587
}
@@ -1121,6 +1122,7 @@ bool GPU_HW::CompilePipelines(Error* error)
11211122
p.reset();
11221123
m_vram_update_depth_pipeline.reset();
11231124
m_vram_write_replacement_pipeline.reset();
1125+
m_clear_depth_pipeline.reset();
11241126
m_copy_depth_pipeline.reset();
11251127

11261128
ShaderCompileProgressTracker progress("Compiling Pipelines", total_items);
@@ -1667,6 +1669,30 @@ bool GPU_HW::CompilePipelines(Error* error)
16671669
plconfig.SetTargetFormats(VRAM_DS_COLOR_FORMAT);
16681670
if (!(m_copy_depth_pipeline = g_gpu_device->CreatePipeline(plconfig, error)))
16691671
return false;
1672+
1673+
fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
1674+
shadergen.GenerateVRAMClearDepthFragmentShader(m_use_rov_for_shader_blend), error);
1675+
if (!fs)
1676+
return false;
1677+
1678+
SetScreenQuadInputLayout(plconfig);
1679+
plconfig.vertex_shader = m_screen_quad_vertex_shader.get();
1680+
plconfig.fragment_shader = fs.get();
1681+
if (!m_use_rov_for_shader_blend)
1682+
{
1683+
plconfig.SetTargetFormats(VRAM_RT_FORMAT, depth_buffer_format);
1684+
plconfig.render_pass_flags =
1685+
needs_feedback_loop ? GPUPipeline::ColorFeedbackLoop : GPUPipeline::NoRenderPassFlags;
1686+
plconfig.blend.write_mask = 0;
1687+
plconfig.depth = GPUPipeline::DepthState::GetAlwaysWriteState();
1688+
}
1689+
else
1690+
{
1691+
plconfig.SetTargetFormats(depth_buffer_format);
1692+
}
1693+
1694+
if (!(m_clear_depth_pipeline = g_gpu_device->CreatePipeline(plconfig, error)))
1695+
return false;
16701696
}
16711697

16721698
if (!CompileResolutionDependentPipelines(error) || !CompileDownsamplePipelines(error))
@@ -1949,7 +1975,7 @@ void GPU_HW::UpdateDepthBufferFromMaskBit()
19491975
SetScissor();
19501976
}
19511977

1952-
void GPU_HW::CopyAndClearDepthBuffer()
1978+
void GPU_HW::CopyAndClearDepthBuffer(bool only_drawing_area)
19531979
{
19541980
if (!m_depth_was_copied)
19551981
{
@@ -1976,17 +2002,39 @@ void GPU_HW::CopyAndClearDepthBuffer()
19762002
m_depth_was_copied = true;
19772003
}
19782004

1979-
ClearDepthBuffer();
2005+
ClearDepthBuffer(only_drawing_area);
19802006
}
19812007

1982-
void GPU_HW::ClearDepthBuffer()
2008+
void GPU_HW::ClearDepthBuffer(bool only_drawing_area)
19832009
{
1984-
GL_SCOPE("GPU_HW::ClearDepthBuffer()");
2010+
GL_SCOPE_FMT("GPU_HW::ClearDepthBuffer({})", only_drawing_area ? "Only Drawing Area" : "Full Buffer");
19852011
DebugAssert(m_pgxp_depth_buffer);
1986-
if (m_use_rov_for_shader_blend)
1987-
g_gpu_device->ClearRenderTarget(m_vram_depth_texture.get(), 0xFF);
2012+
if (only_drawing_area)
2013+
{
2014+
g_gpu_device->SetPipeline(m_clear_depth_pipeline.get());
2015+
2016+
const GSVector4i clear_bounds = m_clamped_drawing_area.mul32l(GSVector4i(m_resolution_scale));
2017+
2018+
// need to re-bind for rov, because we can't turn colour writes off for only the first target
2019+
if (!m_use_rov_for_shader_blend)
2020+
{
2021+
DrawScreenQuad(clear_bounds, m_vram_depth_texture->GetSizeVec());
2022+
}
2023+
else
2024+
{
2025+
g_gpu_device->SetRenderTarget(m_vram_depth_texture.get());
2026+
DrawScreenQuad(clear_bounds, m_vram_depth_texture->GetSizeVec());
2027+
SetVRAMRenderTarget();
2028+
}
2029+
}
19882030
else
1989-
g_gpu_device->ClearDepth(m_vram_depth_texture.get(), 1.0f);
2031+
{
2032+
if (m_use_rov_for_shader_blend)
2033+
g_gpu_device->ClearRenderTarget(m_vram_depth_texture.get(), 0xFF);
2034+
else
2035+
g_gpu_device->ClearDepth(m_vram_depth_texture.get(), 1.0f);
2036+
}
2037+
19902038
m_last_depth_z = 1.0f;
19912039
s_counters.num_depth_buffer_clears++;
19922040
}
@@ -2405,8 +2453,12 @@ void GPU_HW::CheckForDepthClear(const GPUBackendDrawCommand* cmd, const BatchVer
24052453

24062454
if ((average_z - m_last_depth_z) >= g_gpu_settings.gpu_pgxp_depth_clear_threshold)
24072455
{
2456+
GL_INS_FMT("Clear depth buffer avg={} last={} threshold={}", average_z * static_cast<float>(GTE::MAX_Z),
2457+
m_last_depth_z * static_cast<float>(GTE::MAX_Z),
2458+
g_gpu_settings.gpu_pgxp_depth_clear_threshold * static_cast<float>(GTE::MAX_Z));
2459+
24082460
FlushRender();
2409-
CopyAndClearDepthBuffer();
2461+
CopyAndClearDepthBuffer(true);
24102462
EnsureVertexBufferSpaceForCommand(cmd);
24112463
}
24122464

@@ -3723,7 +3775,7 @@ void GPU_HW::PrepareDraw(const GPUBackendDrawCommand* cmd)
37233775
if (m_pgxp_depth_buffer && m_last_depth_z < 1.0f)
37243776
{
37253777
FlushRender();
3726-
CopyAndClearDepthBuffer();
3778+
CopyAndClearDepthBuffer(false);
37273779
EnsureVertexBufferSpaceForCommand(cmd);
37283780
}
37293781
}

src/core/gpu_hw.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ class GPU_HW final : public GPUBackend
186186

187187
void UpdateVRAMReadTexture(bool drawn, bool written);
188188
void UpdateDepthBufferFromMaskBit();
189-
void CopyAndClearDepthBuffer();
190-
void ClearDepthBuffer();
189+
void CopyAndClearDepthBuffer(bool only_drawing_area);
190+
void ClearDepthBuffer(bool only_drawing_area);
191191
void SetScissor();
192192
void SetVRAMRenderTarget();
193193
void DeactivateROV();
@@ -365,6 +365,7 @@ class GPU_HW final : public GPUBackend
365365
std::unique_ptr<GPUTexture> m_vram_extract_texture;
366366
std::unique_ptr<GPUTexture> m_vram_extract_depth_texture;
367367
std::unique_ptr<GPUPipeline> m_copy_depth_pipeline;
368+
std::unique_ptr<GPUPipeline> m_clear_depth_pipeline;
368369
std::unique_ptr<PostProcessing::Chain> m_internal_postfx;
369370

370371
std::unique_ptr<GPUTexture> m_downsample_texture;

src/core/gpu_hw_shadergen.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,24 @@ std::string GPU_HW_ShaderGen::GenerateVRAMUpdateDepthFragmentShader(bool msaa) c
16941694
return std::move(ss).str();
16951695
}
16961696

1697+
std::string GPU_HW_ShaderGen::GenerateVRAMClearDepthFragmentShader(bool write_depth_as_rt) const
1698+
{
1699+
std::stringstream ss;
1700+
WriteHeader(ss);
1701+
DefineMacro(ss, "WRITE_DEPTH_AS_RT", write_depth_as_rt);
1702+
DeclareFragmentEntryPoint(ss, 0, 1, {}, false, BoolToUInt32(write_depth_as_rt), false, false, false, false, false);
1703+
1704+
ss << R"(
1705+
{
1706+
#if WRITE_DEPTH_AS_RT
1707+
o_col0 = float4(1.0f, 0.0f, 0.0f, 0.0f);
1708+
#endif
1709+
}
1710+
)";
1711+
1712+
return std::move(ss).str();
1713+
}
1714+
16971715
void GPU_HW_ShaderGen::WriteAdaptiveDownsampleUniformBuffer(std::stringstream& ss) const
16981716
{
16991717
DeclareUniformBuffer(ss, {"float2 u_uv_min", "float2 u_uv_max", "float2 u_pixel_size", "float u_lod"}, true);

src/core/gpu_hw_shadergen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class GPU_HW_ShaderGen : public ShaderGen
3434
std::string GenerateVRAMFillFragmentShader(bool wrapped, bool interlaced, bool write_mask_as_depth,
3535
bool write_depth_as_rt) const;
3636
std::string GenerateVRAMUpdateDepthFragmentShader(bool msaa) const;
37+
std::string GenerateVRAMClearDepthFragmentShader(bool write_depth_as_rt) const;
3738
std::string GenerateVRAMExtractFragmentShader(u32 resolution_scale, u32 multisamples, bool color_24bit,
3839
bool depth_buffer) const;
3940
std::string GenerateVRAMReplacementBlitFragmentShader() const;

0 commit comments

Comments
 (0)