From cb66100840158ccc27126b544b5158ea7b27b0a2 Mon Sep 17 00:00:00 2001 From: Benson Joeris Date: Thu, 16 Jan 2020 17:21:57 -0500 Subject: [PATCH] Add new image tracking to replay side Change-Id: I67ef6b1f6fd9b84621ec6700a8260c24afb35a05 --- renderdoc/driver/vulkan/vk_core.cpp | 106 ++---- renderdoc/driver/vulkan/vk_core.h | 12 - renderdoc/driver/vulkan/vk_debug.cpp | 21 +- renderdoc/driver/vulkan/vk_debug.h | 3 +- renderdoc/driver/vulkan/vk_initstate.cpp | 296 ++++------------ renderdoc/driver/vulkan/vk_manager.cpp | 20 +- renderdoc/driver/vulkan/vk_manager.h | 1 - renderdoc/driver/vulkan/vk_overlay.cpp | 64 ++-- renderdoc/driver/vulkan/vk_pixelhistory.cpp | 69 ++-- renderdoc/driver/vulkan/vk_rendertexture.cpp | 50 +-- renderdoc/driver/vulkan/vk_replay.cpp | 334 +++++++++--------- renderdoc/driver/vulkan/vk_replay.h | 3 +- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 160 +++++---- .../driver/vulkan/wrappers/vk_queue_funcs.cpp | 8 +- .../vulkan/wrappers/vk_resource_funcs.cpp | 93 ++--- .../driver/vulkan/wrappers/vk_sync_funcs.cpp | 5 +- .../driver/vulkan/wrappers/vk_wsi_funcs.cpp | 21 +- 17 files changed, 513 insertions(+), 753 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index d3dfa70f3..51f5fb417 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -360,89 +360,6 @@ void WrappedVulkan::FlushQ() } } -void WrappedVulkan::TempTransition(VkImage image, VkImageLayout layout, VkAccessFlags access, - rdcarray &setupBarriers, - rdcarray &cleanupBarriers, - bool &extQCleanup) const -{ - ResourceId id = GetResID(image); - - auto it = m_ImageLayouts.find(id); - - if(it == m_ImageLayouts.end()) - { - RDCERR("Can't find image layouts for image %s in TempTransition", ToStr(id).c_str()); - return; - } - - setupBarriers.clear(); - cleanupBarriers.clear(); - - const ImageLayouts &layouts = it->second; - - VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - - barrier.image = Unwrap(image); - barrier.newLayout = layout; - barrier.srcQueueFamilyIndex = layouts.queueFamilyIndex; - barrier.dstQueueFamilyIndex = GetQueueFamilyIndex(); - - extQCleanup = true; - - // if we're on the same queue, don't need to bother with queue acquire/release - if(barrier.srcQueueFamilyIndex == barrier.dstQueueFamilyIndex) - { - barrier.srcQueueFamilyIndex = barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - extQCleanup = false; - } - - barrier.dstAccessMask = access; - - for(const ImageRegionState ®ion : layouts.subresourceStates) - { - barrier.subresourceRange = region.subresourceRange; - barrier.oldLayout = region.newLayout; - barrier.srcAccessMask = VK_ACCESS_ALL_WRITE_BITS | MakeAccessMask(barrier.oldLayout); - SanitiseOldImageLayout(barrier.oldLayout); - - setupBarriers.push_back(barrier); - } - - if(SeparateDepthStencil()) - CombineDepthStencilLayouts(setupBarriers); - - cleanupBarriers = setupBarriers; - for(VkImageMemoryBarrier &b : cleanupBarriers) - { - std::swap(b.srcQueueFamilyIndex, b.dstQueueFamilyIndex); - std::swap(b.oldLayout, b.newLayout); - SanitiseNewImageLayout(b.newLayout); - b.srcAccessMask = access; - b.dstAccessMask = VK_ACCESS_ALL_READ_BITS | MakeAccessMask(b.newLayout); - } - - // if we have some queue transfer to do, submit the release on the ext queue now (which is what we - // defined above). The user will have to check the bool themselves and submit cleanupBarriers as - // external after they're done and submitted on the main queue - if(extQCleanup) - { - VkCommandBuffer extQCmd = GetExtQueueCmd(barrier.srcQueueFamilyIndex); - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - - VkResult vkr = ObjDisp(extQCmd)->BeginCommandBuffer(Unwrap(extQCmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - DoPipelineBarrier(extQCmd, setupBarriers.size(), setupBarriers.data()); - - vkr = ObjDisp(extQCmd)->EndCommandBuffer(Unwrap(extQCmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - SubmitAndFlushExtQueue(layouts.queueFamilyIndex); - } -} - VkCommandBuffer WrappedVulkan::GetExtQueueCmd(uint32_t queueFamilyIdx) const { if(queueFamilyIdx >= m_ExternalQueues.size()) @@ -2443,8 +2360,10 @@ ReplayStatus WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t sta ApplyInitialContents(); + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); SetDebugMessageSink(sink); } @@ -2661,6 +2580,19 @@ void WrappedVulkan::ApplyInitialContents() // actually apply the initial contents here GetResourceManager()->ApplyInitialContents(); + for(auto it = m_ImageStates.begin(); it != m_ImageStates.end(); ++it) + { + if(GetResourceManager()->HasCurrentResource(it->first)) + { + it->second.LockWrite()->ResetToOldState(m_cleanupImageBarriers, GetImageTransitionInfo()); + } + else + { + it = m_ImageStates.erase(it); + --it; + } + } + // likewise again to make sure the initial states are all applied cmd = GetNextCmd(); @@ -2673,7 +2605,10 @@ void WrappedVulkan::ApplyInitialContents() RDCASSERTEQUAL(vkr, VK_SUCCESS); #if ENABLED(SINGLE_FLUSH_VALIDATE) + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); + FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); #endif } @@ -3168,8 +3103,10 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay ApplyInitialContents(); VkMarkerRegion::End(); + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); } m_State = CaptureState::ActiveReplaying; @@ -3287,7 +3224,10 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay } #if ENABLED(SINGLE_FLUSH_VALIDATE) + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); + FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); #endif } diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 4b3c912f6..27784631f 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -577,7 +577,6 @@ private: } state; std::map imageStates; - rdcarray> imgbarriers; ResourceId pushDescriptorID[2][64]; @@ -763,9 +762,6 @@ private: std::map m_ImageStates; Threading::CriticalSection m_ImageStatesLock; - std::map m_ImageLayouts; - Threading::CriticalSection m_ImageLayoutsLock; - // find swapchain for an image std::map m_SwapLookup; Threading::CriticalSection m_SwapLookupLock; @@ -931,10 +927,6 @@ private: int32_t messageCode, const char *pLayerPrefix, const char *pMessage, void *pUserData); void AddFrameTerminator(uint64_t queueMarkerTag); - void ImageInitializationBarriers(ResourceId id, WrappedVkRes *live, InitPolicy policy, - bool initialized, const ImgRefs *imgRefs, - rdcarray &setupBarriers, - rdcarray &cleanupBarriers) const; void SubmitExtQBarriers(const std::map> &extQBarriers); void SubmitExtQBarriers(uint32_t queueFamilyIndex, const rdcarray &queueFamilyBarriers); @@ -1028,10 +1020,6 @@ public: void SubmitSemaphores(); void FlushQ(); - void TempTransition(VkImage image, VkImageLayout layout, VkAccessFlags access, - rdcarray &setupBarriers, - rdcarray &cleanupBarriers, bool &extQCleanup) const; - bool SeparateDepthStencil() const { return m_SeparateDepthStencil; } VulkanRenderState &GetRenderState() { return m_RenderState; } void SetDrawcallCB(VulkanDrawcallCallback *cb) { m_DrawcallCallback = cb; } diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 573d5daa9..106b5ddd8 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -881,22 +881,6 @@ void VulkanDebugManager::CreateCustomShaderTex(uint32_t width, uint32_t height, // need to update image layout into valid state - VkImageMemoryBarrier barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - Unwrap(m_Custom.TexImg), - {VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, 1}, - }; - - m_pDriver->m_ImageLayouts[GetResID(m_Custom.TexImg)].subresourceStates[0].newLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkCommandBuffer cmd = m_pDriver->GetNextCmd(); VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, @@ -904,7 +888,10 @@ void VulkanDebugManager::CreateCustomShaderTex(uint32_t width, uint32_t height, ObjDisp(dev)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - DoPipelineBarrier(cmd, 1, &barrier); + m_pDriver->FindImageState(GetResID(m_Custom.TexImg)) + ->InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + m_pDriver->GetImageTransitionInfo()); vkr = ObjDisp(dev)->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index c789932af..b55ace5fb 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -86,7 +86,8 @@ public: void PixelHistoryCopyPixel(VkCommandBuffer cmd, CopyPixelParams &p, size_t offset); - VkImageLayout GetImageLayout(ResourceId image, VkImageAspectFlags aspect, uint32_t mip); + VkImageLayout GetImageLayout(ResourceId image, VkImageAspectFlagBits aspect, uint32_t mip, + uint32_t slice); const VulkanCreationInfo::Image &GetImageInfo(ResourceId img); diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 6bff5593e..e398405f1 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -1208,22 +1208,21 @@ void WrappedVulkan::Create_InitialState(ResourceId id, WrappedVkRes *live, bool { ResourceId liveid = GetResourceManager()->GetLiveID(id); - if(m_ImageLayouts.find(liveid) == m_ImageLayouts.end()) + VkInitialContents::Tag tag = VkInitialContents::ClearColorImage; + LockedImageStateRef state = FindImageState(liveid); + if(!state) { - RDCERR("Couldn't find image info for %llu", id); + RDCERR("Couldn't find image info for %s", ToStr(id).c_str()); GetResourceManager()->SetInitialContents( id, VkInitialContents(type, VkInitialContents::ClearColorImage)); return; } + else if(IsDepthOrStencilFormat(state->GetImageInfo().format)) + { + tag = VkInitialContents::ClearDepthStencilImage; + } - ImageLayouts &layouts = m_ImageLayouts[liveid]; - - if(!IsDepthOrStencilFormat(layouts.imageInfo.format)) - GetResourceManager()->SetInitialContents( - id, VkInitialContents(type, VkInitialContents::ClearColorImage)); - else - GetResourceManager()->SetInitialContents( - id, VkInitialContents(type, VkInitialContents::ClearDepthStencilImage)); + GetResourceManager()->SetInitialContents(id, VkInitialContents(type, tag)); } else if(type == eResDeviceMemory) { @@ -1235,121 +1234,6 @@ void WrappedVulkan::Create_InitialState(ResourceId id, WrappedVkRes *live, bool } } -void WrappedVulkan::ImageInitializationBarriers(ResourceId id, WrappedVkRes *live, InitPolicy policy, - bool initialized, const ImgRefs *imgRefs, - rdcarray &setupBarriers, - rdcarray &cleanupBarriers) const -{ - // For each subresource that will be initialized (either copy or fill), create barriers that will - // transition the subresource from UNDEFINED to TRANSFER_DST_OPTIMAL before the write (in - // `setupBarriers`), and barriers to transition the subresource from TRANSFER_DST_OPTIMAL back to - // the current layout (`cleanupBarriers`). `cleanupBarriers` will also transfer ownership back to - // the correct queues, if necessary. - const ImageLayouts &imageLayouts = m_ImageLayouts.at(id); - - for(size_t si = 0; si < imageLayouts.subresourceStates.size(); si++) - { - VkImageMemoryBarrier barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - ToUnwrappedHandle(live), - imageLayouts.subresourceStates[si].subresourceRange, - }; - - if(IsDepthAndStencilFormat(imageLayouts.imageInfo.format) && !SeparateDepthStencil()) - { - if(barrier.subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) - { - // There will be a different subresourceState with DEPTH aspect, which is when we will - // handle both the depth and stencil aspects. - continue; - } - else - { - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } - } - - VkImageMemoryBarrier revBarrier = barrier; - revBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - revBarrier.newLayout = imageLayouts.subresourceStates[si].newLayout; - SanitiseNewImageLayout(revBarrier.newLayout); - - revBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - revBarrier.dstAccessMask = VK_ACCESS_ALL_READ_BITS | MakeAccessMask(revBarrier.newLayout); - if(imageLayouts.queueFamilyIndex != m_QueueFamilyIdx) - { - revBarrier.srcQueueFamilyIndex = m_QueueFamilyIdx; - revBarrier.dstQueueFamilyIndex = imageLayouts.queueFamilyIndex; - } - - if(!initialized) - { - setupBarriers.push_back(barrier); - cleanupBarriers.push_back(revBarrier); - } - else - { - if(IsDepthAndStencilFormat(imageLayouts.imageInfo.format) && SeparateDepthStencil()) - { - // process as if we're looking at both aspects in a depth/stencil format whenever we see - // either. If both are already separate, we need to transition them separately - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } - - auto initReqs = - imgRefs->SubresourceRangeInitReqs(barrier.subresourceRange, policy, initialized); - for(auto initIt = initReqs.begin(); initIt != initReqs.end(); ++initIt) - { - barrier.subresourceRange = revBarrier.subresourceRange = initIt->first; - InitReqType initReq = initIt->second; - if(IsDepthAndStencilFormat(imageLayouts.imageInfo.format)) - { - if(SeparateDepthStencil()) - { - // conservatively set init requirements for both aspects whenever we see either aspect. - barrier.subresourceRange.aspectMask = revBarrier.subresourceRange.aspectMask = - VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - initReq = - imgRefs->SubresourceRangeMaxInitReq(barrier.subresourceRange, policy, initialized); - // but transition the original aspect. These barriers will be combined if identical - barrier.subresourceRange.aspectMask = revBarrier.subresourceRange.aspectMask = - imageLayouts.subresourceStates[si].subresourceRange.aspectMask; - } - else - { - if(barrier.subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) - { - // There will be a different subresourceState with DEPTH aspect, which is when we will - // handle both the depth and stencil aspects. - continue; - } - else if(barrier.subresourceRange.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) - { - barrier.subresourceRange.aspectMask = revBarrier.subresourceRange.aspectMask = - VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - initReq = - imgRefs->SubresourceRangeMaxInitReq(barrier.subresourceRange, policy, initialized); - } - } - } - - if(initReq != eInitReq_None) - { - setupBarriers.push_back(barrier); - cleanupBarriers.push_back(revBarrier); - } - } - } - } -} - std::map > GetExtQBarriers( const rdcarray &barriers) { @@ -1466,22 +1350,25 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; ResourceId orig = GetResourceManager()->GetOriginalID(id); - ImgRefs *imgRefs = GetResourceManager()->FindImgRefs(orig); bool initialized = false; InitPolicy policy = GetResourceManager()->GetInitPolicy(); - if(imgRefs) + LockedImageStateRef state = FindImageState(id); + if(!state) { - initialized = imgRefs->initializedLiveRes == live; - imgRefs->initializedLiveRes = live; + RDCWARN("No image state found for image %s", ToStr(id).c_str()); + return; } + ResourceId boundMemory = state->boundMemory; + VkDeviceSize boundMemoryOffset = state->boundMemoryOffset; + VkDeviceSize boundMemorySize = state->boundMemorySize; + const ImageInfo &imageInfo = state->GetImageInfo(); + initialized = IsActiveReplaying(m_State); - ImageLayouts &layout = m_ImageLayouts[id]; - - if(initialized && layout.boundMemory != ResourceId()) + if(initialized && boundMemory != ResourceId()) { - ResourceId origMem = GetResourceManager()->GetOriginalID(layout.boundMemory); + ResourceId origMem = GetResourceManager()->GetOriginalID(boundMemory); if(origMem != ResourceId()) { MemRefs *memRefs = GetResourceManager()->FindMemRefs(origMem); @@ -1497,9 +1384,8 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten } else { - for(auto it = memRefs->rangeRefs.find(layout.boundMemoryOffset); - it != memRefs->rangeRefs.end() && - it->start() < layout.boundMemoryOffset + layout.boundMemorySize; + for(auto it = memRefs->rangeRefs.find(boundMemoryOffset); + it != memRefs->rangeRefs.end() && it->start() < boundMemoryOffset + boundMemorySize; ++it) { if(IncludesWrite(it->value()) || @@ -1526,7 +1412,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten { if(initial.tag == VkInitialContents::ClearColorImage) { - VkFormat format = layout.imageInfo.format; + VkFormat format = imageInfo.format; // can't clear these, so leave them alone. if(IsBlockFormat(format) || IsYUVFormat(format)) @@ -1537,11 +1423,12 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; - TempTransition(ToWrappedHandle(live), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, setupBarriers, cleanupBarriers, extQCleanup); - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); + ImageBarrierSequence setupBarriers; + state->DiscardContents(); + state->Transition(m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, setupBarriers, GetImageTransitionInfo()); + InlineSetupImageBarriers(cmd, setupBarriers); + m_setupImageBarriers.Merge(setupBarriers); VkClearColorValue clearval = {}; VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, @@ -1550,63 +1437,43 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten ObjDisp(cmd)->CmdClearColorImage(Unwrap(cmd), ToUnwrappedHandle(live), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearval, 1, &range); - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); - - if(extQCleanup) - { - // ensure work is completed before we pass ownership back to original queue - SubmitCmds(); - FlushQ(); - - SubmitExtQBarriers(~0U, cleanupBarriers); - } - #if ENABLED(SINGLE_FLUSH_VALIDATE) + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); + FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); #endif } else if(initial.tag == VkInitialContents::ClearDepthStencilImage) { - VkFormat format = layout.imageInfo.format; - VkCommandBuffer cmd = GetNextCmd(); vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; - TempTransition(ToWrappedHandle(live), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, setupBarriers, cleanupBarriers, extQCleanup); - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); + ImageBarrierSequence setupBarriers; // , cleanupBarriers; + state->DiscardContents(); + state->Transition(m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, setupBarriers, GetImageTransitionInfo()); + InlineSetupImageBarriers(cmd, setupBarriers); + m_setupImageBarriers.Merge(setupBarriers); VkClearDepthStencilValue clearval = {1.0f, 0}; - VkImageSubresourceRange range = {FormatImageAspects(format), 0, VK_REMAINING_MIP_LEVELS, 0, - VK_REMAINING_ARRAY_LAYERS}; + VkImageSubresourceRange range = imageInfo.FullRange(); ObjDisp(cmd)->CmdClearDepthStencilImage(Unwrap(cmd), ToUnwrappedHandle(live), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearval, 1, &range); - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); - - if(extQCleanup) - { - // ensure work is completed before we pass ownership back to original queue - SubmitCmds(); - FlushQ(); - - SubmitExtQBarriers(~0U, cleanupBarriers); - } - #if ENABLED(SINGLE_FLUSH_VALIDATE) + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); + FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); #endif } else @@ -1628,12 +1495,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten VkFormat fmt = c.format; - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; - TempTransition(ToWrappedHandle(live), VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - setupBarriers, cleanupBarriers, extQCleanup); - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); + ImageBarrierSequence setupBarriers; // , cleanupBarriers; + state->DiscardContents(); + state->Transition(m_QueueFamilyIdx, VK_IMAGE_LAYOUT_GENERAL, 0, + VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + setupBarriers, GetImageTransitionInfo()); + InlineSetupImageBarriers(cmd, setupBarriers); + m_setupImageBarriers.Merge(setupBarriers); VkImage arrayIm = initial.img; @@ -1649,22 +1517,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); - - if(extQCleanup) - { - // ensure work is completed before we pass ownership back to original queue - SubmitCmds(); - FlushQ(); - - SubmitExtQBarriers(~0U, cleanupBarriers); - } - #if ENABLED(SINGLE_FLUSH_VALIDATE) + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); + FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); #endif return; } @@ -1719,17 +1578,11 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten } } - rdcarray setupBarriers, cleanupBarriers; - ImageInitializationBarriers(id, live, policy, initialized, imgRefs, setupBarriers, - cleanupBarriers); - if(SeparateDepthStencil()) - { - CombineDepthStencilLayouts(setupBarriers); - CombineDepthStencilLayouts(cleanupBarriers); - } - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); - - SubmitExtQBarriers(GetExtQBarriers(setupBarriers)); + ImageBarrierSequence setupBarriers; + state->Transition(m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, setupBarriers, GetImageTransitionInfo()); + InlineSetupImageBarriers(cmd, setupBarriers); + m_setupImageBarriers.Merge(setupBarriers); VkDeviceSize bufOffset = 0; @@ -1781,9 +1634,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten bufOffset += GetPlaneByteSize(extent.width, extent.height, extent.depth, fmt, 0, i); if(!initialized) + { initReq = eInitReq_Copy; + } else - initReq = imgRefs->SubresourceRangeMaxInitReq(range, policy, initialized); + { + initReq = state->MaxInitReq(range, policy, initialized); + } if(initReq == eInitReq_Copy) copyRegions.push_back(region); else if(initReq == eInitReq_Clear) @@ -1797,9 +1654,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; if(!initialized) + { initReq = eInitReq_Copy; + } else - initReq = imgRefs->SubresourceRangeMaxInitReq(range, policy, initialized); + { + initReq = state->MaxInitReq(range, policy, initialized); + } if(initReq == eInitReq_None) continue; @@ -1838,9 +1699,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten bufOffset += GetByteSize(extent.width, extent.height, extent.depth, fmt, 0); if(!initialized) + { initReq = eInitReq_Copy; + } else - initReq = imgRefs->SubresourceRangeMaxInitReq(range, policy, initialized); + { + initReq = state->MaxInitReq(range, policy, initialized); + } if(initReq == eInitReq_Copy) copyRegions.push_back(region); else if(initReq == eInitReq_Clear) @@ -1878,24 +1743,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten } } - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); - - std::map > extQBarriers = - GetExtQBarriers(cleanupBarriers); - if(extQBarriers.size() > 0) - { - // ensure work is completed before we pass ownership back to original queue - SubmitCmds(); - FlushQ(); - - SubmitExtQBarriers(extQBarriers); - } - #if ENABLED(SINGLE_FLUSH_VALIDATE) + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); + FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); #endif } else if(type == eResDeviceMemory) diff --git a/renderdoc/driver/vulkan/vk_manager.cpp b/renderdoc/driver/vulkan/vk_manager.cpp index 6385ee152..dbd46eae3 100644 --- a/renderdoc/driver/vulkan/vk_manager.cpp +++ b/renderdoc/driver/vulkan/vk_manager.cpp @@ -285,6 +285,8 @@ void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser, } else { + bool hasLiveRes = HasLiveResource(Image); + ImageState imageState; if(ser.VersionLess(0x11)) @@ -294,7 +296,7 @@ void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser, ImageLayouts &ImageState = imageLayouts; SERIALISE_ELEMENT(ImageState); } - if(IsReplayingAndReading()) + if(IsReplayingAndReading() && hasLiveRes) { if(imageLayouts.imageInfo.extent.depth > 1) imageLayouts.imageInfo.imageType = VK_IMAGE_TYPE_3D; @@ -317,7 +319,8 @@ void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser, subresourceStates.push_back(p); } - imageState.subresourceStates.FromArray(subresourceStates); + if(!subresourceStates.empty()) + imageState.subresourceStates.FromArray(subresourceStates); imageState.maxRefType = eFrameRef_Unknown; } } @@ -327,7 +330,7 @@ void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser, ::ImageState &ImageState = imageState; SERIALISE_ELEMENT(ImageState); } - if(IsReplayingAndReading()) + if(IsReplayingAndReading() && hasLiveRes) { imageState.newQueueFamilyTransfers.clear(); for(auto it = imageState.subresourceStates.begin(); @@ -342,7 +345,7 @@ void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser, } } } - if(HasLiveResource(Image)) + if(hasLiveRes) { ResourceId liveid = GetLiveID(Image); @@ -878,15 +881,6 @@ MemRefs *VulkanResourceManager::FindMemRefs(ResourceId mem) return NULL; } -ImgRefs *VulkanResourceManager::FindImgRefs(ResourceId img) -{ - auto it = m_ImgFrameRefs.find(img); - if(it != m_ImgFrameRefs.end()) - return &it->second; - else - return NULL; -} - bool VulkanResourceManager::Prepare_InitialState(WrappedVkRes *res) { return m_Core->Prepare_InitialState(res); diff --git a/renderdoc/driver/vulkan/vk_manager.h b/renderdoc/driver/vulkan/vk_manager.h index b68073827..fc93dcbd5 100644 --- a/renderdoc/driver/vulkan/vk_manager.h +++ b/renderdoc/driver/vulkan/vk_manager.h @@ -460,6 +460,5 @@ private: WrappedVulkan *m_Core; std::map m_MemFrameRefs; - std::map m_ImgFrameRefs; InitPolicy m_InitPolicy = eInitPolicy_CopyAll; }; diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index 7da12c027..c51993cba 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -518,23 +518,10 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeCast, Floa // need to update image layout into valid state - VkImageMemoryBarrier barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - Unwrap(m_Overlay.Image), - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, - }; - - m_pDriver->m_ImageLayouts[GetResID(m_Overlay.Image)].subresourceStates[0].newLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - DoPipelineBarrier(cmd, 1, &barrier); + m_pDriver->FindImageState(GetResID(m_Overlay.Image)) + ->InlineTransition( + cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, m_pDriver->GetImageTransitionInfo()); VkAttachmentDescription colDesc = { 0, @@ -1290,21 +1277,16 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeCast, Floa attDescs[1].format = depthImageInfo.format; attDescs[0].samples = attDescs[1].samples = iminfo.samples; - rdcarray &depthStates = m_pDriver->m_ImageLayouts[depthIm].subresourceStates; - - for(ImageRegionState &ds : depthStates) { - // find the state that overlaps the view's subresource range start. We assume all - // subresources are correctly in the same state (as they should be) so we just need to find - // the first match. - if(ds.subresourceRange.baseArrayLayer <= depthViewInfo.range.baseArrayLayer && - ds.subresourceRange.baseArrayLayer + 1 > depthViewInfo.range.baseArrayLayer && - ds.subresourceRange.baseMipLevel <= depthViewInfo.range.baseMipLevel && - ds.subresourceRange.baseMipLevel + ds.subresourceRange.levelCount + 1 > - depthViewInfo.range.baseMipLevel) + LockedConstImageStateRef imState = m_pDriver->FindConstImageState(depthIm); + if(imState) { - attDescs[1].initialLayout = attDescs[1].finalLayout = ds.newLayout; - break; + // find the state that overlaps the view's subresource range start. We assume all + // subresources are correctly in the same state (as they should be) so we just need to + // find the first match. + auto it = imState->subresourceStates.RangeBegin(depthViewInfo.range); + if(it != imState->subresourceStates.end()) + attDescs[1].initialLayout = attDescs[1].finalLayout = it->state().newLayout; } } @@ -2073,22 +2055,16 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeCast, Floa attDescs[1].format = depthImageInfo.format; attDescs[0].samples = attDescs[1].samples = iminfo.samples; - rdcarray &depthStates = - m_pDriver->m_ImageLayouts[depthIm].subresourceStates; - - for(ImageRegionState &ds : depthStates) { - // find the state that overlaps the view's subresource range start. We assume all - // subresources are correctly in the same state (as they should be) so we just need to - // find the first match. - if(ds.subresourceRange.baseArrayLayer <= depthViewInfo.range.baseArrayLayer && - ds.subresourceRange.baseArrayLayer + 1 > depthViewInfo.range.baseArrayLayer && - ds.subresourceRange.baseMipLevel <= depthViewInfo.range.baseMipLevel && - ds.subresourceRange.baseMipLevel + ds.subresourceRange.levelCount + 1 > - depthViewInfo.range.baseMipLevel) + LockedConstImageStateRef imState = m_pDriver->FindConstImageState(depthIm); + if(imState) { - attDescs[1].initialLayout = attDescs[1].finalLayout = ds.newLayout; - break; + // find the state that overlaps the view's subresource range start. We assume all + // subresources are correctly in the same state (as they should be) so we just need to + // find the first match. + auto it = imState->subresourceStates.RangeBegin(depthViewInfo.range); + if(it != imState->subresourceStates.end()) + attDescs[1].initialLayout = attDescs[1].finalLayout = it->state().newLayout; } } diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index fb1364baf..9ecabcbee 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -1345,6 +1345,10 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &colorImage); RDCASSERTEQUAL(vkr, VK_SUCCESS); + VkImage wrappedColorImage = colorImage; + m_pDriver->GetResourceManager()->WrapResource(Unwrap(dev), wrappedColorImage); + ImageState colorImageState = ImageState(wrappedColorImage, ImageInfo(imgInfo), eFrameRef_None); + VkMemoryRequirements colorImageMrq = {0}; m_pDriver->vkGetImageMemoryRequirements(dev, colorImage, &colorImageMrq); @@ -1355,6 +1359,10 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &stencilImage); RDCASSERTEQUAL(vkr, VK_SUCCESS); + VkImage wrappedStencilImage = stencilImage; + m_pDriver->GetResourceManager()->WrapResource(Unwrap(dev), wrappedStencilImage); + ImageState stencilImageState = ImageState(wrappedStencilImage, ImageInfo(imgInfo), eFrameRef_None); + VkMemoryRequirements stencilImageMrq = {0}; m_pDriver->vkGetImageMemoryRequirements(dev, stencilImage, &stencilImageMrq); VkDeviceSize offset = AlignUp(colorImageMrq.size, stencilImageMrq.alignment); @@ -1413,34 +1421,13 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou vkr = ObjDisp(dev)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); - VkImageMemoryBarrier barriers[2] = {}; - barriers[0] = {}; - barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[0].srcAccessMask = 0; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barriers[0].subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; - barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barriers[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barriers[0].image = Unwrap(colorImage); + colorImageState.InlineTransition( + cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, m_pDriver->GetImageTransitionInfo()); + stencilImageState.InlineTransition( + cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 0, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, m_pDriver->GetImageTransitionInfo()); - barriers[1] = barriers[0]; - barriers[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - barriers[1].newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - barriers[1].subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, - 1}; - barriers[1].image = Unwrap(stencilImage); - - DoPipelineBarrier(cmd, 2, barriers); - - { - SCOPED_LOCK(m_pDriver->m_ImageLayoutsLock); - m_pDriver->m_ImageLayouts[GetResID(colorImage)].subresourceStates[0].newLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - m_pDriver->m_ImageLayouts[GetResID(stencilImage)].subresourceStates[0].newLayout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } vkr = ObjDisp(dev)->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); m_pDriver->SubmitCmds(); @@ -1569,23 +1556,19 @@ void CreateOcclusionPool(WrappedVulkan *vk, uint32_t poolSize, VkQueryPool *pQue vk->FlushQ(); } -VkImageLayout VulkanDebugManager::GetImageLayout(ResourceId image, VkImageAspectFlags aspect, - uint32_t mip) +VkImageLayout VulkanDebugManager::GetImageLayout(ResourceId image, VkImageAspectFlagBits aspect, + uint32_t mip, uint32_t slice) { - VkImageLayout imgLayout = VK_IMAGE_LAYOUT_UNDEFINED; - const ImageLayouts &imgLayouts = m_pDriver->m_ImageLayouts[image]; - for(const ImageRegionState &resState : imgLayouts.subresourceStates) + auto state = m_pDriver->FindConstImageState(image); + if(!state) { - VkImageSubresourceRange range = resState.subresourceRange; - - if((range.aspectMask & aspect) && - (mip >= range.baseMipLevel && mip < range.baseMipLevel + range.levelCount)) - { - // Consider using the layer count - imgLayout = resState.newLayout; - } + RDCERR("Could not find image state for %s", ToStr(image).c_str()); + return VK_IMAGE_LAYOUT_UNDEFINED; } - return imgLayout; + if(state->GetImageInfo().extent.depth > 1) + return state->GetImageLayout(aspect, mip, 0); + else + return state->GetImageLayout(aspect, mip, slice); } void UpdateTestsFailed(const TestsFailedCallback *tfCb, uint32_t eventId, uint32_t eventFlags, @@ -1686,10 +1669,12 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even return history; uint32_t mip = sub.mip; + uint32_t slice = sub.slice; uint32_t sampleIdx = sub.sample; // TODO: figure out correct aspect. - VkImageLayout imgLayout = GetDebugManager()->GetImageLayout(target, VK_IMAGE_ASPECT_COLOR_BIT, mip); + VkImageLayout imgLayout = + GetDebugManager()->GetImageLayout(target, VK_IMAGE_ASPECT_COLOR_BIT, mip, slice); RDCASSERTNOTEQUAL(imgLayout, VK_IMAGE_LAYOUT_UNDEFINED); // TODO: use the given type hint for typeless textures diff --git a/renderdoc/driver/vulkan/vk_rendertexture.cpp b/renderdoc/driver/vulkan/vk_rendertexture.cpp index d7e3839ba..1ec5533f0 100644 --- a/renderdoc/driver/vulkan/vk_rendertexture.cpp +++ b/renderdoc/driver/vulkan/vk_rendertexture.cpp @@ -145,10 +145,21 @@ bool VulkanReplay::RenderTexture(TextureDisplay cfg) NULL, }; - return RenderTextureInternal(cfg, rpbegin, eTexDisplay_MipShift | eTexDisplay_BlendAlpha); + LockedConstImageStateRef imageState = m_pDriver->FindConstImageState(cfg.resourceId); + if(!imageState) + { + RDCWARN("Could not find image info for image %s", ToStr(cfg.resourceId).c_str()); + return false; + } + if(!imageState->isMemoryBound) + return false; + + return RenderTextureInternal(cfg, *imageState, rpbegin, + eTexDisplay_MipShift | eTexDisplay_BlendAlpha); } -bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginInfo rpbegin, int flags) +bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, const ImageState &imageState, + VkRenderPassBeginInfo rpbegin, int flags) { const bool blendAlpha = (flags & eTexDisplay_BlendAlpha) != 0; const bool mipShift = (flags & eTexDisplay_MipShift) != 0; @@ -159,14 +170,11 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn VkDevice dev = m_pDriver->GetDev(); const VkDevDispatchTable *vt = ObjDisp(dev); - ImageLayouts &layouts = m_pDriver->m_ImageLayouts[cfg.resourceId]; + const ImageInfo &imageInfo = imageState.GetImageInfo(); + VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[cfg.resourceId]; TextureDisplayViews &texviews = m_TexRender.TextureViews[cfg.resourceId]; VkImage liveIm = m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.resourceId); - const ImageInfo &imageInfo = layouts.imageInfo; - - if(!layouts.isMemoryBound) - return false; CreateTexImageView(liveIm, iminfo, cfg.typeCast, texviews); @@ -481,12 +489,12 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; - m_pDriver->TempTransition(liveIm, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_SHADER_READ_BIT, setupBarriers, cleanupBarriers, extQCleanup); - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); - + ImageBarrierSequence setupBarriers, cleanupBarriers; + imageState.TempTransition(m_pDriver->GetQueueFamilyIndex(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, + setupBarriers, cleanupBarriers, m_pDriver->GetImageTransitionInfo()); + m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); { vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); @@ -556,21 +564,19 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn vt->CmdEndRenderPass(Unwrap(cmd)); } - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - + m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); vt->EndCommandBuffer(Unwrap(cmd)); - - if(extQCleanup) + if(!cleanupBarriers.empty()) { - // ensure work is completed before we pass ownership back to original queue m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); - - m_pDriver->SubmitExtQBarriers(~0U, cleanupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); } - #if ENABLED(SINGLE_FLUSH_VALIDATE) - m_pDriver->SubmitCmds(); + else + { + m_pDriver->SubmitCmds(); + } #endif return true; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 6b3f7bf93..1df369241 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -296,7 +296,7 @@ rdcarray VulkanReplay::GetTextures() { rdcarray texs; - for(auto it = m_pDriver->m_ImageLayouts.begin(); it != m_pDriver->m_ImageLayouts.end(); ++it) + for(auto it = m_pDriver->m_ImageStates.begin(); it != m_pDriver->m_ImageStates.end(); ++it) { // skip textures that aren't from the capture if(m_pDriver->GetResourceManager()->GetOriginalID(it->first) == it->first) @@ -1849,9 +1849,9 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) // image layouts { - m_VulkanPipelineState.images.resize(m_pDriver->m_ImageLayouts.size()); size_t i = 0; - for(auto it = m_pDriver->m_ImageLayouts.begin(); it != m_pDriver->m_ImageLayouts.end(); ++it) + m_VulkanPipelineState.images.resize(m_pDriver->m_ImageStates.size()); + for(auto it = m_pDriver->m_ImageStates.begin(); it != m_pDriver->m_ImageStates.end(); ++it) { VKPipe::ImageData &img = m_VulkanPipelineState.images[i]; @@ -1860,14 +1860,16 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) img.resourceId = rm->GetOriginalID(it->first); - img.layouts.resize(it->second.subresourceStates.size()); - for(size_t l = 0; l < it->second.subresourceStates.size(); l++) + LockedConstImageStateRef imState = it->second.LockRead(); + img.layouts.resize(imState->subresourceStates.size()); + auto subIt = imState->subresourceStates.begin(); + for(size_t l = 0; l < img.layouts.size(); ++l, ++subIt) { - img.layouts[l].name = ToStr(it->second.subresourceStates[l].newLayout); - img.layouts[l].baseMip = it->second.subresourceStates[l].subresourceRange.baseMipLevel; - img.layouts[l].baseLayer = it->second.subresourceStates[l].subresourceRange.baseArrayLayer; - img.layouts[l].numLayer = it->second.subresourceStates[l].subresourceRange.layerCount; - img.layouts[l].numMip = it->second.subresourceStates[l].subresourceRange.levelCount; + img.layouts[l].name = ToStr(subIt->state().newLayout); + img.layouts[l].baseMip = subIt->range().baseMipLevel; + img.layouts[l].numMip = subIt->range().levelCount; + img.layouts[l].baseLayer = subIt->range().baseArrayLayer; + img.layouts[l].numLayer = subIt->range().layerCount; } if(img.layouts.empty()) @@ -1965,6 +1967,14 @@ void VulkanReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const S m_DebugWidth = m_DebugHeight = 1; VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texture]; + LockedConstImageStateRef imageState = m_pDriver->FindConstImageState(texture); + if(!imageState) + { + RDCWARN("Could not find image info for image %s", ToStr(texture).c_str()); + return; + } + if(!imageState->isMemoryBound) + return; bool isStencil = IsStencilFormat(iminfo.format); @@ -2012,7 +2022,8 @@ void VulkanReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const S &clearval, }; - RenderTextureInternal(texDisplay, rpbegin, eTexDisplay_32Render | eTexDisplay_MipShift); + RenderTextureInternal(texDisplay, *imageState, rpbegin, + eTexDisplay_32Render | eTexDisplay_MipShift); } VkDevice dev = m_pDriver->GetDev(); @@ -2114,9 +2125,15 @@ void VulkanReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const S bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval, float *maxval) { - ImageLayouts &layouts = m_pDriver->m_ImageLayouts[texid]; + const ImageInfo *imageInfo = NULL; + { + LockedConstImageStateRef state = m_pDriver->FindConstImageState(texid); + if(!state) + return false; + imageInfo = &state->GetImageInfo(); + } - if(IsDepthAndStencilFormat(layouts.imageInfo.format)) + if(IsDepthAndStencilFormat(imageInfo->format)) { // for depth/stencil we need to run the code twice - once to fetch depth and once to fetch // stencil - since we can't process float depth and int stencil at the same time @@ -2154,12 +2171,15 @@ bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType VkDevice dev = m_pDriver->GetDev(); const VkDevDispatchTable *vt = ObjDisp(dev); - ImageLayouts &layouts = m_pDriver->m_ImageLayouts[texid]; + LockedConstImageStateRef state = m_pDriver->FindConstImageState(texid); + if(!state) + return false; + bool isMemoryBound = state->isMemoryBound; VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texid]; TextureDisplayViews &texviews = m_TexRender.TextureViews[texid]; VkImage liveIm = m_pDriver->GetResourceManager()->GetCurrentHandle(texid); - if(!layouts.isMemoryBound) + if(!isMemoryBound) return false; if(!IsStencilFormat(iminfo.format)) @@ -2339,11 +2359,6 @@ bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType m_Histogram.m_HistogramUBO.Unmap(); - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; - m_pDriver->TempTransition(liveIm, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_SHADER_READ_BIT, setupBarriers, cleanupBarriers, extQCleanup); - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; @@ -2351,7 +2366,12 @@ bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); + ImageBarrierSequence setupBarriers, cleanupBarriers; + state->TempTransition(m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_SHADER_READ_BIT, setupBarriers, cleanupBarriers, + m_pDriver->GetImageTransitionInfo()); + m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); int blocksX = (int)ceil(iminfo.extent.width / float(HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK)); int blocksY = @@ -2365,7 +2385,16 @@ bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType vt->CmdDispatch(Unwrap(cmd), blocksX, blocksY, 1); - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); + m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); + if(!cleanupBarriers.empty()) + { + vt->EndCommandBuffer(Unwrap(cmd)); + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); + cmd = m_pDriver->GetNextCmd(); + vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + } VkBufferMemoryBarrier tilebarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, @@ -2419,9 +2448,6 @@ bool VulkanReplay::GetMinMax(ResourceId texid, const Subresource &sub, CompType m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); - if(extQCleanup) - m_pDriver->SubmitExtQBarriers(~0U, cleanupBarriers); - Vec4f *minmax = (Vec4f *)m_Histogram.m_MinMaxReadback.Map(NULL); minval[0] = minmax[0].x; @@ -2449,14 +2475,13 @@ bool VulkanReplay::GetHistogram(ResourceId texid, const Subresource &sub, CompTy VkDevice dev = m_pDriver->GetDev(); const VkDevDispatchTable *vt = ObjDisp(dev); - ImageLayouts &layouts = m_pDriver->m_ImageLayouts[texid]; + LockedConstImageStateRef state = m_pDriver->FindConstImageState(texid); + if(!state->isMemoryBound) + return false; VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texid]; TextureDisplayViews &texviews = m_TexRender.TextureViews[texid]; VkImage liveIm = m_pDriver->GetResourceManager()->GetCurrentHandle(texid); - if(!layouts.isMemoryBound) - return false; - bool stencil = false; // detect if stencil is selected if(IsStencilFormat(iminfo.format) && !channels[0] && channels[1] && !channels[2] && !channels[3]) @@ -2655,11 +2680,12 @@ bool VulkanReplay::GetHistogram(ResourceId texid, const Subresource &sub, CompTy vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; - m_pDriver->TempTransition(liveIm, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT, - setupBarriers, cleanupBarriers, extQCleanup); - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); + ImageBarrierSequence setupBarriers, cleanupBarriers; + state->TempTransition(m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_READ_BIT, setupBarriers, cleanupBarriers, + m_pDriver->GetImageTransitionInfo()); + m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); int blocksX = (int)ceil(iminfo.extent.width / float(HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK)); int blocksY = @@ -2676,7 +2702,16 @@ bool VulkanReplay::GetHistogram(ResourceId texid, const Subresource &sub, CompTy vt->CmdDispatch(Unwrap(cmd), blocksX, blocksY, 1); - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); + m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); + if(!cleanupBarriers.empty()) + { + vt->EndCommandBuffer(Unwrap(cmd)); + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); + cmd = m_pDriver->GetNextCmd(); + vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + } VkBufferMemoryBarrier tilebarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, @@ -2714,9 +2749,6 @@ bool VulkanReplay::GetHistogram(ResourceId texid, const Subresource &sub, CompTy m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); - if(extQCleanup) - m_pDriver->SubmitExtQBarriers(~0U, cleanupBarriers); - uint32_t *buckets = (uint32_t *)m_Histogram.m_HistogramReadback.Map(NULL); histogram.assign(buckets, HGRAM_NUM_BUCKETS); @@ -2745,10 +2777,11 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, const VulkanCreationInfo::Image &imInfo = m_pDriver->m_CreationInfo.m_Image[tex]; - ImageLayouts &layouts = m_pDriver->m_ImageLayouts[tex]; - - if(!layouts.isMemoryBound) + LockedConstImageStateRef lockedImage = m_pDriver->FindConstImageState(tex); + if(!lockedImage || !lockedImage->isMemoryBound) return; + const ImageState *srcImageState = &*lockedImage; + ImageState tmpImageState; VkMarkerRegion region(StringFormat::Fmt("GetTextureData(%u, %u, %u, remap=%d)", sub.mip, sub.slice, sub.sample, params.remap)); @@ -2781,10 +2814,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, VkImage srcImage = Unwrap(liveWrappedImage); VkImage tmpImage = VK_NULL_HANDLE; + VkImage wrappedTmpImage = VK_NULL_HANDLE; VkDeviceMemory tmpMemory = VK_NULL_HANDLE; - uint32_t srcQueueIndex = layouts.queueFamilyIndex; - VkFramebuffer *tmpFB = NULL; VkImageView *tmpView = NULL; uint32_t numFBs = 0; @@ -2812,9 +2844,6 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, if(wasms && (isDepth || isStencil)) resolve = false; - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; - if(params.remap != RemapTexture::NoRemap) { int renderFlags = 0; @@ -2875,6 +2904,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, // create render texture similar to readback texture vt->CreateImage(Unwrap(dev), &imCreateInfo, NULL, &tmpImage); + wrappedTmpImage = tmpImage; + GetResourceManager()->WrapResource(Unwrap(dev), wrappedTmpImage); + tmpImageState = ImageState(wrappedTmpImage, ImageInfo(imCreateInfo), eFrameRef_None); VkMemoryRequirements mrq = {0}; vt->GetImageMemoryRequirements(Unwrap(dev), tmpImage, &mrq); @@ -2890,21 +2922,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, vkr = vt->BindImageMemory(Unwrap(dev), tmpImage, tmpMemory, 0); RDCASSERTEQUAL(vkr, VK_SUCCESS); - VkImageMemoryBarrier dstimBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - 0, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - tmpImage, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, - }; - - // move tmp image into transfer destination layout - DoPipelineBarrier(cmd, 1, &dstimBarrier); + tmpImageState.InlineTransition( + cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, m_pDriver->GetImageTransitionInfo()); // end this command buffer, the rendertexture below will use its own and we want to ensure // ordering @@ -3046,7 +3066,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, &clearval, }; - RenderTextureInternal(texDisplay, rpbegin, renderFlags); + RenderTextureInternal(texDisplay, *srcImageState, rpbegin, renderFlags); renderCount++; // for textures with stencil, do another draw to copy the stencil @@ -3062,8 +3082,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, rpbegin.framebuffer = tmpFB[i + numFBs]; texDisplay.red = texDisplay.blue = texDisplay.alpha = false; - RenderTextureInternal(texDisplay, rpbegin, (renderFlags & ~eTexDisplay_RemapFloat) | - eTexDisplay_RemapUInt | eTexDisplay_GreenOnly); + RenderTextureInternal(texDisplay, *srcImageState, rpbegin, + (renderFlags & ~eTexDisplay_RemapFloat) | eTexDisplay_RemapUInt | + eTexDisplay_GreenOnly); renderCount++; } } @@ -3072,7 +3093,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, m_DebugHeight = oldH; srcImage = tmpImage; - srcQueueIndex = m_pDriver->GetQueueFamilyIndex(); + srcImageState = &tmpImageState; // fetch a new command buffer for copy & readback cmd = m_pDriver->GetNextCmd(); @@ -3080,13 +3101,10 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); - // ensure all writes happen before copy & readback - dstimBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - dstimBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - dstimBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstimBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - - DoPipelineBarrier(cmd, 1, &dstimBarrier); + tmpImageState.InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, m_pDriver->GetImageTransitionInfo()); // these have already been selected, don't need to fetch that subresource // when copying back to readback buffer @@ -3108,6 +3126,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, // create resolve texture vt->CreateImage(Unwrap(dev), &imCreateInfo, NULL, &tmpImage); + wrappedTmpImage = tmpImage; + GetResourceManager()->WrapResource(Unwrap(dev), wrappedTmpImage); + tmpImageState = ImageState(wrappedTmpImage, ImageInfo(imCreateInfo), eFrameRef_None); VkMemoryRequirements mrq = {0}; vt->GetImageMemoryRequirements(Unwrap(dev), tmpImage, &mrq); @@ -3133,43 +3154,27 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, imCreateInfo.extent, }; - m_pDriver->TempTransition(liveWrappedImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_ACCESS_TRANSFER_READ_BIT, setupBarriers, cleanupBarriers, - extQCleanup); - - VkImageMemoryBarrier dstimBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - 0, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - tmpImage, - {imageAspects, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, - }; - - // move tmp image into transfer destination layout as well - setupBarriers.push_back(dstimBarrier); - - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); + tmpImageState.InlineTransition( + cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, m_pDriver->GetImageTransitionInfo()); + ImageBarrierSequence setupBarriers, cleanupBarriers; + srcImageState->TempTransition(m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, setupBarriers, cleanupBarriers, + m_pDriver->GetImageTransitionInfo()); + m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); // resolve from live texture to resolve texture vt->CmdResolveImage(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmpImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &resolveRegion); - dstimBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstimBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - dstimBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - dstimBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + tmpImageState.InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, m_pDriver->GetImageTransitionInfo()); - // wait for resolve to finish before copy to buffer - cleanupBarriers.push_back(dstimBarrier); + m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - - if(extQCleanup) + if(!cleanupBarriers.empty()) { // ensure this resolve happens before handing back the source image to the original queue vkr = vt->EndCommandBuffer(Unwrap(cmd)); @@ -3178,10 +3183,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); - // don't do our dest image barrier on the external queue - cleanupBarriers.pop_back(); - - m_pDriver->SubmitExtQBarriers(~0U, cleanupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); // fetch a new command buffer for remaining work cmd = m_pDriver->GetNextCmd(); @@ -3189,9 +3191,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); } + srcImageState = &tmpImageState; srcImage = tmpImage; - srcQueueIndex = m_pDriver->GetQueueFamilyIndex(); // these have already been selected, don't need to fetch that subresource // when copying back to readback buffer @@ -3215,6 +3217,9 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, // create resolve texture vt->CreateImage(Unwrap(dev), &imCreateInfo, NULL, &tmpImage); + wrappedTmpImage = tmpImage; + GetResourceManager()->WrapResource(Unwrap(dev), wrappedTmpImage); + tmpImageState = ImageState(wrappedTmpImage, ImageInfo(imCreateInfo), eFrameRef_None); VkMemoryRequirements mrq = {0}; vt->GetImageMemoryRequirements(Unwrap(dev), tmpImage, &mrq); @@ -3230,26 +3235,15 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, vkr = vt->BindImageMemory(Unwrap(dev), tmpImage, tmpMemory, 0); RDCASSERTEQUAL(vkr, VK_SUCCESS); - m_pDriver->TempTransition(liveWrappedImage, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT, - setupBarriers, cleanupBarriers, extQCleanup); - - VkImageMemoryBarrier dstimBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - 0, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_GENERAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - tmpImage, - {imageAspects, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}, - }; - - // move tmp image into transfer destination layout - setupBarriers.push_back(dstimBarrier); - - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); + tmpImageState.InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_GENERAL, 0, + VK_ACCESS_SHADER_WRITE_BIT, m_pDriver->GetImageTransitionInfo()); + ImageBarrierSequence setupBarriers, cleanupBarriers; + srcImageState->TempTransition(m_pDriver->m_QueueFamilyIdx, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_SHADER_READ_BIT, setupBarriers, cleanupBarriers, + m_pDriver->GetImageTransitionInfo()); + m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); vkr = vt->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -3265,18 +3259,13 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); - // wait for copy to finish before copy to buffer - dstimBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - dstimBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - dstimBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - dstimBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + tmpImageState.InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_SHADER_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, m_pDriver->GetImageTransitionInfo()); - // wait for work to finish before copy to buffer - cleanupBarriers.push_back(dstimBarrier); + m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - - if(extQCleanup) + if(!cleanupBarriers.empty()) { // ensure this resolve happens before handing back the source image to the original queue vkr = vt->EndCommandBuffer(Unwrap(cmd)); @@ -3285,10 +3274,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); - // don't do our dest image barrier on the external queue - cleanupBarriers.pop_back(); - - m_pDriver->SubmitExtQBarriers(~0U, cleanupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); // fetch a new command buffer for remaining work cmd = m_pDriver->GetNextCmd(); @@ -3298,27 +3284,22 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, } srcImage = tmpImage; - srcQueueIndex = m_pDriver->GetQueueFamilyIndex(); - + srcImageState = &tmpImageState; s.slice = s.slice * numSamples + s.sample; s.sample = 0; } + ImageBarrierSequence cleanupBarriers; + // if we have no tmpImage, we're copying directly from the real image if(tmpImage == VK_NULL_HANDLE) { - m_pDriver->TempTransition(liveWrappedImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_ACCESS_TRANSFER_READ_BIT, setupBarriers, cleanupBarriers, - extQCleanup); - - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); - } - else - { - // no more setup/cleanup to do, we read from the real image above - extQCleanup = false; - setupBarriers.clear(); - cleanupBarriers.clear(); + ImageBarrierSequence setupBarriers; + srcImageState->TempTransition(m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, setupBarriers, cleanupBarriers, + m_pDriver->GetImageTransitionInfo()); + m_pDriver->InlineSetupImageBarriers(cmd, setupBarriers); + m_pDriver->SubmitAndFlushImageStateBarriers(setupBarriers); } VkImageAspectFlags copyAspects = VK_IMAGE_ASPECT_COLOR_BIT; @@ -3435,6 +3416,30 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, readbackBuf, 1, copyregion); } + // if we have no tmpImage, we're copying directly from the real image + if(tmpImage == VK_NULL_HANDLE) + { + m_pDriver->InlineCleanupImageBarriers(cmd, cleanupBarriers); + + if(!cleanupBarriers.empty()) + { + // ensure this resolve happens before handing back the source image to the original queue + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + m_pDriver->SubmitAndFlushImageStateBarriers(cleanupBarriers); + + // fetch a new command buffer for remaining work + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + } + VkBufferMemoryBarrier bufBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, NULL, @@ -3447,10 +3452,6 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, dataSize, }; - // do any cleanup needed - if(!cleanupBarriers.empty()) - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); - // wait for copy to finish before reading back to host DoPipelineBarrier(cmd, 1, &bufBarrier); @@ -3459,9 +3460,6 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); - if(extQCleanup) - m_pDriver->SubmitExtQBarriers(~0U, cleanupBarriers); - // map the buffer and copy to return buffer byte *pData = NULL; vkr = vt->MapMemory(Unwrap(dev), readbackMem, 0, VK_WHOLE_SIZE, 0, (void **)&pData); @@ -3577,6 +3575,7 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, if(tmpImage != VK_NULL_HANDLE) { + GetResourceManager()->ReleaseWrappedResource(wrappedTmpImage, true); vt->DestroyImage(Unwrap(dev), tmpImage, NULL); vt->FreeMemory(Unwrap(dev), tmpMemory, NULL); } @@ -3658,7 +3657,16 @@ ResourceId VulkanReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, &clearval, }; - RenderTextureInternal(disp, rpbegin, eTexDisplay_MipShift); + LockedConstImageStateRef imageState = m_pDriver->FindConstImageState(texid); + if(!imageState) + { + RDCWARN("Could not find image info for image %s", ToStr(texid).c_str()); + return ResourceId(); + } + if(!imageState->isMemoryBound) + return ResourceId(); + + RenderTextureInternal(disp, *imageState, rpbegin, eTexDisplay_MipShift); m_DebugWidth = oldW; m_DebugHeight = oldH; diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 6e3e1860a..d9b9a2620 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -426,7 +426,8 @@ private: void RefreshDerivedReplacements(); - bool RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginInfo rpbegin, int flags); + bool RenderTextureInternal(TextureDisplay cfg, const ImageState &imageState, + VkRenderPassBeginInfo rpbegin, int flags); bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, bool stencil, float *minval, float *maxval); diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 991bb812a..70caef7b3 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -453,7 +453,7 @@ bool WrappedVulkan::Serialise_vkCreateCommandPool(SerialiserType &ser, VkDevice // remap the queue family index CreateInfo.queueFamilyIndex = m_QueueRemapping[CreateInfo.queueFamilyIndex][0].family; - m_commandQueueFamilies[CmdPool] = CreateInfo.queueFamilyIndex; + InsertCommandQueueFamily(CmdPool, CreateInfo.queueFamilyIndex); VkResult ret = ObjDisp(device)->CreateCommandPool(Unwrap(device), &CreateInfo, NULL, &pool); @@ -466,7 +466,7 @@ bool WrappedVulkan::Serialise_vkCreateCommandPool(SerialiserType &ser, VkDevice { ResourceId live = GetResourceManager()->WrapResource(Unwrap(device), pool); GetResourceManager()->AddLiveResource(CmdPool, pool); - m_commandQueueFamilies[live] = CreateInfo.queueFamilyIndex; + InsertCommandQueueFamily(live, CreateInfo.queueFamilyIndex); } AddResource(CmdPool, ResourceType::Pool, "Command Pool"); @@ -561,13 +561,18 @@ bool WrappedVulkan::Serialise_vkAllocateCommandBuffers(SerialiserType &ser, VkDe { ResourceId live = GetResourceManager()->WrapResource(Unwrap(device), cmd); GetResourceManager()->AddLiveResource(CommandBuffer, cmd); - - m_commandQueueFamilies[live] = m_commandQueueFamilies[GetResID(AllocateInfo.commandPool)]; + auto cmdQueueFamilyIt = m_commandQueueFamilies.find(GetResID(AllocateInfo.commandPool)); + if(cmdQueueFamilyIt == m_commandQueueFamilies.end()) + { + RDCERR("Missing queue family for %s", ToStr(GetResID(AllocateInfo.commandPool)).c_str()); + } + else + { + InsertCommandQueueFamily(CommandBuffer, cmdQueueFamilyIt->second); + InsertCommandQueueFamily(live, cmdQueueFamilyIt->second); + } } - m_commandQueueFamilies[CommandBuffer] = - m_commandQueueFamilies[GetResID(AllocateInfo.commandPool)]; - AddResource(CommandBuffer, ResourceType::CommandBuffer, "Command Buffer"); DerivedResource(device, CommandBuffer); DerivedResource(AllocateInfo.commandPool, CommandBuffer); @@ -695,6 +700,16 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman if(IsReplayingAndReading()) { + auto cmdQueueFamilyIt = m_commandQueueFamilies.find(CommandBuffer); + if(cmdQueueFamilyIt == m_commandQueueFamilies.end()) + { + RDCERR("Unknown queue family for %s", ToStr(CommandBuffer).c_str()); + } + else + { + InsertCommandQueueFamily(BakedCommandBuffer, cmdQueueFamilyIt->second); + } + m_LastCmdBufferID = CommandBuffer; // when loading, allocate a new resource ID for each push descriptor slot in this command buffer @@ -827,6 +842,7 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman // there's no issue with clashes here. m_RerecordCmds[BakedCommandBuffer] = cmd; m_RerecordCmds[m_LastCmdBufferID] = cmd; + InsertCommandQueueFamily(GetResID(cmd), FindCommandQueueFamily(m_LastCmdBufferID)); m_RerecordCmdList.push_back({AllocateInfo.commandPool, cmd}); @@ -921,6 +937,8 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman } ObjDisp(device)->BeginCommandBuffer(Unwrap(cmd), &unwrappedBeginInfo); + InsertCommandQueueFamily(GetResourceManager()->GetLiveID(BakedCommandBuffer), + FindCommandQueueFamily(BakedCommandBuffer)); } } @@ -1050,7 +1068,7 @@ bool WrappedVulkan::Serialise_vkEndCommandBuffer(SerialiserType &ser, VkCommandB // subpass uint32_t &sub = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass; - rdcarray > imgbarriers; + std::map renderPassEndStates; for(sub = m_RenderState.subpass + 1; sub < numSubpasses; sub++) { @@ -1059,51 +1077,43 @@ bool WrappedVulkan::Serialise_vkEndCommandBuffer(SerialiserType &ser, VkCommandB rdcarray subpassBarriers = GetImplicitRenderPassBarriers(); GetResourceManager()->RecordBarriers( - imgbarriers, m_ImageLayouts, (uint32_t)subpassBarriers.size(), &subpassBarriers[0]); + renderPassEndStates, FindCommandQueueFamily(m_LastCmdBufferID), + (uint32_t)subpassBarriers.size(), subpassBarriers.data()); } rdcarray finalBarriers = GetImplicitRenderPassBarriers(~0U); - GetResourceManager()->RecordBarriers(imgbarriers, m_ImageLayouts, - (uint32_t)finalBarriers.size(), &finalBarriers[0]); + GetResourceManager()->RecordBarriers(renderPassEndStates, + FindCommandQueueFamily(m_LastCmdBufferID), + (uint32_t)finalBarriers.size(), finalBarriers.data()); 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. - rdcarray revertBarriers; - for(auto it = imgbarriers.begin(); it != imgbarriers.end(); ++it) + for(auto it = renderPassEndStates.begin(); it != renderPassEndStates.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 && - barrier.newLayout != VK_IMAGE_LAYOUT_UNDEFINED) + ResourceId id = it->first; + ImageState &endState = it->second; + LockedConstImageStateRef current = FindConstImageState(id); + if(!current) { - SanitiseOldImageLayout(barrier.oldLayout); - SanitiseNewImageLayout(barrier.newLayout); - - revertBarriers.push_back(barrier); + RDCERR("Unknown image %s", ToStr(id).c_str()); + } + else + { + ImageBarrierSequence barriers; + endState.Transition(*current, VK_ACCESS_ALL_WRITE_BITS, VK_ACCESS_ALL_READ_BITS, + barriers, GetImageTransitionInfo()); + InlineCleanupImageBarriers(commandBuffer, barriers); + if(!barriers.empty()) + { + // This should not happen, because the cleanup barriers are just image layout + // transitions, no queue family transitions + RDCERR("Partial RenderPass replay cleanup barriers could not all be inlined"); + } } - } - - if(!revertBarriers.empty()) - { - if(SeparateDepthStencil()) - CombineDepthStencilLayouts(revertBarriers); - - DoPipelineBarrier(commandBuffer, revertBarriers.size(), revertBarriers.data()); } } @@ -1327,12 +1337,12 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman } ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); if(m_FirstEventID == m_LastEventID) - GetResourceManager()->ApplyBarriers( - m_QueueFamilyIdx, m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts); + UpdateImageStates(m_BakedCmdBufferInfo[cmd].imageStates); } } else @@ -1389,7 +1399,8 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman rdcarray imgBarriers = GetImplicitRenderPassBarriers(); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); AddEvent(); @@ -1529,7 +1540,8 @@ bool WrappedVulkan::Serialise_vkCmdNextSubpass(SerialiserType &ser, VkCommandBuf rdcarray imgBarriers = GetImplicitRenderPassBarriers(); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); } } @@ -1545,7 +1557,8 @@ bool WrappedVulkan::Serialise_vkCmdNextSubpass(SerialiserType &ser, VkCommandBuf rdcarray imgBarriers = GetImplicitRenderPassBarriers(); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); AddEvent(); @@ -1623,7 +1636,8 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(SerialiserType &ser, VkCommandB } ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); } } @@ -1641,7 +1655,8 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(SerialiserType &ser, VkCommandB rdcarray imgBarriers = GetImplicitRenderPassBarriers(~0U); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); AddImplicitResolveResourceUsage(~0U); @@ -1801,12 +1816,12 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass2(SerialiserType &ser, } ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); if(m_FirstEventID == m_LastEventID) - GetResourceManager()->ApplyBarriers( - m_QueueFamilyIdx, m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts); + UpdateImageStates(m_BakedCmdBufferInfo[cmd].imageStates); } } else @@ -1864,7 +1879,8 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass2(SerialiserType &ser, rdcarray imgBarriers = GetImplicitRenderPassBarriers(); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); AddEvent(); @@ -2021,7 +2037,8 @@ bool WrappedVulkan::Serialise_vkCmdNextSubpass2(SerialiserType &ser, VkCommandBu rdcarray imgBarriers = GetImplicitRenderPassBarriers(); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); } } @@ -2038,7 +2055,8 @@ bool WrappedVulkan::Serialise_vkCmdNextSubpass2(SerialiserType &ser, VkCommandBu rdcarray imgBarriers = GetImplicitRenderPassBarriers(); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); AddEvent(); @@ -2135,7 +2153,8 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass2(SerialiserType &ser, VkCommand } ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); } } @@ -2146,7 +2165,8 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass2(SerialiserType &ser, VkCommand rdcarray imgBarriers = GetImplicitRenderPassBarriers(~0U); ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); AddEvent(); @@ -2962,14 +2982,25 @@ bool WrappedVulkan::Serialise_vkCmdPipelineBarrier( if(commandBuffer != VK_NULL_HANDLE) { ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + FindCommandQueueFamily(m_LastCmdBufferID), (uint32_t)imgBarriers.size(), imgBarriers.data()); // now sanitise layouts before passing to vulkan for(VkImageMemoryBarrier &barrier : imgBarriers) { - SanitiseOldImageLayout(barrier.oldLayout); - SanitiseNewImageLayout(barrier.newLayout); + if(!IsLoading(m_State) && barrier.oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) + { + // This is a transition from PRENITIALIZED, but we've already done this barrier once (when + // loading); Since we couldn't transition back to PREINITIALIZED, we instead left the + // image in GENERAL. + barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + } + else + { + SanitiseReplayImageLayout(barrier.oldLayout); + } + SanitiseReplayImageLayout(barrier.newLayout); } ObjDisp(commandBuffer) @@ -3372,9 +3403,9 @@ bool WrappedVulkan::Serialise_vkCmdExecuteCommands(SerialiserType &ser, VkComman // merge barriers into parent command buffer for(uint32_t i = 0; i < commandBufferCount; i++) { - GetResourceManager()->MergeBarriers( - m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers, - m_BakedCmdBufferInfo[GetResID(pCommandBuffers[i])].imgbarriers); + ImageState::Merge(m_BakedCmdBufferInfo[GetResID(commandBuffer)].imageStates, + m_BakedCmdBufferInfo[GetResID(pCommandBuffers[i])].imageStates, + GetImageTransitionInfo()); } // append deferred indirect copies @@ -3588,9 +3619,8 @@ bool WrappedVulkan::Serialise_vkCmdExecuteCommands(SerialiserType &ser, VkComman #endif rerecordedCmds.push_back(Unwrap(cmd)); - GetResourceManager()->MergeBarriers( - m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers, - m_BakedCmdBufferInfo[rerecord].imgbarriers); + ImageState::Merge(m_BakedCmdBufferInfo[GetResID(commandBuffer)].imageStates, + m_BakedCmdBufferInfo[rerecord].imageStates, GetImageTransitionInfo()); } else { diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index 0eafd3eb9..73bb0c91f 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -268,9 +268,7 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(SerialiserType &ser, VkQueue queue, BakedCmdBufferInfo &cmdBufInfo = m_BakedCmdBufferInfo[cmd]; - GetResourceManager()->ApplyBarriers(m_CreationInfo.m_Queue[GetResID(queue)], - m_BakedCmdBufferInfo[liveCmd].imgbarriers, - m_ImageLayouts); + UpdateImageStates(m_BakedCmdBufferInfo[liveCmd].imageStates); rdcstr name = StringFormat::Fmt("=> %s[%u]: vkBeginCommandBuffer(%s)", basename.c_str(), c, ToStr(cmd).c_str()); @@ -400,9 +398,7 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(SerialiserType &ser, VkQueue queue, #endif rerecordedCmds.push_back(Unwrap(cmd)); - GetResourceManager()->ApplyBarriers(m_CreationInfo.m_Queue[GetResID(queue)], - m_BakedCmdBufferInfo[rerecord].imgbarriers, - m_ImageLayouts); + UpdateImageStates(m_BakedCmdBufferInfo[rerecord].imageStates); } else { diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index 0a6727f11..b603f3618 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -1011,11 +1011,20 @@ bool WrappedVulkan::Serialise_vkBindImageMemory(SerialiserType &ser, VkDevice de ObjDisp(device)->BindImageMemory(Unwrap(device), Unwrap(image), Unwrap(memory), memoryOffset); - ImageLayouts &layout = m_ImageLayouts[GetResID(image)]; - layout.isMemoryBound = true; - layout.boundMemory = GetResID(memory); - layout.boundMemoryOffset = memoryOffset; - layout.boundMemorySize = mrq.size; + { + LockedImageStateRef state = FindImageState(GetResID(image)); + if(!state) + { + RDCERR("Binding memory for unknown image %s", ToStr(GetResID(image)).c_str()); + } + else + { + state->isMemoryBound = true; + state->boundMemory = GetResID(memory); + state->boundMemoryOffset = memoryOffset; + state->boundMemorySize = mrq.size; + } + } GetResourceDesc(memOrigId).derivedResources.push_back(resOrigId); GetResourceDesc(resOrigId).parentResources.push_back(memOrigId); @@ -1071,7 +1080,13 @@ VkResult WrappedVulkan::vkBindImageMemory(VkDevice device, VkImage image, VkDevi } else { - m_ImageLayouts[GetResID(image)].isMemoryBound = true; + { + LockedImageStateRef state = FindImageState(GetResID(image)); + if(!state) + RDCERR("Binding memory to unknown image %s", ToStr(GetResID(image)).c_str()); + else + state->isMemoryBound = true; + } } return ret; @@ -1551,39 +1566,13 @@ bool WrappedVulkan::Serialise_vkCreateImage(SerialiserType &ser, VkDevice device m_CreationInfo.m_Image[live].Init(GetResourceManager(), m_CreationInfo, &CreateInfo); - VkImageSubresourceRange range; - range.baseMipLevel = range.baseArrayLayer = 0; - range.levelCount = CreateInfo.mipLevels; - range.layerCount = CreateInfo.arrayLayers; - - ImageLayouts &layouts = m_ImageLayouts[live]; - layouts.imageInfo = ImageInfo(CreateInfo); - - layouts.subresourceStates.clear(); - - layouts.initialLayout = CreateInfo.initialLayout; - - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - if(IsDepthOnlyFormat(CreateInfo.format)) - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if(IsStencilOnlyFormat(CreateInfo.format)) - range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - else if(IsDepthOrStencilFormat(CreateInfo.format)) - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - // if we don't support separate depth/stencil, track both aspects together - if(!SeparateDepthStencil() && IsDepthAndStencilFormat(CreateInfo.format)) - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - - layouts.subresourceStates.push_back(ImageRegionState( - VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, CreateInfo.initialLayout)); - - // if we do support separate depth stencil, add a separate stencil aspect tracker - if(SeparateDepthStencil() && IsDepthAndStencilFormat(CreateInfo.format)) + bool inserted = false; + auto state = InsertImageState(img, live, CreateInfo, eFrameRef_Unknown, &inserted); + if(!inserted) { - range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - layouts.subresourceStates.push_back(ImageRegionState( - VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, CreateInfo.initialLayout)); + // Image state already existed. + state->wrappedHandle = img; + *state = state->InitialState(); } } @@ -2121,11 +2110,21 @@ bool WrappedVulkan::Serialise_vkBindImageMemory2(SerialiserType &ser, VkDevice d if(!ok) return false; - ImageLayouts &imageLayouts = m_ImageLayouts[GetResID(bindInfo.image)]; - imageLayouts.isMemoryBound = true; - imageLayouts.boundMemory = GetResID(bindInfo.memory); - imageLayouts.boundMemoryOffset = bindInfo.memoryOffset; - imageLayouts.boundMemorySize = mrq.size; + { + ResourceId id = GetResID(bindInfo.image); + LockedImageStateRef state = FindImageState(id); + if(!state) + { + RDCERR("Binding memory for unknown image %s", ToStr(id).c_str()); + } + else + { + state->isMemoryBound = true; + state->boundMemory = GetResID(bindInfo.memory); + state->boundMemoryOffset = bindInfo.memoryOffset; + state->boundMemorySize = mrq.size; + } + } GetResourceDesc(memOrigId).derivedResources.push_back(resOrigId); GetResourceDesc(resOrigId).parentResources.push_back(memOrigId); @@ -2193,7 +2192,13 @@ VkResult WrappedVulkan::vkBindImageMemory2(VkDevice device, uint32_t bindInfoCou else { for(uint32_t i = 0; i < bindInfoCount; i++) - m_ImageLayouts[GetResID(pBindInfos[i].image)].isMemoryBound = true; + { + LockedImageStateRef state = FindImageState(GetResID(pBindInfos[i].image)); + if(!state) + state->isMemoryBound = true; + else + RDCERR("Binding memory to unknown image %s", ToStr(GetResID(pBindInfos[i].image)).c_str()); + } } return ret; diff --git a/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp index 5a18525d4..fe35aa570 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp @@ -841,8 +841,9 @@ bool WrappedVulkan::Serialise_vkCmdWaitEvents( } ResourceId cmd = GetResID(commandBuffer); - GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, - (uint32_t)imgBarriers.size(), &imgBarriers[0]); + GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imageStates, + m_commandQueueFamilies[cmd], (uint32_t)imgBarriers.size(), + &imgBarriers[0]); if(commandBuffer != VK_NULL_HANDLE) { diff --git a/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp index ef39a2d86..69cac9e93 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp @@ -441,22 +441,11 @@ bool WrappedVulkan::Serialise_vkCreateSwapchainKHR(SerialiserType &ser, VkDevice m_CreationInfo.m_Names[liveId] = StringFormat::Fmt("Presentable Image %u", i); - VkImageSubresourceRange range; - range.baseMipLevel = range.baseArrayLayer = 0; - range.levelCount = 1; - range.layerCount = CreateInfo.imageArrayLayers; - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - ImageLayouts &layouts = m_ImageLayouts[liveId]; - - layouts.imageInfo = swapinfo.imageInfo; - - layouts.isMemoryBound = true; - layouts.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - layouts.subresourceStates.clear(); - layouts.subresourceStates.push_back(ImageRegionState( - VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED)); + { + LockedImageStateRef state = + InsertImageState(im, liveId, ImageInfo(swapinfo.imageInfo), eFrameRef_Unknown); + state->isMemoryBound = true; + } } }