From 2954ebe6965669219f1bbd256e958fbd8f83a85d Mon Sep 17 00:00:00 2001 From: TJnotJT Date: Thu, 8 Oct 2026 22:54:58 -0400 Subject: [PATCH] GS:VK: Cleanup render pass handling. Rewrite render pass builder. Make a begin/end present render pass function. Rename `depth_sampling` to `depth_feedback`. --- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 306 ++++++++++------------ pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h | 14 +- pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp | 2 +- pcsx2/GS/Renderers/Vulkan/GSTextureVK.h | 2 + pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp | 262 +++++++++++------- pcsx2/GS/Renderers/Vulkan/VKBuilders.h | 95 ++++--- 6 files changed, 388 insertions(+), 293 deletions(-) diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 9012532f29..13b891d949 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -144,6 +144,13 @@ static constexpr const char* s_required_device_extensions[] = { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, }; +static constexpr VkPipelineStageFlags2 s_color_feedback_src_stage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; +static constexpr VkPipelineStageFlags2 s_color_feedback_src_access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; +static constexpr VkPipelineStageFlags2 s_depth_feedback_src_stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT + | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; +static constexpr VkPipelineStageFlags2 s_depth_feedback_src_access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT + | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; GSDeviceVK::GSDeviceVK() { #ifdef ENABLE_OGL_DEBUG @@ -1059,7 +1066,7 @@ VkRenderPass GSDeviceVK::GetRenderPass(VkFormat color_format, VkFormat depth_for VkAttachmentLoadOp color_load_op, VkAttachmentStoreOp color_store_op, VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op, VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op, - bool color_feedback_loop, bool depth_sampling) + bool color_feedback_loop, bool depth_feedback_loop) { RenderPassCacheKey key = {}; key.color_format = color_format; @@ -1071,7 +1078,7 @@ VkRenderPass GSDeviceVK::GetRenderPass(VkFormat color_format, VkFormat depth_for key.stencil_load_op = stencil_load_op; key.stencil_store_op = stencil_store_op; key.color_feedback_loop = color_feedback_loop; - key.depth_sampling = depth_sampling; + key.depth_feedback_loop = depth_feedback_loop; auto it = m_render_pass_cache.find(key.key); if (it != m_render_pass_cache.end()) @@ -1669,129 +1676,63 @@ void GSDeviceVK::DisableDebugUtils() VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) { - VkAttachmentReference color_reference; - VkAttachmentReference* color_reference_ptr = nullptr; - VkAttachmentReference depth_reference; - VkAttachmentReference* depth_reference_ptr = nullptr; - std::array input_reference; - u32 num_subpass_inputs = 0; - std::array subpass_dependencies; - u32 num_subpass_dependencies = 0; - std::array attachments; - u32 num_attachments = 0; + Vulkan::RenderPassBuilder rpb; + + const GSTextureVK::Layout color_layout = + key.color_feedback_loop ? GSTextureVK::Layout::FeedbackLoop : GSTextureVK::Layout::ColorAttachment; + + const GSTextureVK::Layout depth_layout = + key.depth_feedback_loop ? + (m_features.depth_feedback ? GSTextureVK::Layout::FeedbackLoop : GSTextureVK::Layout::General) : + GSTextureVK::Layout::DepthStencilAttachment; + + const VkDependencyFlags feedback_dependency = GetFeedbackBarrierDependencyFlags(); + + if (key.color_feedback_loop) + { + rpb.SetColorFeedbackBarrier( + s_color_feedback_src_stage, s_color_feedback_src_access, + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, static_cast(GetFeedbackLoopInputAccessFlags()), + feedback_dependency); + if (m_features.framebuffer_fetch) + rpb.AddSubpassFlags(VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT); + } + + if (key.depth_feedback_loop) + { + rpb.SetDepthFeedbackBarrier( + s_depth_feedback_src_stage, s_depth_feedback_src_access, + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, static_cast(GetFeedbackLoopInputAccessFlags()), + feedback_dependency); + } + if (key.color_format != VK_FORMAT_UNDEFINED) { - const VkImageLayout layout = key.color_feedback_loop ? GetFeedbackLoopLayout() : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentDescription& attachment = attachments[num_attachments] = {}; - attachment.format = static_cast(key.color_format); - attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.loadOp = static_cast(key.color_load_op); - attachment.storeOp = static_cast(key.color_store_op); - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = layout; - attachment.finalLayout = layout; - color_reference.attachment = num_attachments; - color_reference.layout = layout; - color_reference_ptr = &color_reference; - - if (key.color_feedback_loop) - { - if (!UseFeedbackLoopLayout()) - { - input_reference[num_subpass_inputs].attachment = num_attachments; - input_reference[num_subpass_inputs].layout = layout; - num_subpass_inputs++; - } - - if (!m_features.framebuffer_fetch) - { - // don't need the framebuffer-local dependency when we have rasterization order attachment access - VkSubpassDependency& subpass_dependency = subpass_dependencies[num_subpass_dependencies++]; - subpass_dependency.srcSubpass = 0; - subpass_dependency.dstSubpass = 0; - subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - subpass_dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - subpass_dependency.dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); - subpass_dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags(); - } - } - - num_attachments++; + rpb.AddColorAttachment( + GSTextureVK::GetVkImageLayout(color_layout), + static_cast(key.color_format), + static_cast(key.color_load_op), + static_cast(key.color_store_op), + key.color_feedback_loop, + !UseFeedbackLoopLayout(), + !m_features.framebuffer_fetch); } + if (key.depth_format != VK_FORMAT_UNDEFINED) { - const VkImageLayout layout = - key.depth_sampling ? - ((m_features.depth_feedback && UseFeedbackLoopLayout()) ? - VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : - VK_IMAGE_LAYOUT_GENERAL) : - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - VkAttachmentDescription& attachment = attachments[num_attachments] = {}; - attachment.format = static_cast(key.depth_format); - attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.loadOp = static_cast(key.depth_load_op); - attachment.storeOp = static_cast(key.depth_store_op); - attachment.stencilLoadOp = static_cast(key.stencil_load_op); - attachment.stencilStoreOp = static_cast(key.stencil_store_op); - attachment.initialLayout = layout; - attachment.finalLayout = layout; - depth_reference.attachment = num_attachments; - depth_reference.layout = layout; - depth_reference_ptr = &depth_reference; - - if (key.depth_sampling) - { - if (!UseFeedbackLoopLayout()) - { - input_reference[num_subpass_inputs].attachment = num_attachments; - input_reference[num_subpass_inputs].layout = layout; - num_subpass_inputs++; - } - - if (!m_features.framebuffer_fetch) - { - // don't need the framebuffer-local dependency when we have rasterization order attachment access - VkSubpassDependency& subpass_dependency = subpass_dependencies[num_subpass_dependencies++]; - subpass_dependency.srcSubpass = 0; - subpass_dependency.dstSubpass = 0; - subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - subpass_dependency.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - subpass_dependency.dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); - subpass_dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags(); - } - } - - num_attachments++; + rpb.AddDepthStencilAttachment( + GSTextureVK::GetVkImageLayout(depth_layout), + static_cast(key.depth_format), + static_cast(key.depth_load_op), + static_cast(key.depth_store_op), + static_cast(key.stencil_load_op), + static_cast(key.stencil_store_op), + key.depth_feedback_loop, + !UseFeedbackLoopLayout(), + !m_features.framebuffer_fetch); } - VkSubpassDescription subpass = {}; - if (key.color_feedback_loop && m_features.framebuffer_fetch) - subpass.flags |= VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.inputAttachmentCount = num_subpass_inputs; - subpass.pInputAttachments = num_subpass_inputs ? input_reference.data() : nullptr; - subpass.colorAttachmentCount = color_reference_ptr ? 1 : 0; - subpass.pColorAttachments = color_reference_ptr; - subpass.pDepthStencilAttachment = depth_reference_ptr; - - VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; - pass_info.attachmentCount = num_attachments; - pass_info.pAttachments = attachments.data(); - pass_info.subpassCount = 1; - pass_info.pSubpasses = &subpass; - pass_info.dependencyCount = num_subpass_dependencies; - pass_info.pDependencies = num_subpass_dependencies ? subpass_dependencies.data() : nullptr; - - VkRenderPass pass; - const VkResult res = vkCreateRenderPass(m_device, &pass_info, nullptr, &pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: "); - return VK_NULL_HANDLE; - } + VkRenderPass pass = rpb.Create(m_device); m_render_pass_cache.emplace(key.key, pass); return pass; @@ -2588,17 +2529,13 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip) if (!frame_skip && m_current) static_cast(m_current)->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); - const VkFramebuffer fb = swap_chain_texture->GetFramebuffer(false); - if (fb == VK_NULL_HANDLE) - return GSDevice::PresentResult::FrameSkipped; + GSVector4i render_area(0, 0, swap_chain_texture->GetWidth(), swap_chain_texture->GetHeight()); - VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - rp.renderPass = GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); - rp.framebuffer = fb; - rp.renderArea = {{0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}; - rp.clearValueCount = 1; - rp.pClearValues = &s_present_clear_color; - vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE); + if (!BeginPresentRenderPass(GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED, + VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE), render_area, swap_chain_texture)) + { + return GSDevice::PresentResult::FrameSkipped; + } const VkViewport vp{0.0f, 0.0f, static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight()), 0.0f, 1.0f}; const VkRect2D scissor{{0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}; @@ -2612,10 +2549,8 @@ void GSDeviceVK::EndPresent() { RenderImGui(); - VkCommandBuffer cmdbuffer = GetCurrentCommandBuffer(); - vkCmdEndRenderPass(cmdbuffer); - m_is_presenting = false; - m_swap_chain->GetCurrentTexture()->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::PresentSrc); + EndPresentRenderPass(); + m_swap_chain->GetCurrentTexture()->TransitionToLayout(GetCurrentCommandBuffer(), GSTextureVK::Layout::PresentSrc); g_perfmon.Put(GSPerfMon::RenderPasses, 1); SubmitCommandBuffer(m_swap_chain.get()); @@ -4166,24 +4101,29 @@ bool GSDeviceVK::CreatePipelineLayouts() bool GSDeviceVK::CreateRenderPasses() { -#define GET(dest, rt, depth, fbl, dsp, opa, opb, opc) \ + const auto CreateHelper = [&](VkFormat rt, VkFormat depth, bool feedback_rt, bool feedback_depth, + VkAttachmentLoadOp load_rt, VkAttachmentLoadOp load_depth, VkAttachmentLoadOp load_stencil) + { + return GetRenderPass( + rt, + depth, + (rt != VK_FORMAT_UNDEFINED) ? load_rt : VK_ATTACHMENT_LOAD_OP_DONT_CARE, + (rt != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE, + (depth != VK_FORMAT_UNDEFINED) ? load_depth : VK_ATTACHMENT_LOAD_OP_DONT_CARE, + (depth != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE, + (depth != VK_FORMAT_UNDEFINED) ? load_stencil : VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + feedback_rt, + feedback_depth + ); + }; + +#define GET(dest, rt, depth, fbc, fbd, opc, opd, ops) \ do \ { \ - dest = GetRenderPass( \ - (rt), (depth), ((rt) != VK_FORMAT_UNDEFINED) ? (opa) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* color load */ \ - ((rt) != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : \ - VK_ATTACHMENT_STORE_OP_DONT_CARE, /* color store */ \ - ((depth) != VK_FORMAT_UNDEFINED) ? (opb) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* depth load */ \ - ((depth) != VK_FORMAT_UNDEFINED) ? VK_ATTACHMENT_STORE_OP_STORE : \ - VK_ATTACHMENT_STORE_OP_DONT_CARE, /* depth store */ \ - ((depth) != VK_FORMAT_UNDEFINED) ? (opc) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, /* stencil load */ \ - VK_ATTACHMENT_STORE_OP_DONT_CARE, /* stencil store */ \ - (fbl), /* feedback loop */ \ - (dsp) /* depth sampling */ \ - ); \ - if (dest == VK_NULL_HANDLE) \ - return false; \ - } while (0) + (dest) = CreateHelper(rt, depth, fbc, fbd, opc, opd, ops); \ + if (!(dest)) return false; \ + } while (false) const VkFormat rt_format = LookupNativeFormat(GSTexture::Format::Color); const VkFormat colclip_rt_format = LookupNativeFormat(GSTexture::Format::ColorClip); @@ -4197,23 +4137,24 @@ bool GSDeviceVK::CreateRenderPasses() { for (u32 stencil = 0; stencil < 2; stencil++) { - for (u32 fbl = 0; fbl < 2; fbl++) + for (u32 feedback_rt = 0; feedback_rt < 2; feedback_rt++) { - for (u32 dsp = 0; dsp < 2; dsp++) + for (u32 feedback_depth = 0; feedback_depth < 2; feedback_depth++) { - for (u32 opa = VK_ATTACHMENT_LOAD_OP_LOAD; opa <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opa++) + for (u32 load_rt = VK_ATTACHMENT_LOAD_OP_LOAD; load_rt <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; load_rt++) { - for (u32 opb = VK_ATTACHMENT_LOAD_OP_LOAD; opb <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opb++) + for (u32 load_depth = VK_ATTACHMENT_LOAD_OP_LOAD; load_depth <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; load_depth++) { - const VkFormat rp_rt_format = - (rt != 0) ? ((colclip != 0) ? colclip_rt_format : rt_format) : VK_FORMAT_UNDEFINED; + const VkFormat rp_rt_format = (rt != 0) ? ((colclip != 0) ? colclip_rt_format : rt_format) : VK_FORMAT_UNDEFINED; const VkFormat rp_depth_format = (ds != 0) ? depth_format : VK_FORMAT_UNDEFINED; - const VkAttachmentLoadOp opc = (!stencil || !m_features.stencil_buffer) ? - VK_ATTACHMENT_LOAD_OP_DONT_CARE : - VK_ATTACHMENT_LOAD_OP_LOAD; - GET(m_tfx_render_pass[rt][ds][colclip][stencil][fbl][dsp][opa][opb], rp_rt_format, - rp_depth_format, (fbl != 0), (dsp != 0), static_cast(opa), - static_cast(opb), static_cast(opc)); + const VkAttachmentLoadOp load_stencil = (!stencil || !m_features.stencil_buffer) ? + VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_LOAD; + + GET(m_tfx_render_pass[rt][ds][colclip][stencil][feedback_rt][feedback_depth][load_rt][load_depth], + rp_rt_format, rp_depth_format, feedback_rt, feedback_depth, + static_cast(load_rt), + static_cast(load_depth), + static_cast(load_stencil)); } } } @@ -5703,9 +5644,9 @@ void GSDeviceVK::BeginRenderPass(VkRenderPass rp, const GSVector4i& rect) begin_info.renderArea.offset.y = rect.y; begin_info.renderArea.extent.width = rect.width(); begin_info.renderArea.extent.height = rect.height(); + vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE); m_command_buffer_render_passes++; - vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE); } void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const VkClearValue* cv, u32 cv_count) @@ -5726,6 +5667,8 @@ void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, c begin_info.clearValueCount = cv_count; begin_info.pClearValues = cv; vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE); + + m_command_buffer_render_passes++; } void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color) @@ -5743,6 +5686,30 @@ void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, f BeginClearRenderPass(rp, rect, &cv, 1); } +bool GSDeviceVK::BeginPresentRenderPass(VkRenderPass rp, const GSVector4i& rect, GSTextureVK* swap_chain) +{ + if (m_current_render_pass != VK_NULL_HANDLE) + EndRenderPass(); + + VkFramebuffer fb = swap_chain->GetFramebuffer(false); + + if (fb == VK_NULL_HANDLE) + return false; + + VkRenderPassBeginInfo begin_info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + begin_info.renderPass = rp; + begin_info.framebuffer = fb; + begin_info.renderArea.offset.x = rect.x; + begin_info.renderArea.offset.y = rect.y; + begin_info.renderArea.extent.width = rect.width(); + begin_info.renderArea.extent.height = rect.height(); + begin_info.clearValueCount = 1; + begin_info.pClearValues = &s_present_clear_color; + vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE); + + return true; +} + void GSDeviceVK::EndRenderPass() { if (m_current_render_pass == VK_NULL_HANDLE) @@ -5754,6 +5721,15 @@ void GSDeviceVK::EndRenderPass() vkCmdEndRenderPass(GetCurrentCommandBuffer()); } +void GSDeviceVK::EndPresentRenderPass() +{ + g_perfmon.Put(GSPerfMon::RenderPasses, 1); + + vkCmdEndRenderPass(GetCurrentCommandBuffer()); + + m_is_presenting = false; +} + void GSDeviceVK::SetViewport(const VkViewport& viewport) { if (std::memcmp(&viewport, &m_viewport, sizeof(VkViewport)) == 0) @@ -6688,8 +6664,8 @@ void GSDeviceVK::FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds) if (rt) { VkImageMemoryBarrier2& barrier = barriers[num_barriers++] = barrier_template; - barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - barrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + barrier.srcStageMask = s_color_feedback_src_stage; + barrier.srcAccessMask = s_color_feedback_src_access; barrier.image = rt->GetImage(); barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } @@ -6697,8 +6673,8 @@ void GSDeviceVK::FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds) if (ds) { VkImageMemoryBarrier2& barrier = barriers[num_barriers++] = barrier_template; - barrier.srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; - barrier.srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barrier.srcStageMask = s_depth_feedback_src_stage; + barrier.srcAccessMask = s_depth_feedback_src_access; barrier.image = ds->GetImage(); barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; } diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index bd89088257..3ccaf38cd8 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -89,8 +89,8 @@ public: VkAttachmentLoadOp depth_load_op = VK_ATTACHMENT_LOAD_OP_LOAD, VkAttachmentStoreOp depth_store_op = VK_ATTACHMENT_STORE_OP_STORE, VkAttachmentLoadOp stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE, bool color_feedback_loop = false, - bool depth_sampling = false); + VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE, + bool color_feedback_loop = false, bool depth_feedback_loop = false); // Gets a non-clearing version of the specified render pass. Slow, don't call in hot path. VkRenderPass GetRenderPassForRestarting(VkRenderPass pass); @@ -176,7 +176,7 @@ private: u32 stencil_load_op : 2; u32 stencil_store_op : 1; u32 color_feedback_loop : 1; - u32 depth_sampling : 1; + u32 depth_feedback_loop : 1; }; u32 key; @@ -545,10 +545,10 @@ public: /// Returns true if Vulkan is suitable as a default for the devices in the system. static bool IsSuitableDefaultRenderer(); - __fi VkRenderPass GetTFXRenderPass(bool rt, bool ds, bool colclip, bool stencil, bool fbl, bool dsp, - VkAttachmentLoadOp rt_op, VkAttachmentLoadOp ds_op) const + __fi VkRenderPass GetTFXRenderPass(bool rt, bool ds, bool colclip, bool stencil, + bool rt_feedback, bool depth_feedback, VkAttachmentLoadOp rt_op, VkAttachmentLoadOp ds_op) const { - return m_tfx_render_pass[rt][ds][colclip][stencil][fbl][dsp][rt_op][ds_op]; + return m_tfx_render_pass[rt][ds][colclip][stencil][rt_feedback][depth_feedback][rt_op][ds_op]; } __fi VkSampler GetPointSampler() const { return m_point_sampler; } __fi VkSampler GetLinearSampler() const { return m_linear_sampler; } @@ -687,7 +687,9 @@ public: void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const VkClearValue* cv, u32 cv_count); void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color); void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, float depth, u8 stencil); + bool BeginPresentRenderPass(VkRenderPass rp, const GSVector4i& rect, GSTextureVK* swap_chain); void EndRenderPass(); + void EndPresentRenderPass(); void SetViewport(const VkViewport& viewport); void SetScissor(const GSVector4i& scissor); diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp index b53807e24f..8646abb008 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp @@ -35,7 +35,7 @@ static constexpr const VkComponentMapping s_identity_swizzle { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, }; -static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout) +VkImageLayout GSTextureVK::GetVkImageLayout(GSTextureVK::Layout layout) { static constexpr VkImageLayout s_vk_layout_mapping[] = { VK_IMAGE_LAYOUT_UNDEFINED, // Undefined diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h index a15180f40f..55ddbb6fa7 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h @@ -36,6 +36,8 @@ public: ~GSTextureVK() override; + static VkImageLayout GetVkImageLayout(Layout layout); + static std::unique_ptr Create(Usage usage, Format format, int width, int height, int levels); static std::unique_ptr Adopt( VkImage image, Usage usage, Format format, int width, int height, int levels, VkFormat vk_format); diff --git a/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp b/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp index bbec5beeed..18542d9659 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp +++ b/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp @@ -115,6 +115,178 @@ void Vulkan::LogVulkanResult(const char* func_name, VkResult res, const char* ms Console.Error("(%s) %s (%d: %s)", func_name, real_msg.c_str(), static_cast(res), VkResultToString(res)); } +void Vulkan::RenderPassBuilder::SetColorFeedbackBarrier( + VkPipelineStageFlags src_stage, VkAccessFlags src_access, + VkPipelineStageFlags dst_stage, VkAccessFlags dst_access, + VkDependencyFlags dependency) +{ + m_feedback_barriers.color_src_stage = src_stage; + m_feedback_barriers.color_src_access = src_access; + m_feedback_barriers.color_dst_stage = dst_stage; + m_feedback_barriers.color_dst_access = dst_access; + m_feedback_barriers.color_dependency = dependency; +} + +void Vulkan::RenderPassBuilder::SetDepthFeedbackBarrier( + VkPipelineStageFlags src_stage, VkAccessFlags src_access, + VkPipelineStageFlags dst_stage, VkAccessFlags dst_access, + VkDependencyFlags dependency) +{ + m_feedback_barriers.depth_src_stage = src_stage; + m_feedback_barriers.depth_src_access = src_access; + m_feedback_barriers.depth_dst_stage = dst_stage; + m_feedback_barriers.depth_dst_access = dst_access; + m_feedback_barriers.depth_dependency = dependency; +} + +void Vulkan::RenderPassBuilder::AddColorAttachment( + VkImageLayout layout, VkFormat format, VkAttachmentLoadOp load_op, VkAttachmentStoreOp store_op, + bool feedback_loop, bool input_reference, bool subpass_self_dependency) +{ + pxAssert(m_num_color_attachments < MAX_COLOR_ATTACHMENTS); + + m_attachments[m_num_attachments].flags = 0; + m_attachments[m_num_attachments].format = format; + m_attachments[m_num_attachments].samples = VK_SAMPLE_COUNT_1_BIT; + m_attachments[m_num_attachments].loadOp = load_op; + m_attachments[m_num_attachments].storeOp = store_op; + m_attachments[m_num_attachments].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + m_attachments[m_num_attachments].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + m_attachments[m_num_attachments].initialLayout = layout; + m_attachments[m_num_attachments].finalLayout = layout; + + m_color_reference[m_num_color_attachments].attachment = m_num_attachments; + m_color_reference[m_num_color_attachments].layout = layout; + m_num_color_attachments++; + + if (feedback_loop) + { + if (input_reference) + { + m_input_reference[m_num_subpass_inputs].attachment = m_num_attachments; + m_input_reference[m_num_subpass_inputs].layout = layout; + m_num_subpass_inputs++; + } + + if (subpass_self_dependency) + { + m_subpass_dependency[m_num_subpass_dependencies].srcSubpass = 0; + m_subpass_dependency[m_num_subpass_dependencies].dstSubpass = 0; + m_subpass_dependency[m_num_subpass_dependencies].srcStageMask = m_feedback_barriers.color_src_stage; + m_subpass_dependency[m_num_subpass_dependencies].dstStageMask = m_feedback_barriers.color_dst_stage; + m_subpass_dependency[m_num_subpass_dependencies].srcAccessMask = m_feedback_barriers.color_src_access; + m_subpass_dependency[m_num_subpass_dependencies].dstAccessMask = m_feedback_barriers.color_dst_access; + m_subpass_dependency[m_num_subpass_dependencies].dependencyFlags = m_feedback_barriers.color_dependency; + m_num_subpass_dependencies++; + } + } + + m_num_attachments++; +} + +void Vulkan::RenderPassBuilder::AddDepthStencilAttachment( + VkImageLayout layout, VkFormat depth_format, VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op, + VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op, + bool feedback_loop, bool input_reference, bool subpass_self_dependency) +{ + pxAssert(m_num_attachments < std::size(m_attachments)); + + m_attachments[m_num_attachments].flags = 0; + m_attachments[m_num_attachments].format = depth_format; + m_attachments[m_num_attachments].samples = VK_SAMPLE_COUNT_1_BIT; + m_attachments[m_num_attachments].loadOp = depth_load_op; + m_attachments[m_num_attachments].storeOp = depth_store_op; + m_attachments[m_num_attachments].stencilLoadOp = stencil_load_op; + m_attachments[m_num_attachments].stencilStoreOp = stencil_store_op; + m_attachments[m_num_attachments].initialLayout = layout; + m_attachments[m_num_attachments].finalLayout = layout; + + pxAssert(!m_has_depth_attachment); + m_depth_reference.attachment = m_num_attachments; + m_depth_reference.layout = layout; + m_has_depth_attachment = true; + + if (feedback_loop) + { + if (input_reference) + { + m_input_reference[m_num_subpass_inputs].attachment = m_num_attachments; + m_input_reference[m_num_subpass_inputs].layout = layout; + m_num_subpass_inputs++; + } + + if (subpass_self_dependency) + { + m_subpass_dependency[m_num_subpass_dependencies].srcSubpass = 0; + m_subpass_dependency[m_num_subpass_dependencies].dstSubpass = 0; + m_subpass_dependency[m_num_subpass_dependencies].srcStageMask = m_feedback_barriers.depth_src_stage; + m_subpass_dependency[m_num_subpass_dependencies].dstStageMask = m_feedback_barriers.depth_dst_stage; + m_subpass_dependency[m_num_subpass_dependencies].srcAccessMask = m_feedback_barriers.depth_src_access; + m_subpass_dependency[m_num_subpass_dependencies].dstAccessMask = m_feedback_barriers.depth_dst_access; + m_subpass_dependency[m_num_subpass_dependencies].dependencyFlags = m_feedback_barriers.depth_dependency; + m_num_subpass_dependencies++; + } + } + + m_num_attachments++; +} + +void Vulkan::RenderPassBuilder::AddSubpassFlags(VkSubpassDescriptionFlags subpass_flags) +{ + m_subpass_flags |= subpass_flags; +} + +VkRenderPass Vulkan::RenderPassBuilder::Create(VkDevice device) +{ + VkSubpassDescription subpass = {}; + subpass.flags = m_subpass_flags; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = m_num_subpass_inputs; + subpass.pInputAttachments = m_input_reference.data(); + subpass.colorAttachmentCount = m_num_color_attachments; + subpass.pColorAttachments = m_color_reference.data(); + subpass.pDepthStencilAttachment = m_has_depth_attachment ? &m_depth_reference : nullptr; + + VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; + pass_info.attachmentCount = m_num_attachments; + pass_info.pAttachments = m_attachments.data(); + pass_info.subpassCount = 1u; + pass_info.pSubpasses = &subpass; + pass_info.dependencyCount = m_num_subpass_dependencies; + pass_info.pDependencies = m_subpass_dependency.data(); + + VkRenderPass pass; + const VkResult res = vkCreateRenderPass(device, &pass_info, nullptr, &pass); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateRenderPass() failed: "); + } + + return pass; +} + +void Vulkan::RenderPassBuilder::Clear() +{ + m_color_reference = {}; + m_num_color_attachments = 0; + + m_depth_reference = {}; + m_has_depth_attachment = false; + + m_input_reference = {}; + m_num_subpass_inputs = 0; + + m_subpass_dependency = {}; + m_num_subpass_dependencies = 0; + + m_attachments = {}; + m_num_attachments = 0; + + m_feedback_barriers = {}; + + m_subpass_flags = 0; +} + Vulkan::DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder() { Clear(); @@ -957,96 +1129,6 @@ void Vulkan::FramebufferBuilder::SetRenderPass(VkRenderPass render_pass) m_ci.renderPass = render_pass; } -Vulkan::RenderPassBuilder::RenderPassBuilder() -{ - Clear(); -} - -void Vulkan::RenderPassBuilder::Clear() -{ - m_ci = {}; - m_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - m_attachments = {}; - m_attachment_references = {}; - m_num_attachment_references = 0; - m_subpasses = {}; -} - -VkRenderPass Vulkan::RenderPassBuilder::Create(VkDevice device, bool clear /*= true*/) -{ - VkRenderPass rp; - VkResult res = vkCreateRenderPass(device, &m_ci, nullptr, &rp); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass() failed: "); - return VK_NULL_HANDLE; - } - - return rp; -} - -u32 Vulkan::RenderPassBuilder::AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load_op, - VkAttachmentStoreOp store_op, VkImageLayout initial_layout, VkImageLayout final_layout) -{ - pxAssert(m_ci.attachmentCount < MAX_ATTACHMENTS); - - const u32 index = m_ci.attachmentCount; - VkAttachmentDescription& ad = m_attachments[index]; - ad.format = format; - ad.samples = samples; - ad.loadOp = load_op; - ad.storeOp = store_op; - ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - ad.initialLayout = initial_layout; - ad.finalLayout = final_layout; - - m_ci.attachmentCount++; - m_ci.pAttachments = m_attachments.data(); - - return index; -} - -u32 Vulkan::RenderPassBuilder::AddSubpass() -{ - pxAssert(m_ci.subpassCount < MAX_SUBPASSES); - - const u32 index = m_ci.subpassCount; - VkSubpassDescription& sp = m_subpasses[index]; - sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - - m_ci.subpassCount++; - m_ci.pSubpasses = m_subpasses.data(); - - return index; -} - -void Vulkan::RenderPassBuilder::AddSubpassColorAttachment(u32 subpass, u32 attachment, VkImageLayout layout) -{ - pxAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES); - - VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++]; - ar.attachment = attachment; - ar.layout = layout; - - VkSubpassDescription& sp = m_subpasses[subpass]; - if (sp.colorAttachmentCount == 0) - sp.pColorAttachments = &ar; - sp.colorAttachmentCount++; -} - -void Vulkan::RenderPassBuilder::AddSubpassDepthAttachment(u32 subpass, u32 attachment, VkImageLayout layout) -{ - pxAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES); - - VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++]; - ar.attachment = attachment; - ar.layout = layout; - - VkSubpassDescription& sp = m_subpasses[subpass]; - sp.pDepthStencilAttachment = &ar; -} - Vulkan::BufferViewBuilder::BufferViewBuilder() { Clear(); diff --git a/pcsx2/GS/Renderers/Vulkan/VKBuilders.h b/pcsx2/GS/Renderers/Vulkan/VKBuilders.h index 39806ffd9f..9cc80df6fe 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKBuilders.h +++ b/pcsx2/GS/Renderers/Vulkan/VKBuilders.h @@ -25,6 +25,70 @@ namespace Vulkan const char* VkResultToString(VkResult res); void LogVulkanResult(const char* func_name, VkResult res, const char* msg, ...); + // Only allows single subpass render passes. + class RenderPassBuilder + { + public: + static constexpr u32 MAX_COLOR_ATTACHMENTS = 1; + static constexpr u32 MAX_ATTACHMENTS = MAX_COLOR_ATTACHMENTS + 1; + + void AddColorAttachment(VkImageLayout layout, VkFormat format, + VkAttachmentLoadOp load_op, VkAttachmentStoreOp store_op, + bool feedback_loop, bool input_reference, bool subpass_self_dependency); + + void AddDepthStencilAttachment(VkImageLayout layout, VkFormat depth_format, + VkAttachmentLoadOp depth_load_op, VkAttachmentStoreOp depth_store_op, + VkAttachmentLoadOp stencil_load_op, VkAttachmentStoreOp stencil_store_op, + bool feedback_loop, bool input_reference, bool subpass_self_dependency); + + void SetColorFeedbackBarrier( + VkPipelineStageFlags src_stage, VkAccessFlags src_access, + VkPipelineStageFlags dst_stage, VkAccessFlags dst_access, + VkDependencyFlags dependency); + void SetDepthFeedbackBarrier( + VkPipelineStageFlags src_stage, VkAccessFlags src_access, + VkPipelineStageFlags dst_stage, VkAccessFlags dst_access, + VkDependencyFlags dependency); + + void AddSubpassFlags(VkSubpassDescriptionFlags subpass_flags); + + void Clear(); + + VkRenderPass Create(VkDevice device); + private: + std::array m_color_reference{}; + u32 m_num_color_attachments = 0; + + VkAttachmentReference m_depth_reference{}; + bool m_has_depth_attachment = false; + + std::array m_input_reference{}; + u32 m_num_subpass_inputs = 0; + + std::array m_subpass_dependency{}; + u32 m_num_subpass_dependencies = 0; + + std::array m_attachments{}; + u32 m_num_attachments = 0; + + VkSubpassDescriptionFlags m_subpass_flags = 0; + + struct + { + VkPipelineStageFlags color_src_stage; + VkAccessFlags color_src_access; + VkPipelineStageFlags color_dst_stage; + VkAccessFlags color_dst_access; + VkDependencyFlags color_dependency; + + VkPipelineStageFlags depth_src_stage; + VkAccessFlags depth_src_access; + VkPipelineStageFlags depth_dst_stage; + VkAccessFlags depth_dst_access; + VkDependencyFlags depth_dependency; + } m_feedback_barriers{}; + }; + class DescriptorSetLayoutBuilder { public: @@ -293,37 +357,6 @@ namespace Vulkan std::array m_images; }; - class RenderPassBuilder - { - enum : u32 - { - MAX_ATTACHMENTS = 2, - MAX_ATTACHMENT_REFERENCES = 2, - MAX_SUBPASSES = 1, - }; - - public: - RenderPassBuilder(); - - void Clear(); - - VkRenderPass Create(VkDevice device, bool clear = true); - - u32 AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load_op, - VkAttachmentStoreOp store_op, VkImageLayout initial_layout, VkImageLayout final_layout); - - u32 AddSubpass(); - void AddSubpassColorAttachment(u32 subpass, u32 attachment, VkImageLayout layout); - void AddSubpassDepthAttachment(u32 subpass, u32 attachment, VkImageLayout layout); - - private: - VkRenderPassCreateInfo m_ci; - std::array m_attachments; - std::array m_attachment_references; - u32 m_num_attachment_references = 0; - std::array m_subpasses; - }; - class BufferViewBuilder { public: