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