GS/HW: Avoid hazard copy if read and draw don't overlap + fix CSBW typo

This commit is contained in:
refractionpcsx2
2026-05-23 11:14:46 +02:00
committed by lightningterror
parent f86cd4c3d2
commit 054e0509c4
+32 -6
View File
@@ -7884,10 +7884,10 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
const GSTextureCache::Target* src_target = nullptr;
if (!m_downscale_source || !tex->m_from_target)
{
if (rt && m_conf.tex == m_conf.rt && !(m_channel_shuffle && tex && tex_diff != frame_diff))
if (rt && m_conf.tex == m_conf.rt)
{
// Can we read the framebuffer directly? (i.e. sample location matches up).
if (CanUseTexIsFB(rt, tex, tmm))
if (CanUseTexIsFB(rt, tex, tmm) && !(m_channel_shuffle && tex_diff != frame_diff))
{
m_conf.tex = nullptr;
m_conf.ps.tex_is_fb = true;
@@ -7901,18 +7901,30 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
return;
}
if (!m_channel_shuffle)
{
const GSVector4i src_box_rect = GSVector4i(m_vt.m_min.t.x, m_vt.m_min.t.y, m_vt.m_max.t.x, m_vt.m_max.t.y);
const GSVector4i src_rect = src_box_rect + source_region.GetRect(rt->GetUnscaledSize().x, rt->GetUnscaledSize().y).xyxy();
// If the two don't overlap, there's no need to copy.
if (m_r.rintersect(src_rect).rempty())
{
unscaled_size = rt->GetUnscaledSize();
scale = rt->GetScale();
return;
}
}
GL_CACHE("HW: Source is render target, taking copy.");
src_target = rt;
}
// Be careful of single page channel shuffles where depth is the source but it's not going to the same place, we can't read this directly.
else if (ds && m_conf.tex == m_conf.ds && (!m_channel_shuffle || (rt && static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) == static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0))))
else if (ds && m_conf.tex == m_conf.ds)
{
// GL, Vulkan (in General layout), DirectX11 (binding dsv as read only) no support for DirectX12 yet!
const bool can_read_current_depth_buffer = g_gs_device->Features().test_and_sample_depth;
// 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 (can_read_current_depth_buffer && (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTST == ZTST_NEVER))
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))
{
// Safe to read!
GL_CACHE("HW: Source is depth buffer, not writing, safe to read.");
@@ -7921,6 +7933,20 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
return;
}
if (!m_channel_shuffle)
{
const GSVector4i src_box_rect = GSVector4i(m_vt.m_min.t.x, m_vt.m_min.t.y, m_vt.m_max.t.x, m_vt.m_max.t.y);
const GSVector4i src_rect = src_box_rect + source_region.GetRect(rt->GetUnscaledSize().x, rt->GetUnscaledSize().y).xyxy();
// If the two don't overlap, there's no need to copy.
if (m_r.rintersect(src_rect).rempty())
{
unscaled_size = ds->GetUnscaledSize();
scale = ds->GetScale();
return;
}
}
// Can't safely read the depth buffer, so we need to take a copy of it.
GL_CACHE("HW: Source is depth buffer, unsafe to read, taking copy.");
src_target = ds;
@@ -9266,7 +9292,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
else
{
// If the target isn't dirty we might have valid data, so let's check their areas overlap, if so we need to read it back for SW.
GSVector4i src_rect = GSVector4i(m_vt.m_min.t.x, m_vt.m_min.t.y, m_vt.m_max.t.x, m_vt.m_max.t.x);
GSVector4i src_rect = GSVector4i(m_vt.m_min.t.x, m_vt.m_min.t.y, m_vt.m_max.t.x, m_vt.m_max.t.y);
GSVector4i area = g_texture_cache->TranslateAlignedRectByPage(src_target, m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.PSM, m_cached_ctx.TEX0.TBW, src_rect, false);
req_readback = !area.rintersect(src_target->m_drawn_since_read).eq(GSVector4i::zero());
}