diff options
| author | TellowKrinkle <tellowkrinkle@gmail.com> | 2025-10-18 05:15:04 -0500 |
|---|---|---|
| committer | TellowKrinkle <tellowkrinkle@gmail.com> | 2025-10-18 05:24:37 -0500 |
| commit | e599ae37c31b0beb1594b3e664faa0a50db91690 (patch) | |
| tree | bd47db449706e2e23864f6af06070fac50351445 /Source/Core/VideoBackends/Vulkan/VKTexture.cpp | |
| parent | 7b994d965432687e194c87b347e584ddda08bfae (diff) | |
VideoBackends:Vulkan: Prevent hazards when restarting render passes
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/VKTexture.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/VKTexture.cpp | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp index edccc9da14..ee6a1b77b3 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -466,6 +466,8 @@ void VKTexture::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout if (m_layout == new_layout) return; + m_written_since_last_layout_change = false; + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType nullptr, // const void* pNext @@ -613,6 +615,8 @@ void VKTexture::TransitionToLayout(VkCommandBuffer command_buffer, if (m_compute_layout == new_layout) return; + m_written_since_last_layout_change = false; + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType nullptr, // const void* pNext @@ -709,6 +713,49 @@ void VKTexture::TransitionToLayout(VkCommandBuffer command_buffer, &barrier); } +void VKTexture::PrepareForRenderPass(VkCommandBuffer command_buffer) const +{ + // Should only be used on images that are already in the layout for being rendered to + ASSERT(m_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || + m_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + if (m_written_since_last_layout_change) + { + // If the image has already been written, we need a barrier to prevent WaW or RaW hazards. + VkPipelineStageFlags srcStage = 0; + VkPipelineStageFlags dstStage = 0; + VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + barrier.image = m_image; + barrier.oldLayout = m_layout; + barrier.newLayout = m_layout; + barrier.subresourceRange.aspectMask = GetImageAspectForFormat(GetFormat()); + barrier.subresourceRange.layerCount = GetLayers(); + barrier.subresourceRange.levelCount = GetLevels(); + if (barrier.subresourceRange.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) + { + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | // + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + else + { + barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + srcStage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + } + vkCmdPipelineBarrier(command_buffer, srcStage, dstStage, 0, // + 0, nullptr, 0, nullptr, 1, &barrier); + } + else + { + // Otherwise, it's about to be written right now. + m_written_since_last_layout_change = true; + } +} + VKStagingTexture::VKStagingTexture(PrivateTag, StagingTextureType type, const TextureConfig& config, std::unique_ptr<StagingBuffer> buffer, VkImage linear_image, VmaAllocation linear_image_alloc) @@ -1117,27 +1164,36 @@ void VKFramebuffer::Unbind() void VKFramebuffer::TransitionForRender() { + VkCommandBuffer cb = g_command_buffer_mgr->GetCurrentCommandBuffer(); if (m_color_attachment) { static_cast<VKTexture*>(m_color_attachment) - ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + ->TransitionToLayout(cb, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } for (auto* attachment : m_additional_color_attachments) { static_cast<VKTexture*>(attachment) - ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + ->TransitionToLayout(cb, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } if (m_depth_attachment) { static_cast<VKTexture*>(m_depth_attachment) - ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + ->TransitionToLayout(cb, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } } +void VKFramebuffer::PrepareForRenderPass() +{ + VkCommandBuffer cb = g_command_buffer_mgr->GetCurrentCommandBuffer(); + if (m_color_attachment) + static_cast<VKTexture*>(m_color_attachment)->PrepareForRenderPass(cb); + if (m_depth_attachment) + static_cast<VKTexture*>(m_depth_attachment)->PrepareForRenderPass(cb); + for (auto* attachment : m_additional_color_attachments) + static_cast<VKTexture*>(attachment)->PrepareForRenderPass(cb); +} + void VKFramebuffer::SetAndClear(const VkRect2D& rect, const VkClearValue& color_value, const VkClearValue& depth_value) { |
