From 9cd0ec16346c621c0e440c32ff6920d8e2adf750 Mon Sep 17 00:00:00 2001 From: TJnotJT Date: Sun, 17 May 2026 14:24:59 -0400 Subject: [PATCH] GS/HW: Use sampled area for RT/DS sampling hazards. --- pcsx2/GS/Renderers/Common/GSDevice.cpp | 13 +++++++++- pcsx2/GS/Renderers/Common/GSDevice.h | 28 ++++++++++++++++---- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 31 ++++++++++++++++++++--- pcsx2/GS/Renderers/DX12/GSDevice12.cpp | 6 ++--- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 27 +++++++++++++++----- pcsx2/GS/Renderers/HW/GSRendererHW.h | 3 ++- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 31 +++++++++++++++++++---- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 8 +++--- 8 files changed, 118 insertions(+), 29 deletions(-) diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index a8a393308f..1857b4b51e 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -1426,6 +1426,17 @@ static const char* GetPSAA1Name(u32 aa1) return "Unknown"; } +static const char* GetTexHazardName(u32 tex_hazard) +{ + switch (tex_hazard) + { + case GSHWDrawConfig::TEX_HAZARD_NONE: return "NONE"; + case GSHWDrawConfig::TEX_HAZARD_RT: return "RT"; + case GSHWDrawConfig::TEX_HAZARD_DEPTH: return "DEPTH"; + } + return "Unknown"; +} + static void DumpPSSelector(DrawConfigWriter& out, const GSHWDrawConfig::PSSelector& ps) { out.WriteLn("aem_fmt: {}", ps.aem_fmt); @@ -1469,7 +1480,6 @@ static void DumpPSSelector(DrawConfigWriter& out, const GSHWDrawConfig::PSSelect out.WriteLn("no_color: {}", ps.no_color); out.WriteLn("no_color1: {}", ps.no_color1); out.WriteLn("channel: {} ({})", GetPSChannelName(static_cast(ps.channel)), ps.channel); - out.WriteLn("tex_hazard: {}", ps.tex_hazard); out.WriteLn("dither: {} ({})", GetPSDitherName(ps.dither), ps.dither); out.WriteLn("dither_adjust: {}", ps.dither_adjust); out.WriteLn("zclamp: {}", ps.zclamp); @@ -1608,6 +1618,7 @@ static void DumpConfig(DrawConfigWriter& out, const GSHWDrawConfig& conf, out.WriteLn("topology: {} ({})", GetTopologyName(conf.topology), static_cast(conf.topology)); out.WriteLn("require_one_barrier: {}", conf.require_one_barrier); out.WriteLn("require_full_barrier: {}", conf.require_full_barrier); + out.WriteLn("tex_hazard: {}", GetTexHazardName(conf.tex_hazard)); out.WriteLn("destination_alpha: {} ({})", GetDestinationAlphaModeName(conf.destination_alpha), static_cast(conf.destination_alpha)); out.WriteLn("datm: {} ({})", GetSetDATMName(conf.datm), static_cast(conf.datm)); diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index d9235e7237..bc5419cd9e 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -397,7 +397,6 @@ struct alignas(16) GSHWDrawConfig // Others ways to fetch the texture u32 channel : 3; - u32 tex_hazard : 2; // 1 rt, 2 ds // Dithering u32 dither : 2; @@ -445,7 +444,7 @@ struct alignas(16) GSHWDrawConfig const u32 sw_blend_bits = blend_a | blend_b | blend_d; const bool sw_blend_needs_rt = (sw_blend_bits != 0 && ((sw_blend_bits | blend_c) & 1u)) || ((a_masked & blend_c) != 0); const bool afail_needs_rt = afail == PS_AFAIL::ZB_ONLY || afail == PS_AFAIL::RGB_ONLY || afail == PS_AFAIL::RGB_ONLY_SW_Z; - return tex_hazard == 1 || tex_is_fb || fbmask || (date >= 5) || sw_blend_needs_rt || afail_needs_rt; + return tex_is_fb || fbmask || (date >= 5) || sw_blend_needs_rt || afail_needs_rt; } __fi bool IsFeedbackLoopDepth() const @@ -453,7 +452,7 @@ struct alignas(16) GSHWDrawConfig const bool afail_needs_depth = afail == PS_AFAIL::FB_ONLY || afail == PS_AFAIL::RGB_ONLY_SW_Z; const bool ztst_needs_depth = ztst == ZTST_GEQUAL || ztst == ZTST_GREATER; const bool aa1_needs_depth = aa1 == PS_AA1::TRIANGLE_SW_Z; - return tex_hazard == 2 || afail_needs_depth || ztst_needs_depth || aa1_needs_depth; + return afail_needs_depth || ztst_needs_depth || aa1_needs_depth; } /// Disables color output from the pixel shader, this is done when all channels are masked. @@ -820,10 +819,12 @@ struct alignas(16) GSHWDrawConfig u32 nverts; ///< Number of vertices u32 nindices; ///< Number of indices u32 indices_per_prim; ///< Number of indices that make up one primitive - const std::vector* drawlist; ///< For reducing barriers on sprites - const std::vector* drawlist_bbox; ///< For RT copy when barriers not available. + const std::vector* drawlist; ///< For reducing barriers on sprites + const std::vector* drawlist_bbox; ///< For RT copy when barriers not available. + const std::vector* drawlist_bbox_tex; ///< Additionally if we need to sample not from the same pixel of the RT. GSVector4i scissor; ///< Scissor rect GSVector4i drawarea; ///< Area in the framebuffer which will be modified. + GSVector4i samplearea; ///< Area in the texture which will be sampled. Topology topology; ///< Draw topology alignas(8) PSSelector ps; @@ -837,6 +838,13 @@ struct alignas(16) GSHWDrawConfig bool require_one_barrier; ///< Require texture barrier before draw (also used to requst an rt copy if texture barrier isn't supported) bool require_full_barrier; ///< Require texture barrier between all prims + enum : u32 + { + TEX_HAZARD_NONE, + TEX_HAZARD_RT, + TEX_HAZARD_DEPTH, + } tex_hazard; + AlphaTestMode alpha_test; DestinationAlphaMode destination_alpha; @@ -877,6 +885,16 @@ struct alignas(16) GSHWDrawConfig GIFRegFRAME colclip_frame; GSVector4i colclip_update_area; ///< Area in the framebuffer which colclip will modify; + __fi bool IsFeedbackLoopRT(const PSSelector& ps) const + { + return ps.IsFeedbackLoopRT() || (tex_hazard == TEX_HAZARD_RT); + } + + __fi bool IsFeedbackLoopDepth(const PSSelector& ps) const + { + return ps.IsFeedbackLoopDepth() || (tex_hazard == TEX_HAZARD_DEPTH); + } + // Dumping static void DumpConfig(const std::string& path, const GSHWDrawConfig& conf, bool ps = true, bool vs = true, bool bs = true, bool dss = true, bool ss = true, bool asp = true, bool bmp = true, diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 6f4d37c2ff..c53587a012 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -2948,8 +2948,8 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) draw_ds = m_state.current_ds; } - const bool rt_feedbackloop_pass1 = config.ps.IsFeedbackLoopRT(); - const bool rt_feedbackloop_pass2 = config.alpha_second_pass.ps.IsFeedbackLoopRT(); + const bool rt_feedbackloop_pass1 = config.IsFeedbackLoopRT(config.ps); + const bool rt_feedbackloop_pass2 = config.IsFeedbackLoopRT(config.alpha_second_pass.ps); if (draw_rt && (((config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) && (rt_feedbackloop_pass1 || rt_feedbackloop_pass2)))) { @@ -3034,7 +3034,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.ps.IsFeedbackLoopRT() || config.ps.IsFeedbackLoopDepth())) [[unlikely]] + if ((one_barrier || full_barrier) && !((config.tex && config.tex == draw_rt) || config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]] Console.Warning("D3D11: Possible unnecessary copy detected."); #endif @@ -3080,7 +3080,30 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config, } if (one_barrier) - CopyAndBind(ProcessCopyArea(rtsize, config.drawarea)); + { + if (config.tex_hazard) + { + GSVector4i union_rect = config.drawarea.runion(config.samplearea); + u32 size_union = union_rect.width() * union_rect.height(); + u32 size_indiv = config.drawarea.width() * config.drawarea.height() + + config.samplearea.width() * config.samplearea.height(); + + // Do an individual copy if the union is larger than the sum of individual areas. + if (size_union > size_indiv) + { + CopyAndBind(ProcessCopyArea(rtsize, config.drawarea)); + CopyAndBind(ProcessCopyArea(rtsize, config.samplearea)); + } + else + { + CopyAndBind(ProcessCopyArea(rtsize, union_rect)); + } + } + else + { + CopyAndBind(ProcessCopyArea(rtsize, config.drawarea)); + } + } Draw(config); } diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index 0e1f445505..f579204335 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -4364,8 +4364,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) GSTexture12* draw_ds_as_rt = static_cast(m_ds_as_rt); - const bool feedback_rt = draw_rt && (((config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier)) && (config.ps.IsFeedbackLoopRT() || - config.alpha_second_pass.ps.IsFeedbackLoopRT()))); + const bool feedback_rt = draw_rt && (((config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier)) && (config.IsFeedbackLoopRT(config.ps) || + config.IsFeedbackLoopRT(config.alpha_second_pass.ps)))); const bool feedback_depth = draw_ds_as_rt != nullptr; if (feedback_rt && !m_features.texture_barrier) @@ -4541,7 +4541,7 @@ void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig& if (feedback_rt || feedback_depth) { #ifdef PCSX2_DEVBUILD - if ((one_barrier || full_barrier) && !(config.ps.IsFeedbackLoopRT() || config.ps.IsFeedbackLoopDepth())) [[unlikely]] + if ((one_barrier || full_barrier) && !(config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]] Console.Warning("D3D12: Possible unnecessary barrier detected."); #endif if ((one_barrier || full_barrier) && feedback_rt) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 02fc19e352..2d76cb2a5a 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -1351,13 +1351,20 @@ GSVector4 GSRendererHW::RealignTargetTextureCoordinate(const GSTextureCache::Sou return half_offset; } -GSVector4i GSRendererHW::ComputeBoundingBox(const GSVector2i& rtsize, float rtscale) +GSVector4i GSRendererHW::ComputeBoundingBoxRT(const GSVector2i& rtsize, float rtscale) { const GSVector4 offset = GSVector4(-1.0f, 1.0f); // Round value const GSVector4 box = m_vt.m_min.p.upld(m_vt.m_max.p) + offset.xxyy(); return GSVector4i(box * GSVector4(rtscale)).rintersect(GSVector4i(0, 0, rtsize.x, rtsize.y)); } +GSVector4i GSRendererHW::ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& region, float texscale) +{ + const GSVector4 offset = GSVector4(region.xyxy()) + GSVector4(-1.0f, -1.0f, 1.0f, 1.0f); // Region offset + round value + const GSVector4 box = m_vt.m_min.t.upld(m_vt.m_max.t) + offset; + return GSVector4i(box * GSVector4(texscale)).rintersect(GSVector4i(0, 0, texsize.x, texsize.y)); +} + void GSRendererHW::MergeSprite(GSTextureCache::Source* tex) { // Upscaling hack to avoid various line/grid issues @@ -7884,7 +7891,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c auto HandleBarrierHazard = [&](bool src_empty) { if (rt && m_conf.tex == m_conf.rt) { - m_conf.ps.tex_hazard = 1; + m_conf.tex_hazard = GSHWDrawConfig::TEX_HAZARD_RT; if (m_prim_overlap == PRIM_OVERLAP_NO || src_empty || m_channel_shuffle || !g_gs_device->Features().feedback_loops()) m_conf.require_one_barrier = true; else @@ -7900,7 +7907,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c // TODO: Add gpu copies for depth on VK/DX12 that doesn't rely on feedback loops. else if (g_gs_device->Features().feedback_loops()) { - m_conf.ps.tex_hazard = 2; + m_conf.tex_hazard = GSHWDrawConfig::TEX_HAZARD_DEPTH; if (m_prim_overlap == PRIM_OVERLAP_NO || src_empty || m_channel_shuffle) m_conf.require_one_barrier = true; else @@ -8046,7 +8053,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c } m_conf.cb_ps.ChannelShuffleOffset = GSVector2((horizontal_offset - m_r.x) * tex->GetScale(), (vertical_offset - m_r.y) * tex->GetScale()); - m_conf.ps.tex_hazard = 1; + m_conf.tex_hazard = GSHWDrawConfig::TEX_HAZARD_RT; target_region = false; source_region.bits = 0; @@ -8722,7 +8729,7 @@ void GSRendererHW::EmulateAlphaTestSecondPass() { m_conf.alpha_second_pass.ps.DisableDepthOutput(); } - if (m_conf.alpha_second_pass.ps.IsFeedbackLoopRT() || m_conf.alpha_second_pass.ps.IsFeedbackLoopDepth()) + if (m_conf.IsFeedbackLoopRT(m_conf.alpha_second_pass.ps) || m_conf.IsFeedbackLoopDepth(m_conf.alpha_second_pass.ps)) { m_conf.alpha_second_pass.require_one_barrier = m_conf.require_one_barrier; m_conf.alpha_second_pass.require_full_barrier = m_conf.require_full_barrier; @@ -8968,6 +8975,9 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta const float rtscale = rt_or_ds->GetScale(); const GSVector2i rtsize = rt_or_ds->GetTexture()->GetSize(); const GSVector2i rt_unscaled_size = rt_or_ds->GetUnscaledSize(); + + const float texscale = tex ? tex->GetScale() : 0.0f; + const GSVector2i texsize = tex ? tex->GetTexture()->GetSize() : GSVector2i(0, 0); // Vertex shader config float vs_scale_x, vs_scale_y; @@ -9014,7 +9024,12 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta const GSVector4i hacked_scissor = m_channel_shuffle ? GSVector4i::cxpr(0, 0, 1024, 1024) : m_context->scissor.in; const GSVector4i scissor(GSVector4i(GSVector4(rtscale) * GSVector4(hacked_scissor)).rintersect(GSVector4i::loadh(rtsize))); - m_conf.drawarea = m_channel_shuffle ? scissor : scissor.rintersect(ComputeBoundingBox(rtsize, rtscale)); + m_conf.drawarea = m_channel_shuffle ? scissor : scissor.rintersect(ComputeBoundingBoxRT(rtsize, rtscale)); + + const GSVector4i tex_region = tex ? tex->GetRegionRect() : GSVector4i::zero(); + m_conf.samplearea = m_channel_shuffle ? scissor : + GSVector4i::loadh(texsize).rintersect(ComputeBoundingBoxTex(texsize, tex_region, texscale)); + m_conf.scissor = (date_options.enabled && !date_options.barrier) ? m_conf.drawarea : scissor; HandleProvokingVertexFirst(); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index e83404cae4..042291240d 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -349,7 +349,8 @@ public: bool VerifyIndices(); void ExpandLineIndices(); GSVector4 RealignTargetTextureCoordinate(const GSTextureCache::Source* tex); - GSVector4i ComputeBoundingBox(const GSVector2i& rtsize, float rtscale); + GSVector4i ComputeBoundingBoxRT(const GSVector2i& rtsize, float rtscale); + GSVector4i ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& region, float texscale); void MergeSprite(GSTextureCache::Source* tex); float GetTextureScaleFactor() override; GSVector2i GetValidSize(const GSTextureCache::Source* tex = nullptr, const bool is_shuffle = false); diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index e8e112b722..94972c7f55 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -2828,7 +2828,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config) // Pretty sure GL is supposed to guarantee that the blend unit is coherent with previous pixel write out, so calling this a bug. bool broken_blend_coherency_barrier = false; if (m_bugs.broken_blend_coherency) - broken_blend_coherency_barrier = (psel.ps.IsFeedbackLoopRT() || psel.ps.blend_c == 1) && GLState::rt == config.rt; + broken_blend_coherency_barrier = (config.IsFeedbackLoopRT(psel.ps) || psel.ps.blend_c == 1) && GLState::rt == config.rt; if (config.require_one_barrier || !m_features.texture_barrier) { broken_blend_coherency_barrier = false; @@ -2929,8 +2929,8 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config) glTextureBarrier(); } - const bool rt_feedbackloop_pass1 = config.ps.IsFeedbackLoopRT(); - const bool rt_feedbackloop_pass2 = config.alpha_second_pass.ps.IsFeedbackLoopRT(); + const bool rt_feedbackloop_pass1 = config.IsFeedbackLoopRT(config.ps); + const bool rt_feedbackloop_pass2 = config.IsFeedbackLoopRT(config.alpha_second_pass.ps); if (draw_rt && !m_features.texture_barrier && (((config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) && (rt_feedbackloop_pass1 || rt_feedbackloop_pass2)))) { @@ -3039,7 +3039,7 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config, { #ifdef PCSX2_DEVBUILD if ((one_barrier || full_barrier) && - !((!m_features.texture_barrier && config.tex && config.tex == draw_rt) || config.ps.IsFeedbackLoopRT() || config.ps.IsFeedbackLoopDepth())) [[unlikely]] + !((!m_features.texture_barrier && config.tex && config.tex == draw_rt) || config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]] Console.Warning("OpenGL: Possible unnecessary barrier detected."); #endif @@ -3104,7 +3104,28 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config, else { // Optimization: For alpha second pass we can reuse the copy snapshot from the first pass. - CopyAndBind(ProcessCopyArea(rtsize, config.drawarea)); + if (config.tex_hazard) + { + GSVector4i union_rect = config.drawarea.runion(config.samplearea); + u32 size_union = union_rect.width() * union_rect.height(); + u32 size_indiv = config.drawarea.width() * config.drawarea.height() + + config.samplearea.width() * config.samplearea.height(); + + // Do an individual copy if the union is larger than the sum of individual areas. + if (size_union > size_indiv) + { + CopyAndBind(ProcessCopyArea(rtsize, config.drawarea)); + CopyAndBind(ProcessCopyArea(rtsize, config.samplearea)); + } + else + { + CopyAndBind(ProcessCopyArea(rtsize, union_rect)); + } + } + else + { + CopyAndBind(ProcessCopyArea(rtsize, config.drawarea)); + } } } diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 773f6e7772..4c079618ad 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -5994,7 +5994,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) pipe.feedback_loop_flags |= m_current_framebuffer_feedback_loop; } - if (draw_rt && ((config.require_one_barrier && (config.ps.IsFeedbackLoopRT() || config.alpha_second_pass.ps.IsFeedbackLoopRT()))) && !m_features.texture_barrier) + if (draw_rt && ((config.require_one_barrier && (config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopRT(config.alpha_second_pass.ps)))) && !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)); @@ -6222,10 +6222,10 @@ void GSDeviceVK::UpdateHWPipelineSelector(GSHWDrawConfig& config, PipelineSelect pipe.feedback_loop_flags = FeedbackLoopFlag_None; if (m_features.texture_barrier && (config.require_one_barrier || config.require_full_barrier)) { - if (config.ps.IsFeedbackLoopRT()) + if (config.IsFeedbackLoopRT(config.ps)) pipe.feedback_loop_flags |= FeedbackLoopFlag_ReadAndWriteRT; - if (config.ps.IsFeedbackLoopDepth()) + if (config.IsFeedbackLoopDepth(config.ps)) pipe.feedback_loop_flags |= FeedbackLoopFlag_ReadAndWriteDepth; } if (!(pipe.feedback_loop_flags & FeedbackLoopFlag_ReadAndWriteDepth)) @@ -6297,7 +6297,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, } #ifdef PCSX2_DEVBUILD - if ((one_barrier || full_barrier) && !(m_pipeline_selector.ps.IsFeedbackLoopRT() || m_pipeline_selector.ps.IsFeedbackLoopDepth())) [[unlikely]] + if ((one_barrier || full_barrier) && !(config.IsFeedbackLoopRT(m_pipeline_selector.ps) || config.IsFeedbackLoopDepth(m_pipeline_selector.ps))) [[unlikely]] Console.Warning("VK: Possible unnecessary barrier detected."); #endif VkDependencyFlags barrier_flags = GetFeedbackBarrierDependencyFlags();