diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index aedc5c1d7..1f6c540bf 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -2881,6 +2881,13 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay VkResult vkr = VK_SUCCESS; bool rpWasActive = false; + // these are the image barriers to take the images from their current state to whatever is + // needed for the loadRP. This is because when creating the loadRP we set initial = final = + // attachment layout, to ensure it's in a known layout (and not transitioned from UNDEFINED or + // something). We do a 'safe' transition from current layout to what's expected in the + // attachment, which should always be a nop or overriding an UNDEFINED transition. Then we put + // it back again afterwards. + std::vector loadRPImgBarriers; // we'll need our own command buffer if we're replaying just a subsection // of events within a single command buffer record - always if it's only @@ -2904,29 +2911,29 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay if(m_Partial[Primary].renderPassActive) { // first apply implicit transitions to the right subpass - std::vector imgBarriers = GetImplicitRenderPassBarriers(); + loadRPImgBarriers = GetImplicitRenderPassBarriers(); // don't transition from undefined, or contents will be discarded, instead transition from // the current state. - for(size_t i = 0; i < imgBarriers.size(); i++) + for(size_t i = 0; i < loadRPImgBarriers.size(); i++) { - if(imgBarriers[i].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) + if(loadRPImgBarriers[i].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) { // TODO find overlapping range and transition that instead - imgBarriers[i].oldLayout = - m_ImageLayouts[GetResourceManager()->GetNonDispWrapper(imgBarriers[i].image)->id] + loadRPImgBarriers[i].oldLayout = + m_ImageLayouts[GetResourceManager()->GetNonDispWrapper(loadRPImgBarriers[i].image)->id] .subresourceStates[0] .newLayout; } } GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers, - m_ImageLayouts, (uint32_t)imgBarriers.size(), - &imgBarriers[0]); + m_ImageLayouts, (uint32_t)loadRPImgBarriers.size(), + &loadRPImgBarriers[0]); 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)imgBarriers.size(), &imgBarriers[0]); + (uint32_t)loadRPImgBarriers.size(), &loadRPImgBarriers[0]); const DrawcallDescription *draw = GetDrawcall(endEventID); @@ -2983,6 +2990,20 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay if(m_Partial[Primary].renderPassActive) m_RenderState.EndRenderPass(cmd); + // reverse the loadRPImgBarriers + for(size_t i = 0; i < loadRPImgBarriers.size(); i++) + { + std::swap(loadRPImgBarriers[i].oldLayout, loadRPImgBarriers[i].newLayout); + } + + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers, + m_ImageLayouts, (uint32_t)loadRPImgBarriers.size(), + &loadRPImgBarriers[0]); + + 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)loadRPImgBarriers.size(), &loadRPImgBarriers[0]); + // we might have replayed a CmdBeginRenderPass or CmdEndRenderPass, // but we want to keep the partial replay data state intact, so restore // whether or not a render pass was active. diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 235e6dcc0..94e1c5c17 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -922,9 +922,28 @@ bool WrappedVulkan::Serialise_vkEndCommandBuffer(SerialiserType &ser, VkCommandB uint32_t numSubpasses = (uint32_t)m_CreationInfo.m_RenderPass[m_RenderState.renderPass].subpasses.size(); - for(uint32_t sub = m_RenderState.subpass; sub < numSubpasses - 1; sub++) + // 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. + uint32_t &sub = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass; + + for(sub = m_RenderState.subpass; sub < numSubpasses - 1; sub++) + { ObjDisp(commandBuffer)->CmdNextSubpass(Unwrap(commandBuffer), VK_SUBPASS_CONTENTS_INLINE); + std::vector imgBarriers = GetImplicitRenderPassBarriers(); + + GetResourceManager()->RecordBarriers( + m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), &imgBarriers[0]); + } + + std::vector imgBarriers = GetImplicitRenderPassBarriers(~0U); + + GetResourceManager()->RecordBarriers( + m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers, m_ImageLayouts, + (uint32_t)imgBarriers.size(), &imgBarriers[0]); + ObjDisp(commandBuffer)->CmdEndRenderPass(Unwrap(commandBuffer)); }