GS/HW: Use copies if barriers aren't supported properly.

VK/GL: Tex is fb requires the copy to be bound on slot 0 as well.
Fixes validation errors on VK when barriers are force disabled.

DX12: Always create a copy if barriers aren't supported for sw blend or tex is fb.
Fixes issues when barriers are force disabled.
This commit is contained in:
lightningterror
2025-12-19 11:32:45 +01:00
parent aab889535f
commit 579cb7bd27
3 changed files with 70 additions and 39 deletions

View File

@@ -3845,6 +3845,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
GSTexture12* colclip_rt = static_cast<GSTexture12*>(g_gs_device->GetColorClipTexture());
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
GSTexture12* draw_rt_clone = nullptr;
// Align the render area to 128x128, hopefully avoiding render pass restarts for small render area changes (e.g. Ratchet and Clank).
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
@@ -3999,6 +4000,25 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
}
const bool feedback = draw_rt && (config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier) || (config.tex && config.tex == config.rt));
if (feedback && !m_features.texture_barrier)
{
// Requires a copy of the RT.
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true));
if (draw_rt_clone)
{
GL_PUSH("D3D12: Copy RT to temp texture {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
EndRenderPass();
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt_clone, true);
if (config.tex && config.tex == config.rt)
PSSetShaderResource(0, draw_rt_clone, true);
}
else
Console.Warning("D3D12: Failed to allocate temp texture for RT copy.");
}
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
@@ -4082,6 +4102,9 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
if (date_image)
Recycle(date_image);
if (draw_rt_clone)
Recycle(draw_rt_clone);
// now blit the colclip texture back to the original target
if (colclip_rt)
{
@@ -4118,6 +4141,12 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig& config, GSTexture12* draw_rt, const bool feedback, const bool one_barrier, const bool full_barrier)
{
if (BindDrawPipeline(pipe) && !m_features.texture_barrier) [[unlikely]]
{
DrawIndexedPrimitive();
return;
}
if (feedback)
{
#ifdef PCSX2_DEVBUILD

View File

@@ -2430,6 +2430,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
GSTexture* primid_texture = nullptr;
GSTexture* draw_rt_clone = nullptr;
GSTexture* colclip_rt = g_gs_device->GetColorClipTexture();
if (colclip_rt)
@@ -2505,23 +2506,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
break;
}
GSTexture* draw_rt_clone = nullptr;
if (config.require_one_barrier && !m_features.texture_barrier)
{
// Requires a copy of the RT.
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, colclip_rt ? GSTexture::Format::ColorClip : GSTexture::Format::Color, true);
if (draw_rt_clone)
{
GL_PUSH("GL: Copy RT to temp texture {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
CopyRect(colclip_rt ? colclip_rt : config.rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
}
else
Console.Warning("GL: Failed to allocate temp texture for RT copy.");
}
IASetVertexBuffer(config.verts, config.nverts, GetVertexAlignment(config.vs.expand));
m_vertex.start *= GetExpansionFactor(config.vs.expand);
@@ -2550,9 +2534,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
PSSetShaderResource(0, config.tex);
if (config.pal)
PSSetShaderResource(1, config.pal);
if (draw_rt_clone)
PSSetShaderResource(2, draw_rt_clone);
else if (config.require_one_barrier || config.require_full_barrier)
if (m_features.texture_barrier && (config.require_one_barrier || config.require_full_barrier))
PSSetShaderResource(2, colclip_rt ? colclip_rt : config.rt);
SetupSampler(config.sampler);
@@ -2668,6 +2650,25 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
glTextureBarrier();
}
if (draw_rt && (config.require_one_barrier || (config.tex && config.tex == config.rt)) && !m_features.texture_barrier)
{
// Requires a copy of the RT.
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true);
if (draw_rt_clone)
{
GL_PUSH("GL: Copy RT to temp texture {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt_clone);
if (config.tex && config.tex == config.rt)
PSSetShaderResource(0, draw_rt_clone);
}
else
Console.Warning("GL: Failed to allocate temp texture for RT copy.");
}
OMSetRenderTargets(draw_rt, draw_ds, &config.scissor);
OMSetColorMaskState(config.colormask);
SetupOM(config.depth);

View File

@@ -5583,7 +5583,6 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config)
void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
{
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
GSTextureVK* draw_rt = static_cast<GSTextureVK*>(config.rt);
GSTextureVK* draw_ds = static_cast<GSTextureVK*>(config.ds);
@@ -5716,24 +5715,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
break;
}
if (config.require_one_barrier && !m_features.texture_barrier)
{
// requires a copy of the RT
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, colclip_rt ? GSTexture::Format::ColorClip : GSTexture::Format::Color, true));
if (draw_rt_clone)
{
EndRenderPass();
GL_PUSH("VK: Copy RT to temp texture for fbmask {%d,%d %dx%d}", config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
PSSetShaderResource(2, draw_rt_clone, true);
}
else
Console.Warning("VK: Failed to allocate temp texture for RT copy.");
}
// Switch to colclip target for colclip hw rendering
if (pipe.ps.colclip_hw)
{
@@ -5811,6 +5792,26 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
pipe.feedback_loop_flags |= m_current_framebuffer_feedback_loop;
}
if (draw_rt && (config.require_one_barrier || (config.tex && config.tex == config.rt)) && !m_features.texture_barrier)
{
// Requires a copy of the RT.
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true));
if (draw_rt_clone)
{
GL_PUSH("VK: Copy RT to temp texture {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
EndRenderPass();
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt_clone, true);
if (config.tex && config.tex == config.rt)
PSSetShaderResource(0, draw_rt_clone, true);
}
else
Console.Warning("VK: Failed to allocate temp texture for RT copy.");
}
// We don't need the very first barrier if this is the first draw after switching to feedback loop,
// because the layout change in itself enforces the execution dependency. colclip hw needs a barrier between
// setup and the first draw to read it. TODO: Make colclip hw use subpasses instead.