From f01dfec52f4c6796b73bf64daf849d84952cca0c Mon Sep 17 00:00:00 2001 From: lightningterror <18107717+lightningterror@users.noreply.github.com> Date: Mon, 29 Jun 2026 15:04:42 +0200 Subject: [PATCH] GS/DX11: Skip barrier/copy if it's not needed. It is possible to skip one barrier copy when using draw_ds_as_rt if only one pass needs a barrier, we already have a copy and draw_ds_as_rt doesn't need updating. --- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 56 +++++++++++++++++--------- pcsx2/GS/Renderers/DX11/GSDevice11.h | 6 +-- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 9ce212193e..d201d329ed 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -3234,17 +3234,28 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) const bool ds_feedbackloop_pass1 = config.IsFeedbackLoopDepth(config.ps); const bool ds_feedbackloop_pass2 = config.IsFeedbackLoopDepth(config.alpha_second_pass.ps); + + // It is possible to skip one barrier copy when using draw_ds_as_rt if only one pass needs a barrier, we already have a copy and draw_ds_as_rt doesn't need updating. + const bool can_skip_ds_barrier = draw_ds_as_rt && + // Pass 1 needs barrier only. + ((ds_feedbackloop_pass1 && config.require_one_barrier && !ds_feedbackloop_pass2 && !config.alpha_second_pass.require_one_barrier) || + // Pass 2 needs barrier only. + (!ds_feedbackloop_pass1 && !config.require_one_barrier && ds_feedbackloop_pass2 && config.alpha_second_pass.require_one_barrier)); + if (draw_ds && !draw_ds_rov && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) && (ds_feedbackloop_pass1 || ds_feedbackloop_pass2)) { // Requires a copy of the DS. - draw_ds_clone = CreateTexture(rtsize.x, rtsize.y, 1, (draw_ds_as_rt ? draw_ds_as_rt : draw_ds)->GetFormat(), true); + if (can_skip_ds_barrier) + draw_ds_clone = CreateFeedbackTarget(rtsize.x, rtsize.y, (draw_ds_as_rt ? draw_ds_as_rt : draw_ds)->GetFormat(), false, true); + else + draw_ds_clone = CreateTexture(rtsize.x, rtsize.y, 1, (draw_ds_as_rt ? draw_ds_as_rt : draw_ds)->GetFormat(), true); if (!draw_ds_clone) Console.Warning("D3D11: Failed to allocate temp texture for DS copy."); } - OMSetRenderTargets(draw_rt, draw_ds_as_rt, draw_ds, draw_rt_rov, draw_ds_rov, &config.scissor, read_only_dsv); + OMSetRenderTargets(draw_rt, can_skip_ds_barrier ? draw_ds_clone : draw_ds_as_rt, draw_ds, draw_rt_rov, draw_ds_rov, &config.scissor, read_only_dsv); SetRenderHWShaderResources(config, primid_texture); SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant); @@ -3253,7 +3264,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) m_ctx->ClearDepthStencilView(*static_cast(draw_ds), D3D11_CLEAR_STENCIL, 0.0f, 1); SendHWDraw(config, rt_feedbackloop_pass1 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass1 ? draw_ds_clone : nullptr, draw_ds_as_rt ? draw_ds_as_rt : draw_ds, - config.require_one_barrier, config.require_full_barrier, rtsize); + config.require_one_barrier, config.require_full_barrier, can_skip_ds_barrier, rtsize); if (config.blend_multi_pass.enable) { @@ -3281,7 +3292,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) const bool one_barrier = config.alpha_second_pass.require_one_barrier && m_features.multidraw_fb_copy; SetupOM(config.alpha_second_pass.depth, OMBlendSelector(config.alpha_second_pass.colormask, config.blend), config.blend.constant); SendHWDraw(config, rt_feedbackloop_pass2 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass2 ? draw_ds_clone : nullptr, draw_ds_as_rt ? draw_ds_as_rt : draw_ds, - one_barrier, config.alpha_second_pass.require_full_barrier, rtsize); + one_barrier, config.alpha_second_pass.require_full_barrier, can_skip_ds_barrier, rtsize); } if (colclip_rt) @@ -3302,27 +3313,34 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) } void GSDevice11::FeedbackCopyAndBind(const GSHWDrawConfig& config, - GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const GSVector4i& copyarea) + GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const bool skip_ds_barrier, const GSVector4i& copyarea) { if (rt_clone) { CopyRect(rt, rt_clone, copyarea, copyarea.left, copyarea.top); - PSSetShaderResource(2, rt_clone); + PSSetShaderResource(TEXTURE_RT, rt_clone); if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT) PSSetShaderResource(0, rt_clone); } if (ds_clone) { - CopyRect(ds, ds_clone, copyarea, copyarea.left, copyarea.top); - PSSetShaderResource(4, ds_clone); - if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH) - PSSetShaderResource(0, ds_clone); + if (skip_ds_barrier) + { + PSSetShaderResource(TEXTURE_DEPTH, ds); + } + else + { + CopyRect(ds, ds_clone, copyarea, copyarea.left, copyarea.top); + PSSetShaderResource(TEXTURE_DEPTH, ds_clone); + if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH) + PSSetShaderResource(0, ds_clone); + } } } // Choose the best copy area based on the hazards and whether we need RT and/or DS copies. void GSDevice11::FeedbackCopyAndBind(const GSHWDrawConfig& config, - GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, + GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const bool skip_ds_barrier, const GSVector4i& copyarea, const GSVector4i& samplearea) { const GSVector4i rtsize = (rt ? rt : ds)->GetRect(); @@ -3338,24 +3356,24 @@ void GSDevice11::FeedbackCopyAndBind(const GSHWDrawConfig& config, // Do an individual copy if the union is larger than the sum of individual areas. if (size_union > size_indiv) { - FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.drawarea)); - FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.samplearea)); + FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, skip_ds_barrier, ProcessCopyArea(rtsize, config.drawarea)); + FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, skip_ds_barrier, ProcessCopyArea(rtsize, config.samplearea)); } else { - FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, union_rect)); + FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, skip_ds_barrier, ProcessCopyArea(rtsize, union_rect)); } } else { // No RT hazards so just need the draw area (or full area for DS). - FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.drawarea)); + FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, skip_ds_barrier, ProcessCopyArea(rtsize, config.drawarea)); } }; void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds_clone, GSTexture* draw_ds, - const bool one_barrier, const bool full_barrier, GSVector2i rtsize) + const bool one_barrier, const bool full_barrier, const bool skip_ds_barrier, GSVector2i rtsize) { #ifdef PCSX2_DEVBUILD if ((one_barrier || full_barrier) && !(config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]] @@ -3371,7 +3389,7 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, pxAssert(config.drawlist_bbox && static_cast(config.drawlist_bbox->size()) == draw_list_size); if (config.tex_hazard != config.TEX_HAZARD_NONE) - FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.samplearea); + FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, skip_ds_barrier, config.samplearea); for (u32 n = 0, p = 0; n < draw_list_size; n++) { @@ -3379,7 +3397,7 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, const GSVector4i bbox = config.drawlist_bbox->at(n).rintersect(config.drawarea); - FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, bbox); + FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, skip_ds_barrier, bbox); Draw(config, p, count); @@ -3391,7 +3409,7 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, if (one_barrier) { - FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.drawarea, config.samplearea); + FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, skip_ds_barrier, config.drawarea, config.samplearea); } Draw(config); diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index 3da31414cf..5556b47e8e 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -416,13 +416,13 @@ public: void RenderHW(GSHWDrawConfig& config) override; void FeedbackCopyAndBind(const GSHWDrawConfig& config, - GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const GSVector4i& copyarea); + GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const bool skip_ds_barrier, const GSVector4i& copyarea); void FeedbackCopyAndBind(const GSHWDrawConfig& config, - GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, + GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const bool skip_ds_barrier, const GSVector4i& copyarea, const GSVector4i& samplearea); void SendHWDraw(const GSHWDrawConfig& config, GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds_clone, GSTexture* draw_ds, - const bool one_barrier, const bool full_barrier, GSVector2i rtsize); + const bool one_barrier, const bool full_barrier, const bool skip_ds_barrier, GSVector2i rtsize); void SetRenderHWShaderResources(const GSHWDrawConfig& config, GSTexture* primid_texture); void ClearSamplerCache() override;