From 579cb7bd27338a18c2095b372c676fad960fa53b Mon Sep 17 00:00:00 2001 From: lightningterror <18107717+lightningterror@users.noreply.github.com> Date: Fri, 19 Dec 2025 11:32:45 +0100 Subject: [PATCH] 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. --- pcsx2/GS/Renderers/DX12/GSDevice12.cpp | 29 ++++++++++++++++ pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 41 ++++++++++++----------- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 39 ++++++++++----------- 3 files changed, 70 insertions(+), 39 deletions(-) diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index 44e79593ad..afdacb7682 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -3845,6 +3845,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) GSTexture12* colclip_rt = static_cast(g_gs_device->GetColorClipTexture()); GSTexture12* draw_rt = static_cast(config.rt); GSTexture12* draw_ds = static_cast(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(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 diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index bc871c61df..1b40001e70 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -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); diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index feac057b98..088be60a49 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -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(config.rt); GSTextureVK* draw_ds = static_cast(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(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(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.