From cf8633fe50daf30c649e74708d6c957304a8ccf2 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sat, 5 Sep 2026 21:32:23 -0500 Subject: [PATCH] GS:Vk: Use vkCmdPipelineBarrier2KHR Co-Authored-By: TJnotJT --- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 230 ++++++++----- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h | 6 +- pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp | 337 ++++++++------------ pcsx2/GS/Renderers/Vulkan/GSTextureVK.h | 9 +- pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl | 1 + 5 files changed, 304 insertions(+), 279 deletions(-) diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 9c5864ab32..55e6d65682 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -52,6 +52,67 @@ enum : u32 static u32 s_debug_scope_depth = 0; #endif +namespace ReplaceVK +{ + static VkPipelineStageFlags TranslateStageFlags(VkPipelineStageFlags2 flags2) + { + VkPipelineStageFlags flags = static_cast(flags2); + static constexpr VkPipelineStageFlags2 transfer = VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_RESOLVE_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT | VK_PIPELINE_STAGE_2_CLEAR_BIT; + if (flags2 & transfer) + flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; + assert(!(flags2 & ~transfer & ~static_cast(VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM))); + return flags; + } + + static VkAccessFlags TranslateAccessFlags(VkAccessFlags2 flags2) + { + VkAccessFlags flags = static_cast(flags2); + assert(!(flags2 & ~static_cast(VK_ACCESS_FLAG_BITS_MAX_ENUM))); + return flags; + } + + static void VKAPI_CALL CmdPipelineBarrier2(VkCommandBuffer commandBuffer, const VkDependencyInfo* RESTRICT pDependencyInfo) + { + assert(!pDependencyInfo->pNext); + VkDependencyFlags dependencyFlags = pDependencyInfo->dependencyFlags; + for (const VkMemoryBarrier2& barrier2 : std::span(pDependencyInfo->pMemoryBarriers, pDependencyInfo->memoryBarrierCount)) + { + VkMemoryBarrier barrier = {VK_STRUCTURE_TYPE_MEMORY_BARRIER}; + barrier.srcAccessMask = TranslateAccessFlags(barrier2.srcAccessMask); + barrier.dstAccessMask = TranslateAccessFlags(barrier2.dstAccessMask); + vkCmdPipelineBarrier(commandBuffer, TranslateStageFlags(barrier2.srcStageMask), TranslateStageFlags(barrier2.dstStageMask), + dependencyFlags, 1, &barrier, 0, nullptr, 0, nullptr); + } + for (const VkBufferMemoryBarrier2& barrier2 : std::span(pDependencyInfo->pBufferMemoryBarriers, pDependencyInfo->bufferMemoryBarrierCount)) + { + VkBufferMemoryBarrier barrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + barrier.srcAccessMask = TranslateAccessFlags(barrier2.srcAccessMask); + barrier.dstAccessMask = TranslateAccessFlags(barrier2.dstAccessMask); + barrier.srcQueueFamilyIndex = barrier2.srcQueueFamilyIndex; + barrier.dstQueueFamilyIndex = barrier2.dstQueueFamilyIndex; + barrier.buffer = barrier2.buffer; + barrier.offset = barrier2.offset; + barrier.size = barrier2.size; + vkCmdPipelineBarrier(commandBuffer, TranslateStageFlags(barrier2.srcStageMask), TranslateStageFlags(barrier2.dstStageMask), + dependencyFlags, 0, nullptr, 1, &barrier, 0, nullptr); + } + for (const VkImageMemoryBarrier2& barrier2 : std::span(pDependencyInfo->pImageMemoryBarriers, pDependencyInfo->imageMemoryBarrierCount)) + { + VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + barrier.srcAccessMask = TranslateAccessFlags(barrier2.srcAccessMask); + barrier.dstAccessMask = TranslateAccessFlags(barrier2.dstAccessMask); + barrier.oldLayout = barrier2.oldLayout; + barrier.newLayout = barrier2.newLayout; + barrier.srcQueueFamilyIndex = barrier2.srcQueueFamilyIndex; + barrier.dstQueueFamilyIndex = barrier2.dstQueueFamilyIndex; + barrier.image = barrier2.image; + barrier.subresourceRange = barrier2.subresourceRange; + vkCmdPipelineBarrier(commandBuffer, TranslateStageFlags(barrier2.srcStageMask), TranslateStageFlags(barrier2.dstStageMask), + dependencyFlags, 0, nullptr, 0, nullptr, 1, &barrier); + } + } +} // namespace ReplaceVK + static bool IsDATEModePrimIDInit(u32 flag) { return flag == 1 || flag == 2; @@ -423,6 +484,7 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false); m_optional_extensions.vk_ext_calibrated_timestamps = SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false); + m_optional_extensions.vk_khr_synchronization2 = SupportsExtension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, false); if (m_optional_extensions.vk_swapchain_maintenance1) { @@ -619,6 +681,8 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer device_info.ppEnabledLayerNames = layer_names; } + VkPhysicalDeviceSynchronization2Features sync2_features = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES}; // provoking vertex VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT}; @@ -634,6 +698,11 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_ext_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT}; + if (m_optional_extensions.vk_khr_synchronization2) + { + sync2_features.synchronization2 = VK_TRUE; + Vulkan::AddPointerToChain(&device_info, &sync2_features); + } if (m_optional_extensions.vk_ext_provoking_vertex) { provoking_vertex_feature.provokingVertexLast = VK_TRUE; @@ -703,6 +772,12 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer if (!ProcessDeviceExtensions()) return false; + // Add replacements for unsupported functions + if (!m_optional_extensions.vk_khr_synchronization2) + { + vkCmdPipelineBarrier2KHR = ReplaceVK::CmdPipelineBarrier2; + } + if (m_spinning_supported) { vkGetDeviceQueue(m_device, m_spin_queue_family_index, spin_queue_index, &m_spin_queue); @@ -726,6 +801,8 @@ bool GSDeviceVK::ProcessDeviceExtensions() { // advanced feature checks VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + VkPhysicalDeviceSynchronization2Features sync2_features = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES}; VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT}; VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = { @@ -741,6 +818,8 @@ bool GSDeviceVK::ProcessDeviceExtensions() VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT }; // add in optional feature structs + if (m_optional_extensions.vk_khr_synchronization2) + Vulkan::AddPointerToChain(&features2, &sync2_features); if (m_optional_extensions.vk_ext_provoking_vertex) Vulkan::AddPointerToChain(&features2, &provoking_vertex_features); if (m_optional_extensions.vk_ext_line_rasterization) @@ -758,6 +837,7 @@ bool GSDeviceVK::ProcessDeviceExtensions() vkGetPhysicalDeviceFeatures2(m_physical_device, &features2); // confirm we actually support it + m_optional_extensions.vk_khr_synchronization2 &= (sync2_features.synchronization2 == VK_TRUE); m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE); m_optional_extensions.vk_ext_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE); @@ -838,6 +918,8 @@ bool GSDeviceVK::ProcessDeviceExtensions() m_optional_extensions.vk_swapchain_maintenance1 ? "supported" : "NOT supported"); Console.WriteLn("VK_EXT_full_screen_exclusive is %s", m_optional_extensions.vk_ext_full_screen_exclusive ? "supported" : "NOT supported"); + Console.WriteLn("VK_KHR_synchronization2 is %s", + m_optional_extensions.vk_khr_synchronization2 ? "supported" : "NOT supported"); Console.WriteLn( "VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported"); Console.WriteLn("VK_EXT_line_rasterization is %s", @@ -1667,11 +1749,8 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) subpass_dependency[num_subpass_dependencies].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; subpass_dependency[num_subpass_dependencies].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - subpass_dependency[num_subpass_dependencies].dstAccessMask = - UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - subpass_dependency[num_subpass_dependencies].dependencyFlags = - UseFeedbackLoopLayout() ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) : - VK_DEPENDENCY_BY_REGION_BIT; + subpass_dependency[num_subpass_dependencies].dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); + subpass_dependency[num_subpass_dependencies].dependencyFlags = GetFeedbackBarrierDependencyFlags(); num_subpass_dependencies++; } } @@ -1713,11 +1792,8 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) subpass_dependency[num_subpass_dependencies].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; subpass_dependency[num_subpass_dependencies].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - subpass_dependency[num_subpass_dependencies].dstAccessMask = - UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - subpass_dependency[num_subpass_dependencies].dependencyFlags = - UseFeedbackLoopLayout() ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) : - VK_DEPENDENCY_BY_REGION_BIT; + subpass_dependency[num_subpass_dependencies].dstAccessMask = static_cast(GetFeedbackLoopInputAccessFlags()); + subpass_dependency[num_subpass_dependencies].dependencyFlags = GetFeedbackBarrierDependencyFlags(); num_subpass_dependencies++; } } @@ -1999,7 +2075,9 @@ void GSDeviceVK::SubmitSpinCommand(u32 index, u32 cycles) { m_spin_buffer_initialized = true; vkCmdFillBuffer(resources.command_buffer, m_spin_buffer, 0, VK_WHOLE_SIZE, 0); - VkBufferMemoryBarrier barrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + VkBufferMemoryBarrier2 barrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2}; + barrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.srcQueueFamilyIndex = m_spin_queue_family_index; @@ -2007,13 +2085,22 @@ void GSDeviceVK::SubmitSpinCommand(u32 index, u32 cycles) barrier.buffer = m_spin_buffer; barrier.offset = 0; barrier.size = VK_WHOLE_SIZE; - vkCmdPipelineBarrier(resources.command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 1, &barrier, 0, nullptr); + VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + dependency.bufferMemoryBarrierCount = 1; + dependency.pBufferMemoryBarriers = &barrier; + vkCmdPipelineBarrier2KHR(resources.command_buffer, &dependency); } if (m_spin_queue_is_graphics_queue) - vkCmdPipelineBarrier(resources.command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 0, nullptr); + { + VkMemoryBarrier2 barrier = {VK_STRUCTURE_TYPE_MEMORY_BARRIER_2}; + barrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + dependency.memoryBarrierCount = 1; + dependency.pMemoryBarriers = &barrier; + vkCmdPipelineBarrier2KHR(resources.command_buffer, &dependency); + } const u32 timestamp_base = (index + NUM_COMMAND_BUFFERS) * 2; vkCmdResetQueryPool(resources.command_buffer, m_timestamp_query_pool, timestamp_base, 2); @@ -3052,9 +3139,9 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, sTexVK->SetUseFenceCounter(GetCurrentFenceCounter()); dTexVK->SetUseFenceCounter(GetCurrentFenceCounter()); sTexVK->TransitionToLayout( - (dTexVK == sTexVK) ? GSTextureVK::Layout::TransferSelf : GSTextureVK::Layout::TransferSrc); + (dTexVK == sTexVK) ? GSTextureVK::Layout::CopySelf : GSTextureVK::Layout::CopySrc); dTexVK->TransitionToLayout( - (dTexVK == sTexVK) ? GSTextureVK::Layout::TransferSelf : GSTextureVK::Layout::TransferDst); + (dTexVK == sTexVK) ? GSTextureVK::Layout::CopySelf : GSTextureVK::Layout::CopyDst); vkCmdCopyImage(GetCurrentCommandBuffer(), sTexVK->GetImage(), sTexVK->GetVkLayout(), dTexVK->GetImage(), dTexVK->GetVkLayout(), 1, &ic); @@ -3322,8 +3409,8 @@ void GSDeviceVK::BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel, EndRenderPass(); - sTexVK->TransitionToLayout(GSTextureVK::Layout::TransferSrc); - dTexVK->TransitionToLayout(GSTextureVK::Layout::TransferDst); + sTexVK->TransitionToLayout(GSTextureVK::Layout::BlitSrc); + dTexVK->TransitionToLayout(GSTextureVK::Layout::BlitDst); // ensure we don't leave this bound later on if (m_tfx_textures[0] == sTexVK) @@ -4768,7 +4855,7 @@ void GSDeviceVK::RenderBlankFrame() VkCommandBuffer cmdbuffer = GetCurrentCommandBuffer(); GSTextureVK* sctex = m_swap_chain->GetCurrentTexture(); - sctex->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::TransferDst); + sctex->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::ClearDst); constexpr VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; vkCmdClearColorImage( @@ -6543,27 +6630,9 @@ void GSDeviceVK::UploadHWDrawVerticesAndIndices(GSHWDrawConfig& config) } } -VkImageMemoryBarrier GSDeviceVK::GetColorBufferFeedbackBarrier(GSTextureVK* rt) const +VkImageLayout GSDeviceVK::GetFeedbackLoopLayout() const { - const VkImageLayout layout = - UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL; - const VkAccessFlags dst_access = - UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - return {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, dst_access, layout, layout, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, rt->GetImage(), {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}}; -} - -VkImageMemoryBarrier GSDeviceVK::GetDepthStencilBufferFeedbackBarrier(GSTextureVK* ds) const -{ - const VkImageLayout layout = - UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL; - const VkAccessFlags dst_access = - UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - return {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, dst_access, layout, layout, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, ds->GetImage(), - {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u}}; + return UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL; } VkDependencyFlags GSDeviceVK::GetFeedbackBarrierDependencyFlags() const @@ -6572,6 +6641,50 @@ VkDependencyFlags GSDeviceVK::GetFeedbackBarrierDependencyFlags() const VK_DEPENDENCY_BY_REGION_BIT; } +VkAccessFlags2 GSDeviceVK::GetFeedbackLoopInputAccessFlags() const +{ + return UseFeedbackLoopLayout() ? VK_ACCESS_2_SHADER_READ_BIT : VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT; +} + +void GSDeviceVK::FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds) +{ + VkImageMemoryBarrier2 barrier_template = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; + barrier_template.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; + barrier_template.dstAccessMask = GetFeedbackLoopInputAccessFlags(); + barrier_template.oldLayout = GetFeedbackLoopLayout(); + barrier_template.newLayout = GetFeedbackLoopLayout(); + barrier_template.subresourceRange.levelCount = 1; + barrier_template.subresourceRange.layerCount = 1; + + std::array barriers; + u32 num_barriers = 0; + + 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.image = rt->GetImage(); + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + 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.image = ds->GetImage(); + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } + + VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags(); + dependency.imageMemoryBarrierCount = num_barriers; + dependency.pImageMemoryBarriers = barriers.data(); + + vkCmdPipelineBarrier2KHR(GetCurrentCommandBuffer(), &dependency); +} + void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, GSTextureVK* draw_ds, bool one_barrier, bool full_barrier) { @@ -6585,38 +6698,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, 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(); - - std::array barriers; - u32 n_barriers = 0; - if (full_barrier || one_barrier) - { - if (draw_rt) - { - barriers[0] = GetColorBufferFeedbackBarrier(draw_rt); - n_barriers++; - } - if (draw_ds) - { - barriers[1] = GetDepthStencilBufferFeedbackBarrier(draw_ds); - n_barriers++; - } - } - - const auto IssueBarriers = [&]() { - if (draw_rt) - { - vkCmdPipelineBarrier(GetCurrentCommandBuffer(), - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags, 0, nullptr, 0, nullptr, 1, &barriers[0]); - } - if (draw_ds) - { - vkCmdPipelineBarrier(GetCurrentCommandBuffer(), - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags, 0, nullptr, 0, nullptr, 1, &barriers[1]); - } - }; + const int n_barriers = (draw_rt ? 1 : 0) + (draw_ds ? 1 : 0); if (full_barrier) { @@ -6630,7 +6712,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, for (u32 n = 0, p = 0; n < draw_list_size; n++) { - IssueBarriers(); + FeedbackBarrier(draw_rt, draw_ds); const u32 count = config.drawlist->at(n) * indices_per_prim; Draw(config, p, count); @@ -6643,7 +6725,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, if (one_barrier) { g_perfmon.Put(GSPerfMon::Barriers, n_barriers); - IssueBarriers(); + FeedbackBarrier(draw_rt, draw_ds); } Draw(config); diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index 04edc295f5..bd89088257 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -45,6 +45,7 @@ public: bool vk_swapchain_maintenance1_is_khr : 1; bool vk_khr_driver_properties : 1; bool vk_khr_shader_non_semantic_info : 1; + bool vk_khr_synchronization2 : 1; bool vk_ext_attachment_feedback_loop_layout : 1; bool vk_ext_fragment_shader_interlock : 1; }; @@ -640,9 +641,10 @@ public: void RenderHW(GSHWDrawConfig& config) override; void UpdateHWPipelineSelector(GSHWDrawConfig& config, PipelineSelector& pipe); void UploadHWDrawVerticesAndIndices(GSHWDrawConfig& config); - VkImageMemoryBarrier GetColorBufferFeedbackBarrier(GSTextureVK* rt) const; - VkImageMemoryBarrier GetDepthStencilBufferFeedbackBarrier(GSTextureVK* ds) const; + VkImageLayout GetFeedbackLoopLayout() const; VkDependencyFlags GetFeedbackBarrierDependencyFlags() const; + VkAccessFlags2 GetFeedbackLoopInputAccessFlags() const; + void FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds); void SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, GSTextureVK* draw_ds, bool one_barrier, bool full_barrier); diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp index 0ce82eb092..6af56425de 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp @@ -34,31 +34,105 @@ static constexpr const VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZL static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout) { - static constexpr std::array(GSTextureVK::Layout::Count)> s_vk_layout_mapping = {{ + static constexpr VkImageLayout s_vk_layout_mapping[] = { VK_IMAGE_LAYOUT_UNDEFINED, // Undefined VK_IMAGE_LAYOUT_PREINITIALIZED, // Preinitialized VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // ColorAttachment VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // DepthStencilAttachment VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // ShaderReadOnly VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // ClearDst - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TransferSrc - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TransferDst - VK_IMAGE_LAYOUT_GENERAL, // TransferSelf + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // CopySrc + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // CopyDst + VK_IMAGE_LAYOUT_GENERAL, // CopySelf + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // BlitSrc + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // BlitDst + VK_IMAGE_LAYOUT_GENERAL, // BlitSelf VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // PresentSrc VK_IMAGE_LAYOUT_GENERAL, // FeedbackLoop VK_IMAGE_LAYOUT_GENERAL, // ReadWriteImage VK_IMAGE_LAYOUT_GENERAL, // ComputeReadWriteImage VK_IMAGE_LAYOUT_GENERAL, // General - }}; - return (layout == GSTextureVK::Layout::FeedbackLoop && GSDeviceVK::GetInstance()->UseFeedbackLoopLayout()) ? - VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : - s_vk_layout_mapping[static_cast(layout)]; + }; + static_assert(std::size(s_vk_layout_mapping) == static_cast(GSTextureVK::Layout::Count)); + if (layout == GSTextureVK::Layout::FeedbackLoop) + return GSDeviceVK::GetInstance()->GetFeedbackLoopLayout(); + else + return s_vk_layout_mapping[static_cast(layout)]; } -static VkAccessFlagBits GetFeedbackLoopInputAccessBits() +static VkPipelineStageFlags2 GetPipelineStageFlags(GSTextureVK::Layout layout, bool color) { - return GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + static constexpr VkPipelineStageFlags2 s_vk_stage_mapping[] = { + VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, // Undefined + VK_PIPELINE_STAGE_2_HOST_BIT, // Preinitialized + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, // ColorAttachment + VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, // DepthStencilAttachment + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, // ShaderReadOnly + VK_PIPELINE_STAGE_2_CLEAR_BIT, // ClearDst + VK_PIPELINE_STAGE_2_COPY_BIT, // CopySrc + VK_PIPELINE_STAGE_2_COPY_BIT, // CopyDst + VK_PIPELINE_STAGE_2_COPY_BIT, // CopySelf + VK_PIPELINE_STAGE_2_BLIT_BIT, // BlitSrc + VK_PIPELINE_STAGE_2_BLIT_BIT, // BlitDst + VK_PIPELINE_STAGE_2_BLIT_BIT, // BlitSelf + VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, // PresentSrc + VK_PIPELINE_STAGE_2_NONE, // FeedbackLoop (overridden) + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, // ReadWriteImage + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, // ComputeReadWriteImage + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, // General + }; + static_assert(std::size(s_vk_stage_mapping) == static_cast(GSTextureVK::Layout::Count)); + if (layout == GSTextureVK::Layout::FeedbackLoop) + { + VkPipelineStageFlags2 flags = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; + if (color) + flags |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + else + flags |= VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; + return flags; + } + else + { + return s_vk_stage_mapping[static_cast(layout)]; + } +} + +static VkAccessFlags2 GetAccessFlags(GSTextureVK::Layout layout, bool color) +{ + static constexpr VkPipelineStageFlags2 s_vk_access_mapping[] = { + VK_ACCESS_2_NONE, // Undefined + VK_ACCESS_2_HOST_WRITE_BIT, // Preinitialized + VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, // ColorAttachment + VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // DepthStencilAttachment + VK_ACCESS_2_SHADER_READ_BIT, // ShaderReadOnly + VK_ACCESS_2_TRANSFER_WRITE_BIT, // ClearDst + VK_ACCESS_2_TRANSFER_READ_BIT, // CopySrc + VK_ACCESS_2_TRANSFER_WRITE_BIT, // CopyDst + VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, // CopySelf + VK_ACCESS_2_TRANSFER_READ_BIT, // BlitSrc + VK_ACCESS_2_TRANSFER_WRITE_BIT, // BlitDst + VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, // BlitSelf + VK_ACCESS_2_NONE, // PresentSrc + VK_ACCESS_2_NONE, // FeedbackLoop (overridden) + VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, // ReadWriteImage + VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, // ComputeReadWriteImage + VK_ACCESS_2_NONE, // General + }; + static_assert(std::size(s_vk_access_mapping) == static_cast(GSTextureVK::Layout::Count)); + + if (layout == GSTextureVK::Layout::FeedbackLoop) + { + VkAccessFlags2 flags; + if (color) + flags = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + else + flags = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + return flags | GSDeviceVK::GetInstance()->GetFeedbackLoopInputAccessFlags(); + } + else + { + return s_vk_access_mapping[static_cast(layout)]; + } } GSTextureVK::GSTextureVK(Usage usage, Format format, int width, int height, int levels, VkImage image, @@ -315,9 +389,9 @@ void GSTextureVK::UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32 { const Layout old_layout = m_layout; if (old_layout == Layout::Undefined) - TransitionToLayout(cmdbuf, Layout::TransferDst); - else if (old_layout != Layout::TransferDst) - TransitionSubresourcesToLayout(cmdbuf, level, 1, old_layout, Layout::TransferDst); + TransitionToLayout(cmdbuf, Layout::CopyDst); + else if (old_layout != Layout::CopyDst) + TransitionSubresourcesToLayout(cmdbuf, level, 1, old_layout, Layout::CopyDst); const VkBufferImageCopy bic = {static_cast(buffer_offset), row_length, buffer_height, {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(level), 0u, 1u}, {static_cast(x), static_cast(y), 0}, @@ -325,8 +399,8 @@ void GSTextureVK::UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32 vkCmdCopyBufferToImage(cmdbuf, buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bic); - if (old_layout != Layout::TransferDst && old_layout != Layout::Undefined) - TransitionSubresourcesToLayout(cmdbuf, level, 1, Layout::TransferDst, old_layout); + if (old_layout != Layout::CopyDst && old_layout != Layout::Undefined) + TransitionSubresourcesToLayout(cmdbuf, level, 1, Layout::CopyDst, old_layout); } bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int layer) @@ -387,7 +461,7 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l // first time the texture is used? don't leave it undefined if (m_layout == Layout::Undefined) - TransitionToLayout(cmdbuf, Layout::TransferDst); + TransitionToLayout(cmdbuf, Layout::CopyDst); // if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear if (IsRenderTarget()) @@ -469,7 +543,7 @@ void GSTextureVK::Unmap() // first time the texture is used? don't leave it undefined if (m_layout == Layout::Undefined) - TransitionToLayout(cmdbuf, Layout::TransferDst); + TransitionToLayout(cmdbuf, Layout::CopyDst); // if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear if (IsRenderTarget()) @@ -494,7 +568,7 @@ void GSTextureVK::GenerateMipmap() const VkCommandBuffer cmdbuf = GetCommandBufferForUpdate(); if (m_layout == Layout::Undefined) - TransitionToLayout(cmdbuf, Layout::TransferSrc); + TransitionToLayout(cmdbuf, Layout::BlitSrc); for (int dst_level = 1; dst_level < m_mipmap_levels; dst_level++) { @@ -504,8 +578,8 @@ void GSTextureVK::GenerateMipmap() const int dst_width = std::max(m_size.x >> dst_level, 1); const int dst_height = std::max(m_size.y >> dst_level, 1); - TransitionSubresourcesToLayout(cmdbuf, src_level, 1, m_layout, Layout::TransferSrc); - TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, m_layout, Layout::TransferDst); + TransitionSubresourcesToLayout(cmdbuf, src_level, 1, m_layout, Layout::BlitSrc); + TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, m_layout, Layout::BlitDst); const VkImageBlit blit = { {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(src_level), 0u, 1u}, // srcSubresource @@ -517,8 +591,8 @@ void GSTextureVK::GenerateMipmap() vkCmdBlitImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); - TransitionSubresourcesToLayout(cmdbuf, src_level, 1, Layout::TransferSrc, m_layout); - TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, Layout::TransferDst, m_layout); + TransitionSubresourcesToLayout(cmdbuf, src_level, 1, Layout::BlitSrc, m_layout); + TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, Layout::BlitDst, m_layout); } } @@ -620,168 +694,29 @@ void GSTextureVK::TransitionSubresourcesToLayout( aspect = VK_IMAGE_ASPECT_COLOR_BIT; } - VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, 0, 0, GetVkImageLayout(old_layout), - GetVkImageLayout(new_layout), VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, m_image, - {aspect, static_cast(start_level), static_cast(num_levels), 0u, 1u}}; + // These layouts should only be used on one side of the barrier + pxAssert(old_layout != Layout::PresentSrc); + pxAssert(new_layout != Layout::Undefined); + pxAssert(new_layout != Layout::Preinitialized); - // srcStageMask -> Stages that must complete before the barrier - // dstStageMask -> Stages that must wait for after the barrier before beginning - VkPipelineStageFlags srcStageMask, dstStageMask; - switch (old_layout) - { - case Layout::Undefined: - // Layout undefined therefore contents undefined, and we don't care what happens to it. - barrier.srcAccessMask = 0; - srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; + VkImageMemoryBarrier2 barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; + barrier.srcStageMask = GetPipelineStageFlags(old_layout, !IsDepthStencil()); + barrier.dstStageMask = GetPipelineStageFlags(new_layout, !IsDepthStencil()); + barrier.srcAccessMask = GetAccessFlags(old_layout, !IsDepthStencil()); + barrier.dstAccessMask = GetAccessFlags(new_layout, !IsDepthStencil()); + barrier.oldLayout = GetVkImageLayout(old_layout); + barrier.newLayout = GetVkImageLayout(new_layout); + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = m_image; + barrier.subresourceRange = {aspect, static_cast(start_level), static_cast(num_levels), 0u, 1u}; - case Layout::Preinitialized: - // Image has been pre-initialized by the host, so ensure all writes have completed. - barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_HOST_BIT; - break; + VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + dependency.dependencyFlags = GSDeviceVK::GetInstance()->GetFeedbackBarrierDependencyFlags(); + dependency.imageMemoryBarrierCount = 1; + dependency.pImageMemoryBarriers = &barrier; - case Layout::ColorAttachment: - // Image was being used as a color attachment, so ensure all writes have completed. - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - - case Layout::DepthStencilAttachment: - // Image was being used as a depthstencil attachment, so ensure all writes have completed. - barrier.srcAccessMask = - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - - case Layout::ShaderReadOnly: - // Image was being used as a shader resource, make sure all reads have finished. - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - - case Layout::ClearDst: - // Image was being used as a clear destination, ensure all writes have finished. - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::TransferSrc: - // Image was being used as a copy source, ensure all reads have finished. - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::TransferDst: - // Image was being used as a copy destination, ensure all writes have finished. - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::TransferSelf: - // Image was being used as a copy source and destination, ensure all reads and writes have finished. - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::FeedbackLoop: - barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) - ? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits()) - : (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits()); - srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) - ? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) - : (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - break; - - case Layout::ReadWriteImage: - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - - case Layout::ComputeReadWriteImage: - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - break; - - case Layout::General: - default: - srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; - } - - switch (new_layout) - { - case Layout::Undefined: - barrier.dstAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; - - case Layout::ColorAttachment: - barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - - case Layout::DepthStencilAttachment: - barrier.dstAccessMask = - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - - case Layout::ShaderReadOnly: - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - - case Layout::ClearDst: - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::TransferSrc: - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::TransferDst: - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::TransferSelf: - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case Layout::PresentSrc: - srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; - - case Layout::FeedbackLoop: - barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) - ? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits()) - : (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits()); - dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) - ? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) - : (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - break; - - case Layout::ReadWriteImage: - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - - case Layout::ComputeReadWriteImage: - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - break; - - case Layout::General: - default: - dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - break; - } - vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier); + vkCmdPipelineBarrier2KHR(command_buffer, &dependency); // Count as a UAV barrier if we transition to/from UAV. if (IsRenderTargetOrDepthStencil() && @@ -902,9 +837,9 @@ void GSDownloadTextureVK::CopyFromTexture( GSTextureVK::Layout old_layout = vkTex->GetLayout(); if (old_layout == GSTextureVK::Layout::Undefined) - vkTex->TransitionToLayout(cmdbuf, GSTextureVK::Layout::TransferSrc); - else if (old_layout != GSTextureVK::Layout::TransferSrc) - vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, old_layout, GSTextureVK::Layout::TransferSrc); + vkTex->TransitionToLayout(cmdbuf, GSTextureVK::Layout::CopySrc); + else if (old_layout != GSTextureVK::Layout::CopySrc) + vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, old_layout, GSTextureVK::Layout::CopySrc); VkBufferImageCopy image_copy = {}; const VkImageAspectFlags aspect = vkTex->IsDepthStencil() ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; @@ -919,22 +854,24 @@ void GSDownloadTextureVK::CopyFromTexture( vkCmdCopyImageToBuffer(cmdbuf, vkTex->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer, 1, &image_copy); // flush gpu cache - const VkBufferMemoryBarrier buffer_info = { - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType - nullptr, // const void* pNext - VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask - VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask - VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex - VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex - m_buffer, // VkBuffer buffer - 0, // VkDeviceSize offset - copy_size // VkDeviceSize size - }; - vkCmdPipelineBarrier( - cmdbuf, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, 1, &buffer_info, 0, nullptr); + VkBufferMemoryBarrier2 buffer_info = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2}; + buffer_info.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT; + buffer_info.dstStageMask = VK_PIPELINE_STAGE_2_HOST_BIT; + buffer_info.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT; + buffer_info.dstAccessMask = VK_ACCESS_2_HOST_READ_BIT; + buffer_info.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_info.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_info.buffer = m_buffer; + buffer_info.size = copy_size; - if (old_layout != GSTextureVK::Layout::TransferSrc && old_layout != GSTextureVK::Layout::Undefined) - vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, GSTextureVK::Layout::TransferSrc, old_layout); + VkDependencyInfo barrier_info = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + barrier_info.bufferMemoryBarrierCount = 1; + barrier_info.pBufferMemoryBarriers = &buffer_info; + + vkCmdPipelineBarrier2KHR(cmdbuf, &barrier_info); + + if (old_layout != GSTextureVK::Layout::CopySrc && old_layout != GSTextureVK::Layout::Undefined) + vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, GSTextureVK::Layout::CopySrc, old_layout); m_copy_fence_counter = GSDeviceVK::GetInstance()->GetCurrentFenceCounter(); m_needs_cache_invalidate = true; diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h index 006aaaf4f6..a15180f40f 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h @@ -20,9 +20,12 @@ public: DepthStencilAttachment, ShaderReadOnly, ClearDst, - TransferSrc, - TransferDst, - TransferSelf, + CopySrc, + CopyDst, + CopySelf, + BlitSrc, + BlitDst, + BlitSelf, PresentSrc, FeedbackLoop, ReadWriteImage, diff --git a/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl b/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl index b4c9f36527..98adfd1545 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl +++ b/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl @@ -201,6 +201,7 @@ VULKAN_DEVICE_ENTRY_POINT(vkCmdSetEvent, true) VULKAN_DEVICE_ENTRY_POINT(vkCmdResetEvent, true) VULKAN_DEVICE_ENTRY_POINT(vkCmdWaitEvents, true) VULKAN_DEVICE_ENTRY_POINT(vkCmdPipelineBarrier, true) +VULKAN_DEVICE_ENTRY_POINT(vkCmdPipelineBarrier2KHR, false) VULKAN_DEVICE_ENTRY_POINT(vkCmdBeginQuery, true) VULKAN_DEVICE_ENTRY_POINT(vkCmdEndQuery, true) VULKAN_DEVICE_ENTRY_POINT(vkCmdResetQueryPool, true)