GS/DX11: Backport ds as rt from GL for depth feedback.

Doing gpu depth copies is quite slower on dx11, so let's
use the ds as rt behavior from GL which would allow us
to treat them as rt copies instead which are faster.
This commit is contained in:
lightningterror
2026-06-25 20:56:58 +02:00
parent a6769818fd
commit 66ea4c4967
5 changed files with 55 additions and 27 deletions
+2 -2
View File
@@ -214,7 +214,7 @@ struct PS_OUTPUT_REAL
#if PS_RETURN_DEPTH
// In DX12 we do depth feedback loops with a color copy.
#if SW_DEPTH && PS_NO_COLOR1 && DX12
#if SW_DEPTH && PS_NO_COLOR1 && PS_DEPTH_FEEDBACK_SUPPORT == 2
#if NUM_RTS > 0
float depth_color : SV_Target1;
#else
@@ -1607,7 +1607,7 @@ if (bad)
// Depth write back
#if PS_RETURN_DEPTH
output_real.depth = input.p.z;
#if SW_DEPTH && PS_NO_COLOR1 && DX12
#if SW_DEPTH && PS_NO_COLOR1 && PS_DEPTH_FEEDBACK_SUPPORT == 2
// Output color clone for feedback.
output_real.depth_color = input.p.z;
#endif
+48 -23
View File
@@ -642,6 +642,13 @@ void GSDevice11::Destroy()
}
m_state.current_rt = nullptr;
if (m_state.dsv_as_rtv)
{
m_state.dsv_as_rtv->Release();
m_state.dsv_as_rtv = nullptr;
}
m_state.current_ds_as_rt = nullptr;
if (m_state.dsv)
{
m_state.dsv->Release();
@@ -695,7 +702,7 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
m_features.bptc_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC7_UNORM);
m_features.cas_sharpening = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_features.test_and_sample_depth = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_features.depth_feedback = m_features.feedback_loops();
m_features.depth_feedback = m_features.multidraw_fb_copy && GSConfig.DepthFeedbackMode == GSDepthFeedbackMode::Depth;
m_features.aa1 = GSConfig.HWAA1 && m_features.vs_expand && m_features.feedback_loops();
m_max_texture_size = (m_feature_level >= D3D_FEATURE_LEVEL_11_0) ?
@@ -1091,7 +1098,7 @@ void GSDevice11::EndPresent()
PopTimestampQuery();
// clear out the swap chain view, it might get resized..
OMSetRenderTargets(nullptr, nullptr);
OMSetRenderTargets(nullptr, nullptr, nullptr);
const UINT sync_interval = static_cast<UINT>(m_vsync_mode == GSVSyncMode::FIFO);
const UINT flags = (m_vsync_mode == GSVSyncMode::Disabled && m_using_allow_tearing) ? DXGI_PRESENT_ALLOW_TEARING : 0;
@@ -1466,9 +1473,9 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
{
ds = dTex->GetSize();
if (draw_in_depth)
OMSetRenderTargets(nullptr, dTex);
OMSetRenderTargets(nullptr, nullptr, dTex);
else
OMSetRenderTargets(dTex, nullptr);
OMSetRenderTargets(dTex, nullptr, nullptr);
}
else
{
@@ -1532,7 +1539,7 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
if (dTex)
{
ds = dTex->GetSize();
OMSetRenderTargets(dTex, nullptr);
OMSetRenderTargets(dTex, nullptr, nullptr);
}
else
{
@@ -1655,7 +1662,7 @@ void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_re
PSSetShader(GetConvertShader(shader), nullptr);
OMSetDepthStencilState(dTex->IsRenderTarget() ? m_convert.dss.get() : m_convert.dss_write.get(), 0);
OMSetRenderTargets(dTex->IsRenderTarget() ? dTex : nullptr, dTex->IsDepthStencil() ? dTex : nullptr);
OMSetRenderTargets(dTex->IsRenderTarget() ? dTex : nullptr, nullptr, dTex->IsDepthStencil() ? dTex : nullptr);
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(dTex->GetHeight()));
GSTexture* last_tex = rects[0].src;
@@ -1891,6 +1898,7 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
sm.AddMacro("PIXEL_SHADER", 1);
sm.AddMacro("PS_HAS_CONSERVATIVE_DEPTH", m_conservative_depth);
sm.AddMacro("PS_DEPTH_FEEDBACK_SUPPORT", m_features.depth_feedback ? 1 : 2);
sm.AddMacro("PS_FST", sel.fst);
sm.AddMacro("PS_WMS", sel.wms);
sm.AddMacro("PS_WMT", sel.wmt);
@@ -2153,7 +2161,7 @@ bool GSDevice11::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons
ID3D11ShaderResourceView* srvs[1] = {*static_cast<GSTexture11*>(sTex)};
ID3D11UnorderedAccessView* uavs[1] = {*static_cast<GSTexture11*>(dTex)};
OMSetRenderTargets(nullptr, nullptr);
OMSetRenderTargets(nullptr, nullptr, nullptr);
m_ctx->UpdateSubresource(m_cas.cb.get(), 0, nullptr, constants.data(), 0, 0);
m_ctx->CSSetConstantBuffers(0, 1, m_cas.cb.addressof());
m_ctx->CSSetShader(sharpen_only ? m_cas.cs_sharpen.get() : m_cas.cs_upscale.get(), nullptr, 0);
@@ -2347,7 +2355,7 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV
OMSetDepthStencilState(m_date.dss.get(), 1);
OMSetBlendState(m_date.bs.get(), 0);
OMSetRenderTargets(nullptr, ds);
OMSetRenderTargets(nullptr, nullptr, ds);
// ia
@@ -2740,13 +2748,14 @@ void GSDevice11::OMSetBlendState(ID3D11BlendState* bs, u8 bf)
}
}
void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_uav_tex, GSTexture* ds_uav_tex,
void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds_as_rt, GSTexture* ds, GSTexture* rt_uav_tex, GSTexture* ds_uav_tex,
const GSVector4i* scissor, ID3D11DepthStencilView* read_only_dsv)
{
if (!(rt || rt_uav_tex) && ds_uav_tex)
rt_uav_tex = m_null_texture; // Fill in the first UAV slot with the null texture.
ID3D11RenderTargetView* rtv = nullptr;
ID3D11RenderTargetView* dsv_as_rtv = nullptr;
ID3D11DepthStencilView* dsv = nullptr;
ID3D11UnorderedAccessView* rt_uav = nullptr;
ID3D11UnorderedAccessView* ds_uav = nullptr;
@@ -2756,6 +2765,11 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
CommitClear(rt);
rtv = *static_cast<GSTexture11*>(rt);
}
if (ds_as_rt)
{
CommitClear(ds_as_rt);
dsv_as_rtv = *static_cast<GSTexture11*>(ds_as_rt);
}
if (ds)
{
CommitClear(ds);
@@ -2772,7 +2786,7 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
ds_uav = *static_cast<GSTexture11*>(ds_uav_tex);
}
const bool changed = (m_state.rtv != rtv || m_state.dsv != dsv || m_state.rt_uav != rt_uav || m_state.ds_uav != ds_uav);
const bool changed = (m_state.rtv != rtv || m_state.dsv_as_rtv != dsv_as_rtv || m_state.dsv != dsv || m_state.rt_uav != rt_uav || m_state.ds_uav != ds_uav);
const bool no_uavs = m_state.rt_uav == nullptr && rt_uav == nullptr && m_state.ds_uav == nullptr && ds_uav == nullptr;
if (changed)
@@ -2787,6 +2801,15 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
m_state.rtv = rtv;
m_state.current_rt = rt;
}
if (m_state.dsv_as_rtv != dsv_as_rtv)
{
if (m_state.dsv_as_rtv)
m_state.dsv_as_rtv->Release();
if (dsv_as_rtv)
dsv_as_rtv->AddRef();
m_state.rtv = dsv_as_rtv;
m_state.current_ds_as_rt = ds_as_rt;
}
if (m_state.dsv != dsv)
{
if (m_state.dsv)
@@ -2816,13 +2839,14 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
}
PSUnbindConflictingSRVs(m_state.current_rt, read_only_dsv ? nullptr : m_state.current_ds);
PSUnbindConflictingSRVs(m_state.current_ds_as_rt);
PSUnbindConflictingSRVs(m_state.current_rt_uav, m_state.current_ds_uav);
if (changed)
{
// OM targets and UAVs share the same namespace in DX11, so we need to pack them into contiguous slots.
const u32 num_rtvs = rt ? 1 : 0;
ID3D11RenderTargetView* rtvs[] = {rtv};
const u32 num_rtvs = ds_as_rt ? 2 : rt ? 1 : 0;
ID3D11RenderTargetView* rtvs[] = {rtv, dsv_as_rtv};
if (no_uavs)
m_ctx->OMSetRenderTargets(num_rtvs, rtvs, dsv);
else
@@ -2837,7 +2861,7 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
}
}
if (rt || ds || rt_uav_tex || ds_uav_tex)
if (rt || ds_as_rt || ds || rt_uav_tex || ds_uav_tex)
{
const GSVector2i size =
rt ? rt->GetSize() :
@@ -2907,6 +2931,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
GSTexture* colclip_rt = g_gs_device->GetColorClipTexture();
GSTexture* draw_rt = config.ps.HasColorROV() ? nullptr : config.rt;
GSTexture* draw_ds_as_rt = m_ds_as_rt;
GSTexture* draw_ds = config.ps.HasDepthROV() ? nullptr : config.ds;
GSTexture* draw_rt_rov = config.ps.HasColorROV() ? config.rt : nullptr;
GSTexture* draw_ds_rov = config.ps.HasDepthROV() ? config.ds : nullptr;
@@ -3047,7 +3072,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const OMBlendSelector blend(GSHWDrawConfig::ColorMaskSelector(1),
GSHWDrawConfig::BlendState(true, CONST_ONE, CONST_ONE, 3 /* MIN */, CONST_ONE, CONST_ZERO, false, 0));
SetupOM(dss, blend, 0);
OMSetRenderTargets(primid_texture, config.ds, nullptr, nullptr, &config.scissor, read_only_dsv);
OMSetRenderTargets(primid_texture, nullptr, config.ds, nullptr, nullptr, &config.scissor, read_only_dsv);
SetRenderHWShaderResources(config, nullptr);
Draw(config);
@@ -3059,19 +3084,19 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
// Avoid changing framebuffer just to switch from rt+depth to rt and vice versa.
// Make sure no tex is bound as both rtv and srv at the same time.
// All conflicts should've been taken care of by PSUnbindConflictingSRVs.
if (!(draw_rt || draw_rt_rov) && draw_ds && m_state.current_rt && config.tex != m_state.current_rt && m_state.current_rt->GetSize() == draw_ds->GetSize())
if (!(draw_rt || draw_rt_rov || draw_ds_as_rt) && draw_ds && m_state.current_rt && config.tex != m_state.current_rt && m_state.current_rt->GetSize() == draw_ds->GetSize())
{
draw_rt = m_state.current_rt;
}
else if (!(draw_ds || draw_ds_rov) && draw_rt && m_state.current_ds && config.tex != m_state.current_ds && m_state.current_ds->GetSize() == draw_rt->GetSize())
else if (!(draw_ds || draw_ds_rov || draw_ds_as_rt) && draw_rt && m_state.current_ds && config.tex != m_state.current_ds && m_state.current_ds->GetSize() == draw_rt->GetSize())
{
draw_ds = m_state.current_ds;
}
else if (!(draw_rt || draw_rt_rov) && draw_ds_rov && m_state.current_rt_uav && config.tex != m_state.current_rt_uav)
else if (!(draw_rt || draw_rt_rov || draw_ds_as_rt) && draw_ds_rov && m_state.current_rt_uav && config.tex != m_state.current_rt_uav)
{
draw_rt_rov = m_state.current_rt_uav;
}
else if (!(draw_ds || draw_ds_rov) && draw_rt_rov && m_state.current_ds_uav && config.tex != m_state.current_ds_uav)
else if (!(draw_ds || draw_ds_rov || draw_ds_as_rt) && draw_rt_rov && m_state.current_ds_uav && config.tex != m_state.current_ds_uav)
{
draw_ds_rov = m_state.current_ds_uav;
}
@@ -3090,17 +3115,17 @@ 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);
if (draw_ds && !draw_ds_rov && m_features.depth_feedback && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
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->GetFormat(), true);
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, draw_rt_rov, draw_ds_rov, &config.scissor, read_only_dsv);
OMSetRenderTargets(draw_rt, 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);
@@ -3108,7 +3133,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && need_barrier)
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(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,
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);
if (config.blend_multi_pass.enable)
@@ -3136,7 +3161,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,
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);
}
+3 -1
View File
@@ -173,10 +173,12 @@ private:
ID3D11BlendState* bs;
u8 bf;
ID3D11RenderTargetView* rtv;
ID3D11RenderTargetView* dsv_as_rtv;
ID3D11DepthStencilView* dsv;
ID3D11UnorderedAccessView* rt_uav;
ID3D11UnorderedAccessView* ds_uav;
GSTexture* current_rt;
GSTexture* current_ds_as_rt;
GSTexture* current_ds;
GSTexture* current_rt_uav;
GSTexture* current_ds_uav;
@@ -383,7 +385,7 @@ public:
void OMSetDepthStencilState(ID3D11DepthStencilState* dss, u8 sref);
void OMSetBlendState(ID3D11BlendState* bs, u8 bf);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_uav = nullptr, GSTexture* ds_uav = nullptr,
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds_as_rt, GSTexture* ds, GSTexture* rt_uav = nullptr, GSTexture* ds_uav = nullptr,
const GSVector4i* scissor = nullptr, ID3D11DepthStencilView* read_only_dsv = nullptr);
void SetViewport(const GSVector2i& viewport);
void SetScissor(const GSVector4i& scissor);
+1
View File
@@ -3117,6 +3117,7 @@ const ID3DBlob* GSDevice12::GetTFXPixelShader(const GSHWDrawConfig::PSSelector&
ShaderMacro sm;
sm.AddMacro("PIXEL_SHADER", 1);
sm.AddMacro("PS_HAS_CONSERVATIVE_DEPTH", 1);
sm.AddMacro("PS_DEPTH_FEEDBACK_SUPPORT", 2);
sm.AddMacro("PS_FST", sel.fst);
sm.AddMacro("PS_WMS", sel.wms);
sm.AddMacro("PS_WMT", sel.wmt);
+1 -1
View File
@@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 103; // Last changed in PR 14602
static constexpr u32 SHADER_CACHE_VERSION = 104; // Last changed in PR 14603