From ac95d0ff4826fa93433a534b61a69c8fe0b584f3 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 11 Feb 2019 15:40:12 +0000 Subject: [PATCH] When ending partially replayed RP, set image back into layout afterwards * If we have a renderpass that we stop replaying at subpass 0, we want to pretend that the image is preserved as it was at that point - layout and all. However since we're replaying with the original renderpass any subpass transitions and finalLayout transitions will take effect. When we end any active RP during vkEndCommandBuffer, we then undo any of these implicit transitions to put the image back as it was. --- renderdoc/driver/vulkan/vk_core.cpp | 2 - renderdoc/driver/vulkan/vk_state.cpp | 51 ------------------- renderdoc/driver/vulkan/vk_state.h | 3 -- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 46 +++++++++++++---- 4 files changed, 37 insertions(+), 65 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 9065133ca..3051cb6e5 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -3014,8 +3014,6 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay // we need to reverse the virtual transitions we did above, as it won't happen otherwise if(m_Partial[Primary].renderPassActive) m_RenderState.EndRenderPass(cmd); - else if(rpWasActive) - m_RenderState.DoRenderpassEndTransitions(cmd); // we might have replayed a CmdBeginRenderPass or CmdEndRenderPass, // but we want to keep the partial replay data state intact, so restore diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index 6967dc9e0..3f3f11000 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -89,8 +89,6 @@ VulkanRenderState &VulkanRenderState::operator=(const VulkanRenderState &o) void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd, PipelineBinding binding) { - DoRenderPassBeginTransitions(cmd); - RDCASSERT(renderPass != ResourceId()); // clear values don't matter as we're using the load renderpass here, that @@ -173,7 +171,6 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd, Pipeli void VulkanRenderState::EndRenderPass(VkCommandBuffer cmd) { ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); - DoRenderpassEndTransitions(cmd); } void VulkanRenderState::EndTransformFeedback(VkCommandBuffer cmd) @@ -517,54 +514,6 @@ void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCom } } -void VulkanRenderState::DoRenderPassBeginTransitions(VkCommandBuffer cmd) -{ - // first apply implicit transitions to the right subpass - rpBarriers = m_pDriver->GetImplicitRenderPassBarriers(); - - if(!rpBarriers.empty()) - { - // don't transition from undefined, or contents will be discarded, instead transition from - // the current state. - for(size_t i = 0; i < rpBarriers.size(); i++) - { - if(rpBarriers[i].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) - { - ResourceId imgid = GetResourceManager()->GetNonDispWrapper(rpBarriers[i].image)->id; - - // TODO find overlapping range and transition that instead - rpBarriers[i].oldLayout = m_pDriver->m_ImageLayouts[imgid].subresourceStates[0].newLayout; - } - } - - GetResourceManager()->RecordBarriers(m_pDriver->m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers, - m_pDriver->m_ImageLayouts, (uint32_t)rpBarriers.size(), - rpBarriers.data()); - - ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 0, NULL, 0, NULL, - (uint32_t)rpBarriers.size(), rpBarriers.data()); - } -} - -void VulkanRenderState::DoRenderpassEndTransitions(VkCommandBuffer cmd) -{ - if(!rpBarriers.empty()) - { - // reverse the rpBarriers that we applied at the start - for(size_t i = 0; i < rpBarriers.size(); i++) - std::swap(rpBarriers[i].oldLayout, rpBarriers[i].newLayout); - - GetResourceManager()->RecordBarriers(m_pDriver->m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers, - m_pDriver->m_ImageLayouts, (uint32_t)rpBarriers.size(), - rpBarriers.data()); - - ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 0, NULL, 0, NULL, - (uint32_t)rpBarriers.size(), rpBarriers.data()); - } -} - VulkanResourceManager *VulkanRenderState::GetResourceManager() { return m_pDriver->GetResourceManager(); diff --git a/renderdoc/driver/vulkan/vk_state.h b/renderdoc/driver/vulkan/vk_state.h index 20c1ea7dd..f0ebbd9ae 100644 --- a/renderdoc/driver/vulkan/vk_state.h +++ b/renderdoc/driver/vulkan/vk_state.h @@ -46,9 +46,6 @@ struct VulkanRenderState void BeginRenderPassAndApplyState(VkCommandBuffer cmd, PipelineBinding binding); void EndRenderPass(VkCommandBuffer cmd); - void DoRenderPassBeginTransitions(VkCommandBuffer cmd); - void DoRenderpassEndTransitions(VkCommandBuffer cmd); - void EndTransformFeedback(VkCommandBuffer cmd); void EndConditionalRendering(VkCommandBuffer cmd); diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index a109f0044..4b443ffe8 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -939,28 +939,56 @@ bool WrappedVulkan::Serialise_vkEndCommandBuffer(SerialiserType &ser, VkCommandB (uint32_t)m_CreationInfo.m_RenderPass[m_RenderState.renderPass].subpasses.size(); // for each subpass we skip, and for the finalLayout transition at the end of the - // renderpass, update our tracking. These are executed implicitly but because we're - // sneaking past them here our tracking will get out of date. + // renderpass, record these barriers. These are executed implicitly but because we want to + // pretend they never happened, we then reverse their effects so that our layout tracking + // is accurate and the images end up in the layout they were in during the last active + // subpass uint32_t &sub = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass; + std::vector > imgbarriers; + for(sub = m_RenderState.subpass; sub < numSubpasses - 1; sub++) { ObjDisp(commandBuffer)->CmdNextSubpass(Unwrap(commandBuffer), VK_SUBPASS_CONTENTS_INLINE); - std::vector imgBarriers = GetImplicitRenderPassBarriers(); + std::vector subpassBarriers = GetImplicitRenderPassBarriers(); GetResourceManager()->RecordBarriers( - m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers, m_ImageLayouts, - (uint32_t)imgBarriers.size(), &imgBarriers[0]); + imgbarriers, m_ImageLayouts, (uint32_t)subpassBarriers.size(), &subpassBarriers[0]); } - std::vector imgBarriers = GetImplicitRenderPassBarriers(~0U); + std::vector finalBarriers = GetImplicitRenderPassBarriers(~0U); - GetResourceManager()->RecordBarriers( - m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers, m_ImageLayouts, - (uint32_t)imgBarriers.size(), &imgBarriers[0]); + GetResourceManager()->RecordBarriers(imgbarriers, m_ImageLayouts, + (uint32_t)finalBarriers.size(), &finalBarriers[0]); ObjDisp(commandBuffer)->CmdEndRenderPass(Unwrap(commandBuffer)); + + // undo any implicit transitions we just went through, so that we can pretend that the + // image stayed in the same layout as it was when we stopped partially replaying. + std::vector revertBarriers; + + for(auto it = imgbarriers.begin(); it != imgbarriers.end(); ++it) + { + VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + barrier.srcAccessMask = VK_ACCESS_ALL_READ_BITS | VK_ACCESS_ALL_WRITE_BITS; + barrier.dstAccessMask = VK_ACCESS_ALL_READ_BITS | VK_ACCESS_ALL_WRITE_BITS; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = Unwrap(GetResourceManager()->GetCurrentHandle(it->first)); + + // go from the layout we ended up in, to the layout we started in + barrier.oldLayout = it->second.newLayout; + barrier.newLayout = it->second.oldLayout; + + barrier.subresourceRange = it->second.subresourceRange; + + if(barrier.oldLayout != barrier.newLayout) + revertBarriers.push_back(barrier); + } + + if(!revertBarriers.empty()) + DoPipelineBarrier(commandBuffer, (uint32_t)revertBarriers.size(), revertBarriers.data()); } // also finish any nested markers we truncated and didn't finish