GS/HW: Further improve tex hazards.

Always enable test and sample depth on vk as well.

Make sure there is no feedback depth when using barriers,
as GL/DX12 have issues with it, so just stick with a plain copy
which is equivalent to depth as rt which we would have to do anyway.

Check for hazards properly for Hitman shuffle.

Better handle depth read only condition, allow for a barrier if it isn't.

Better handle hazard checks in device when doing a copy.

We don't need two or union copies on dx11 for depth as dx11 can't do partial depth
gpu copies.
This commit is contained in:
lightningterror
2026-05-23 11:14:46 +02:00
parent d39457951a
commit 0f9b8afe04
5 changed files with 42 additions and 41 deletions
+12 -10
View File
@@ -2907,10 +2907,8 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
ID3D11DepthStencilView* read_only_dsv = nullptr;
if (config.tex && config.tex == config.ds)
{
if (m_features.test_and_sample_depth && !config.depth.zwe && !config.ps.IsFeedbackLoopDepth() && !config.alpha_second_pass.ps.IsFeedbackLoopDepth())
if (m_features.test_and_sample_depth && !config.depth.zwe && !config.IsFeedbackLoopDepth(config.ps) && !config.IsFeedbackLoopDepth(config.alpha_second_pass.ps))
read_only_dsv = static_cast<GSTexture11*>(config.ds)->ReadOnlyDepthStencilView();
else
config.tex = nullptr;
}
SetupVS(config.vs, &config.cb_vs);
@@ -2960,8 +2958,8 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
Console.Warning("D3D11: Failed to allocate temp texture for RT copy.");
}
const bool ds_feedbackloop_pass1 = config.ps.IsFeedbackLoopDepth();
const bool ds_feedbackloop_pass2 = config.alpha_second_pass.ps.IsFeedbackLoopDepth();
const bool ds_feedbackloop_pass1 = config.IsFeedbackLoopDepth(config.ps);
const bool ds_feedbackloop_pass2 = config.IsFeedbackLoopDepth(config.alpha_second_pass.ps);
if (draw_ds && m_features.depth_feedback && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
(ds_feedbackloop_pass1 || ds_feedbackloop_pass2))
{
@@ -3034,7 +3032,7 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
const bool one_barrier, const bool full_barrier)
{
#ifdef PCSX2_DEVBUILD
if ((one_barrier || full_barrier) && !((config.tex && config.tex == draw_rt) || config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]]
if ((one_barrier || full_barrier) && !(config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]]
Console.Warning("D3D11: Possible unnecessary copy detected.");
#endif
@@ -3044,13 +3042,16 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
if ((one_barrier || full_barrier))
PSSetShaderResource(2, draw_rt_clone);
if (config.tex && config.tex == draw_rt)
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
PSSetShaderResource(0, draw_rt_clone);
}
if (draw_ds_clone)
{
CopyRect(draw_ds, draw_ds_clone, drawarea, drawarea.left, drawarea.top);
PSSetShaderResource(4, draw_ds_clone);
if ((one_barrier || full_barrier))
PSSetShaderResource(4, draw_ds_clone);
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH)
PSSetShaderResource(0, draw_ds_clone);
}
};
@@ -3081,7 +3082,8 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
if (one_barrier)
{
if (config.tex_hazard)
// DX11 can't do partial depth copies.
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
{
const GSVector4i union_rect = config.drawarea.runion(config.samplearea);
const u32 size_union = union_rect.width() * union_rect.height();
@@ -3110,7 +3112,7 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
void GSDevice11::SetRenderHWShaderResources(const GSHWDrawConfig& config, GSTexture* primid_texture)
{
if (config.tex && config.tex != config.rt)
if (config.tex && config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_NONE)
{
CommitClear(config.tex);
PSSetShaderResource(0, config.tex);
+2 -2
View File
@@ -4405,7 +4405,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt_clone, true);
if (config.tex && config.tex == draw_rt)
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
PSSetShaderResource(0, draw_rt_clone, true);
}
else
@@ -4569,7 +4569,7 @@ void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig&
#endif
if ((one_barrier || full_barrier) && feedback_rt)
PSSetShaderResource(2, draw_rt, false, true);
if (config.tex && config.tex == config.rt)
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
PSSetShaderResource(0, draw_rt, false, true);
if ((one_barrier || full_barrier) && feedback_depth)
PSSetShaderResource(4, draw_ds, false, true);
+19 -22
View File
@@ -7907,7 +7907,14 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
}
else if (ds && m_conf.tex == m_conf.ds)
{
if (g_gs_device->Features().feedback_loops())
// Check if we have depth feedback, if we do then we need to make a copy as
// GL/DX12 has issues with depth feedback and depth as rt will basically do the same.
const bool no_depth_write = (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTST == ZTST_NEVER);
if (g_gs_device->Features().test_and_sample_depth && no_depth_write)
{
return true;
}
else if (g_gs_device->Features().feedback_loops() && no_depth_write)
{
m_conf.tex_hazard = GSHWDrawConfig::TEX_HAZARD_DEPTH;
if (m_prim_overlap == PRIM_OVERLAP_NO || src_empty || m_channel_shuffle)
@@ -7971,13 +7978,17 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
{
// If this is our current Z buffer, we might not be able to read it directly if it's being written to.
// Rather than leaving the backend to do it, we'll check it here.
if ((!m_channel_shuffle || tex_diff == frame_diff) && g_gs_device->Features().test_and_sample_depth && (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTST == ZTST_NEVER))
if ((!m_channel_shuffle || tex_diff == frame_diff) && (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTST == ZTST_NEVER))
{
// Safe to read!
GL_CACHE("HW: Source is depth buffer, not writing, safe to read.");
unscaled_size = ds->GetUnscaledSize();
scale = ds->GetScale();
return;
// We need to make sure test_and_sample_depth is supported, otherwise we might still need a barrier/copy.
if (HandleBarrierHazard(true))
{
// Safe to read!
GL_CACHE("HW: Source is depth buffer, not writing, safe to read.");
unscaled_size = ds->GetUnscaledSize();
scale = ds->GetScale();
return;
}
}
if (!m_channel_shuffle)
@@ -8047,23 +8058,9 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
const int horizontal_offset = ((page_offset % src_target->m_TEX0.TBW) * GSLocalMemory::m_psm[src_target->m_TEX0.PSM].pgs.x);
const int vertical_offset = ((page_offset / src_target->m_TEX0.TBW) * GSLocalMemory::m_psm[src_target->m_TEX0.PSM].pgs.y);
if (g_gs_device->Features().feedback_loops())
if (HandleBarrierHazard(false))
{
const u32 max_skip = ((m_channel_shuffle_finish || !m_channel_shuffle_width) ? 1 : m_channel_shuffle_width) << 5;
const bool new_shuffle = !(m_last_channel_shuffle_fbmsk == m_context->FRAME.FBMSK &&
m_last_channel_shuffle_fbp <= m_context->FRAME.Block() && (m_last_channel_shuffle_fbp + max_skip) >= m_context->FRAME.Block() &&
m_last_channel_shuffle_end_block > m_context->FRAME.Block() && m_last_channel_shuffle_tbp <= m_context->TEX0.TBP0 && (m_last_channel_shuffle_tbp + max_skip) >= m_context->TEX0.TBP0);
if (rt == tex->m_from_target && new_shuffle)
{
if (m_prim_overlap == PRIM_OVERLAP_NO)
m_conf.require_one_barrier = true;
else
m_conf.require_full_barrier = true;
}
m_conf.cb_ps.ChannelShuffleOffset = GSVector2((horizontal_offset - m_r.x) * tex->GetScale(), (vertical_offset - m_r.y) * tex->GetScale());
m_conf.tex_hazard = GSHWDrawConfig::TEX_HAZARD_RT;
target_region = false;
source_region.bits = 0;
+7 -5
View File
@@ -2797,7 +2797,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
}
IASetPrimitiveTopology(topology);
if (config.tex && (m_features.texture_barrier || (config.tex != config.rt)))
if (config.tex && (m_features.texture_barrier || config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_NONE))
PSSetShaderResource(0, config.tex);
if (config.pal)
PSSetShaderResource(1, config.pal);
@@ -3038,8 +3038,7 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
const bool one_barrier, const bool full_barrier)
{
#ifdef PCSX2_DEVBUILD
if ((one_barrier || full_barrier) &&
!((!m_features.texture_barrier && config.tex && config.tex == draw_rt) || config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]]
if ((one_barrier || full_barrier) && !(config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]]
Console.Warning("OpenGL: Possible unnecessary barrier detected.");
#endif
@@ -3049,13 +3048,16 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
if ((one_barrier || full_barrier))
PSSetShaderResource(2, draw_rt_clone);
if (config.tex && config.tex == draw_rt)
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
PSSetShaderResource(0, draw_rt_clone);
}
if (draw_ds_clone)
{
CopyRect(draw_ds, draw_ds_clone, drawarea, drawarea.left, drawarea.top);
PSSetShaderResource(4, draw_ds_clone);
if ((one_barrier || full_barrier))
PSSetShaderResource(4, draw_ds_clone);
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH)
PSSetShaderResource(0, draw_ds_clone);
}
};
+2 -2
View File
@@ -2691,7 +2691,7 @@ bool GSDeviceVK::CheckFeatures()
m_features.framebuffer_fetch &= m_features.texture_barrier;
// Buggy drivers with broken barriers probably have no chance using GENERAL layout for depth either...
m_features.test_and_sample_depth = m_features.texture_barrier;
m_features.test_and_sample_depth = true;
// Use D32F depth instead of D32S8 when we have framebuffer fetch.
m_features.stencil_buffer &= !m_features.framebuffer_fetch;
@@ -6031,7 +6031,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt_clone, true);
if (config.tex && config.tex == draw_rt)
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
PSSetShaderResource(0, draw_rt_clone, true);
}
else