diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 1b18324b2..d3dfa70f3 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -1599,110 +1599,10 @@ void WrappedVulkan::FirstFrame() template bool WrappedVulkan::Serialise_BeginCaptureFrame(SerialiserType &ser) { - rdcarray imgBarriers; - - { - SCOPED_LOCK(m_ImageLayoutsLock); // not needed on replay, but harmless also - GetResourceManager()->SerialiseImageStates(ser, m_ImageLayouts, imgBarriers); - } - + SCOPED_LOCK(m_ImageStatesLock); + GetResourceManager()->SerialiseImageStates(ser, m_ImageStates); SERIALISE_CHECK_READ_ERRORS(); - if(IsReplayingAndReading()) - { - VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - - if(IsLoading(m_State)) - { - // for the first load, promote any PREINITIALIZED images to GENERAL here since we treat - // PREINIT as if it was GENERAL. - for(auto it = m_ImageLayouts.begin(); it != m_ImageLayouts.end(); ++it) - { - if(!it->second.isMemoryBound) - continue; - - for(auto stit = it->second.subresourceStates.begin(); - stit != it->second.subresourceStates.end(); ++stit) - { - if(stit->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && - GetResourceManager()->HasCurrentResource(it->first)) - { - VkImage img = GetResourceManager()->GetCurrentHandle(it->first); - - { - VkImageMemoryBarrier barrier = {}; - - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; - barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - barrier.srcQueueFamilyIndex = m_QueueFamilyIdx; - barrier.dstQueueFamilyIndex = m_QueueFamilyIdx; - barrier.image = Unwrap(img); - barrier.subresourceRange = stit->subresourceRange; - - imgBarriers.push_back(barrier); - } - } - } - } - } - - if(!imgBarriers.empty()) - { - VkMarkerRegion region("Frame-start barriers"); - - for(size_t i = 0; i < imgBarriers.size(); i++) - { - // sanitise the layouts before passing to Vulkan - if(!IsLoading(m_State)) - SanitiseOldImageLayout(imgBarriers[i].oldLayout); - SanitiseNewImageLayout(imgBarriers[i].newLayout); - - imgBarriers[i].srcAccessMask = MakeAccessMask(imgBarriers[i].oldLayout); - imgBarriers[i].dstAccessMask = MakeAccessMask(imgBarriers[i].newLayout); - } - - if(SeparateDepthStencil()) - CombineDepthStencilLayouts(imgBarriers); - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - -#if ENABLED(SINGLE_FLUSH_VALIDATE) - for(size_t i = 0; i < imgBarriers.size(); i++) - { - VkCommandBuffer cmd = GetNextCmd(); - - VkResult vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), src_stages, dest_stages, false, 0, NULL, 0, - NULL, 1, &imgBarriers[i]); - - vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - SubmitCmds(); - } -#else - VkCommandBuffer cmd = GetNextCmd(); - - VkResult vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), src_stages, dest_stages, false, 0, NULL, 0, - NULL, (uint32_t)imgBarriers.size(), &imgBarriers[0]); - - vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - SubmitCmds(); -#endif - } - // don't need to flush here - } - return true; } @@ -1762,20 +1662,19 @@ void WrappedVulkan::StartFrameCapture(void *dev, void *wnd) } GetResourceManager()->PrepareInitialContents(); + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); + SubmitCmds(); + FlushQ(); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); RDCDEBUG("Attempting capture"); m_FrameCaptureRecord->DeleteChunks(); - { - CACHE_THREAD_SERIALISER(); - - SCOPED_SERIALISE_CHUNK(SystemChunk::CaptureBegin); - - Serialise_BeginCaptureFrame(ser); - - // need to hold onto this as it must come right after the capture chunk, - // before any command buffers - m_HeaderChunk = scope.Get(); + SCOPED_LOCK(m_ImageStatesLock); + for(auto it = m_ImageStates.begin(); it != m_ImageStates.end(); ++it) + { + it->second.LockWrite()->BeginCapture(); + } } m_State = CaptureState::ActiveCapturing; @@ -2129,7 +2028,6 @@ bool WrappedVulkan::EndFrameCapture(void *dev, void *wnd) GetResourceManager()->Serialise_InitialContentsNeeded(ser); GetResourceManager()->InsertDeviceMemoryRefs(ser); - GetResourceManager()->InsertImageRefs(ser); { SCOPED_SERIALISE_CHUNK(SystemChunk::CaptureScope, 16); @@ -2137,6 +2035,14 @@ bool WrappedVulkan::EndFrameCapture(void *dev, void *wnd) Serialise_CaptureScope(ser); } + { + WriteSerialiser &captureBeginSer = GetThreadSerialiser(); + ScopedChunk scope(captureBeginSer, SystemChunk::CaptureBegin); + + Serialise_BeginCaptureFrame(captureBeginSer); + + m_HeaderChunk = scope.Get(); + } m_HeaderChunk->Write(ser); // don't need to lock access to m_CmdBufferRecords as we are no longer @@ -3128,8 +3034,8 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) return Serialise_vkCmdSetLineStippleEXT(ser, VK_NULL_HANDLE, 0, 0); case VulkanChunk::ImageRefs: { - rdcarray data; - return GetResourceManager()->Serialise_ImageRefs(ser, data); + SCOPED_LOCK(m_ImageStatesLock); + return GetResourceManager()->Serialise_ImageRefs(ser, m_ImageStates); } case VulkanChunk::vkGetSemaphoreCounterValue: return Serialise_vkGetSemaphoreCounterValue(ser, VK_NULL_HANDLE, VK_NULL_HANDLE, NULL); @@ -4191,6 +4097,87 @@ void WrappedVulkan::InsertCommandQueueFamily(ResourceId cmdId, uint32_t queueFam { m_commandQueueFamilies[cmdId] = queueFamilyIndex; } +LockedImageStateRef WrappedVulkan::FindImageState(ResourceId id) +{ + SCOPED_LOCK(m_ImageStatesLock); + auto it = m_ImageStates.find(id); + if(it != m_ImageStates.end()) + return it->second.LockWrite(); + else + return LockedImageStateRef(); +} + +LockedConstImageStateRef WrappedVulkan::FindConstImageState(ResourceId id) +{ + SCOPED_LOCK(m_ImageStatesLock); + auto it = m_ImageStates.find(id); + if(it != m_ImageStates.end()) + return it->second.LockRead(); + else + return LockedConstImageStateRef(); +} + +LockedImageStateRef WrappedVulkan::InsertImageState(VkImage wrappedHandle, ResourceId id, + const ImageInfo &info, FrameRefType refType, + bool *inserted) +{ + SCOPED_LOCK(m_ImageStatesLock); + auto it = m_ImageStates.find(id); + if(it != m_ImageStates.end()) + { + if(inserted != NULL) + *inserted = false; + return it->second.LockWrite(); + } + else + { + if(inserted != NULL) + *inserted = true; + it = m_ImageStates.insert({id, LockingImageState(wrappedHandle, info, refType)}).first; + return it->second.LockWrite(); + } +} + +bool WrappedVulkan::EraseImageState(ResourceId id) +{ + SCOPED_LOCK(m_ImageStatesLock); + auto it = m_ImageStates.find(id); + if(it != m_ImageStates.end()) + { + m_ImageStates.erase(it); + return true; + } + return false; +} + +void WrappedVulkan::UpdateImageStates(const std::map &dstStates) +{ + SCOPED_LOCK(m_ImageStatesLock); + auto it = m_ImageStates.begin(); + auto dstIt = dstStates.begin(); + ImageTransitionInfo info = GetImageTransitionInfo(); + while(dstIt != dstStates.end()) + { + if(it == m_ImageStates.end() || dstIt->first < it->first) + { + it = m_ImageStates + .insert({dstIt->first, + LockingImageState(dstIt->second.wrappedHandle, dstIt->second.GetImageInfo(), + info.GetDefaultRefType())}) + .first; + dstIt->second.InitialState(*it->second.LockWrite()); + } + else if(it->first < dstIt->first) + { + ++it; + continue; + } + + it->second.LockWrite()->Merge(dstIt->second, info); + ++dstIt; + ++it; + } +} #if ENABLED(ENABLE_UNIT_TESTS) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 24fd462fb..4b3c912f6 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -422,6 +422,9 @@ private: rdcarray m_QueueFamilyCounts; rdcarray m_QueueFamilyIndices; + ImageBarrierSequence m_setupImageBarriers; + ImageBarrierSequence m_cleanupImageBarriers; + // a small amount of helper code during capture for handling resources on different queues in init // states struct ExternalQueue @@ -573,6 +576,7 @@ private: uint32_t subpass = 0; } state; + std::map imageStates; rdcarray> imgbarriers; ResourceId pushDescriptorID[2][64]; @@ -754,8 +758,11 @@ private: // used on replay side to track the queue family of command buffers and pools std::map m_commandQueueFamilies; - // used both on capture and replay side to track image layouts. Only locked + // used both on capture and replay side to track image state. Only locked // in capture + std::map m_ImageStates; + Threading::CriticalSection m_ImageStatesLock; + std::map m_ImageLayouts; Threading::CriticalSection m_ImageLayoutsLock; @@ -1052,6 +1059,18 @@ public: VkDriverInfo GetDriverInfo() { return m_PhysicalDeviceData.driverInfo; } uint32_t FindCommandQueueFamily(ResourceId cmdId); void InsertCommandQueueFamily(ResourceId cmdId, uint32_t queueFamilyIndex); + LockedImageStateRef FindImageState(ResourceId id); + LockedConstImageStateRef FindConstImageState(ResourceId id); + LockedImageStateRef InsertImageState(VkImage wrappedHandle, ResourceId id, const ImageInfo &info, + FrameRefType refType, bool *inserted = NULL); + bool EraseImageState(ResourceId id); + void UpdateImageStates(const std::map &dstStates); + + inline ImageTransitionInfo GetImageTransitionInfo() const + { + return ImageTransitionInfo(m_State, m_QueueFamilyIdx); + } + // Device initialization IMPLEMENT_FUNCTION_SERIALISED(VkResult, vkCreateInstance, const VkInstanceCreateInfo *pCreateInfo, diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index d70abf69c..6bff5593e 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -94,9 +94,6 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) const ResourceInfo &resInfo = *im->record->resInfo; const ImageInfo &imageInfo = resInfo.imageInfo; - if(!GetResourceManager()->FindImgRefs(id)) - GetResourceManager()->AddImageFrameRefs(id, imageInfo); - if(resInfo.IsSparse()) { // if the image is sparse we have to do a different kind of initial state prepare, @@ -104,24 +101,23 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) return Prepare_SparseInitialState((WrappedVkImage *)res); } - ImageLayouts *layout = NULL; - { - SCOPED_LOCK(m_ImageLayoutsLock); - layout = &m_ImageLayouts[im->id]; - } - - if(layout->queueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL || - layout->queueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT) - { - RDCWARN("Image %s in external/foreign queue family, initial contents impossible to fetch.", - ToStr(im->id).c_str()); - return true; - } + LockedImageStateRef state = FindImageState(im->id); // if the image has no memory bound, nothing is to be fetched - if(!layout->isMemoryBound) + if(!state || !state->isMemoryBound) return true; + for(auto it = state->subresourceStates.begin(); it != state->subresourceStates.end(); ++it) + { + if(it->state().newQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT || + it->state().newQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL) + { + // This image has a subresource owned by an external/foreign queue family, so we can't fetch + // the initial contents. + return true; + } + } + VkDevice d = GetDev(); // INITSTATEBATCH VkCommandBuffer cmd = GetNextCmd(); @@ -274,18 +270,17 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) VkImageAspectFlags aspectFlags = FormatImageAspects(imageInfo.format); - rdcarray setupBarriers, cleanupBarriers; - bool extQCleanup = false; + ImageBarrierSequence setupBarriers, cleanupBarriers; VkImageLayout readingLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; if(arrayIm != VK_NULL_HANDLE) readingLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - TempTransition(ToWrappedHandle(res), readingLayout, - VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT, setupBarriers, - cleanupBarriers, extQCleanup); - DoPipelineBarrier(cmd, setupBarriers.size(), setupBarriers.data()); - + state->TempTransition(m_QueueFamilyIdx, readingLayout, + VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT, setupBarriers, + cleanupBarriers, GetImageTransitionInfo()); + InlineSetupImageBarriers(cmd, setupBarriers); + m_setupImageBarriers.Merge(setupBarriers); if(arrayIm != VK_NULL_HANDLE) { VkImageMemoryBarrier arrayimBarrier = { @@ -414,18 +409,16 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) RDCASSERTMSG("buffer wasn't sized sufficiently!", bufOffset <= bufInfo.size, bufOffset, readbackmem.size, imageInfo.extent, imageInfo.format, numLayers, imageInfo.levelCount); - - DoPipelineBarrier(cmd, cleanupBarriers.size(), cleanupBarriers.data()); + InlineCleanupImageBarriers(cmd, cleanupBarriers); + m_cleanupImageBarriers.Merge(cleanupBarriers); vkr = ObjDisp(d)->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); - // INITSTATEBATCH + SubmitAndFlushImageStateBarriers(m_setupImageBarriers); SubmitCmds(); FlushQ(); - - if(extQCleanup) - SubmitExtQBarriers(~0U, cleanupBarriers); + SubmitAndFlushImageStateBarriers(m_cleanupImageBarriers); ObjDisp(d)->DestroyBuffer(Unwrap(d), Unwrap(dstBuf), NULL); GetResourceManager()->ReleaseWrappedResource(dstBuf); @@ -1217,7 +1210,7 @@ void WrappedVulkan::Create_InitialState(ResourceId id, WrappedVkRes *live, bool if(m_ImageLayouts.find(liveid) == m_ImageLayouts.end()) { - RDCERR("Couldn't find image info for %s", ToStr(id).c_str()); + RDCERR("Couldn't find image info for %llu", id); GetResourceManager()->SetInitialContents( id, VkInitialContents(type, VkInitialContents::ClearColorImage)); return; diff --git a/renderdoc/driver/vulkan/vk_manager.cpp b/renderdoc/driver/vulkan/vk_manager.cpp index 071f4427d..6385ee152 100644 --- a/renderdoc/driver/vulkan/vk_manager.cpp +++ b/renderdoc/driver/vulkan/vk_manager.cpp @@ -33,60 +33,6 @@ #define TRDBG(...) #endif -static void AddAndMerge(rdcarray &barriers, - rdcarray> &states, - const VkImageMemoryBarrier &newBarrier, - const rdcpair &newState) -{ - bool add_new = true; - - // see if we can combine our incoming barrier into the last one by expanding the - // subresource range. Note we iterate over array layers first, then mips. - if(!barriers.empty() && barriers.back().oldLayout == newBarrier.oldLayout && - barriers.back().newLayout == newBarrier.newLayout) - { - // if it's the same array layer and we're the next mip on, combine - if(barriers.back().subresourceRange.aspectMask == newBarrier.subresourceRange.aspectMask && - barriers.back().subresourceRange.baseArrayLayer == newBarrier.subresourceRange.baseArrayLayer && - barriers.back().subresourceRange.layerCount == newBarrier.subresourceRange.layerCount && - barriers.back().subresourceRange.baseMipLevel + barriers.back().subresourceRange.levelCount == - newBarrier.subresourceRange.baseMipLevel) - { - barriers.back().subresourceRange.levelCount += newBarrier.subresourceRange.levelCount; - states.back().second.subresourceRange.levelCount += newBarrier.subresourceRange.levelCount; - add_new = false; - } - } - - if(add_new) - { - barriers.push_back(newBarrier); - states.push_back(newState); - } - - // we might have added the last mip(s) in an array layer, allowing us to combine with - // the previous array layer. Check for that - if(barriers.size() >= 2) - { - VkImageMemoryBarrier &a = barriers[barriers.size() - 2]; - VkImageMemoryBarrier &b = barriers[barriers.size() - 1]; - - // if the mips are identical and we're the next array layer on, combine - if(a.oldLayout == b.oldLayout && a.newLayout == b.newLayout && - a.subresourceRange.aspectMask == b.subresourceRange.aspectMask && - a.subresourceRange.baseMipLevel == b.subresourceRange.baseMipLevel && - a.subresourceRange.levelCount == b.subresourceRange.levelCount && - a.subresourceRange.baseArrayLayer + a.subresourceRange.layerCount == - b.subresourceRange.baseArrayLayer) - { - a.subresourceRange.layerCount += b.subresourceRange.layerCount; - states[states.size() - 2].second.subresourceRange.layerCount += b.subresourceRange.layerCount; - barriers.pop_back(); - states.pop_back(); - } - } -} - template void VulkanResourceManager::RecordSingleBarrier( rdcarray> &dststates, ResourceId id, @@ -319,165 +265,133 @@ void VulkanResourceManager::MergeBarriers(rdcarray void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser, - std::map &states, - rdcarray &barriers) + std::map &states) { SERIALISE_ELEMENT_LOCAL(NumImages, (uint32_t)states.size()); auto srcit = states.begin(); - rdcarray> vec; - std::set updatedState; for(uint32_t i = 0; i < NumImages; i++) { SERIALISE_ELEMENT_LOCAL(Image, (ResourceId)(srcit->first)).TypedAs("VkImage"_lit); - SERIALISE_ELEMENT_LOCAL(ImageState, (ImageLayouts)(srcit->second)); - - ResourceId liveid; - if(IsReplayingAndReading() && HasLiveResource(Image)) - liveid = GetLiveID(Image); - - if(IsReplayingAndReading() && liveid != ResourceId()) + if(ser.IsWriting()) { - updatedState.insert(liveid); + LockedImageStateRef lockedState = srcit->second.LockWrite(); + ::ImageState &ImageState = *lockedState; + SERIALISE_ELEMENT(ImageState); + ++srcit; + } + else + { + ImageState imageState; - VkImageMemoryBarrier t = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - - t.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - t.image = Unwrap(GetCurrentHandle(liveid)); - t.srcQueueFamilyIndex = ImageState.queueFamilyIndex; - t.dstQueueFamilyIndex = ImageState.queueFamilyIndex; - m_Core->RemapQueueFamilyIndices(t.srcQueueFamilyIndex, t.dstQueueFamilyIndex); - if(t.dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) - t.dstQueueFamilyIndex = t.srcQueueFamilyIndex = m_Core->GetQueueFamilyIndex(); - - for(ImageRegionState &state : ImageState.subresourceStates) + if(ser.VersionLess(0x11)) { - state.dstQueueFamilyIndex = t.dstQueueFamilyIndex; - - t.newLayout = state.newLayout; - t.subresourceRange = state.subresourceRange; - - auto stit = states.find(liveid); - - if(stit == states.end() || stit->second.isMemoryBound) + ImageLayouts imageLayouts; { - AddAndMerge(barriers, vec, t, make_rdcpair(liveid, state)); + ImageLayouts &ImageState = imageLayouts; + SERIALISE_ELEMENT(ImageState); + } + if(IsReplayingAndReading()) + { + if(imageLayouts.imageInfo.extent.depth > 1) + imageLayouts.imageInfo.imageType = VK_IMAGE_TYPE_3D; + + imageState = ImageState(VK_NULL_HANDLE, imageLayouts.imageInfo, eFrameRef_Unknown); + + rdcarray subresourceStates; + subresourceStates.reserve(imageLayouts.subresourceStates.size()); + + for(ImageRegionState &st : imageLayouts.subresourceStates) + { + ImageSubresourceStateForRange p; + p.range = st.subresourceRange; + p.range.sliceCount = imageLayouts.imageInfo.extent.depth; + p.state.oldQueueFamilyIndex = st.dstQueueFamilyIndex; + p.state.newQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + p.state.oldLayout = st.newLayout; + p.state.newLayout = imageState.GetImageInfo().initialLayout; + p.state.refType = eFrameRef_Unknown; + subresourceStates.push_back(p); + } + + imageState.subresourceStates.FromArray(subresourceStates); + imageState.maxRefType = eFrameRef_Unknown; } } - } - - if(ser.IsWriting()) - srcit++; - } - - // on replay, any images from the capture which didn't get touched above were created mid-frame so - // we reset them to their initialLayout. - if(IsReplayingAndReading()) - { - for(auto it = states.begin(); it != states.end(); ++it) - { - ResourceId liveid = it->first; - - if(GetOriginalID(liveid) != liveid && updatedState.find(liveid) == updatedState.end()) + else { - VkImageMemoryBarrier t = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - t.image = Unwrap(GetCurrentHandle(liveid)); - t.srcQueueFamilyIndex = it->second.queueFamilyIndex; - t.dstQueueFamilyIndex = it->second.queueFamilyIndex; - m_Core->RemapQueueFamilyIndices(t.srcQueueFamilyIndex, t.dstQueueFamilyIndex); - if(t.dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) - t.dstQueueFamilyIndex = t.srcQueueFamilyIndex = m_Core->GetQueueFamilyIndex(); - - for(ImageRegionState &state : it->second.subresourceStates) { - state.dstQueueFamilyIndex = t.dstQueueFamilyIndex; - - t.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - if(it->second.initialLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) - t.oldLayout = state.newLayout; - state.newLayout = t.newLayout = it->second.initialLayout; - - t.subresourceRange = state.subresourceRange; - - auto stit = states.find(liveid); - - if(stit == states.end() || stit->second.isMemoryBound) + ::ImageState &ImageState = imageState; + SERIALISE_ELEMENT(ImageState); + } + if(IsReplayingAndReading()) + { + imageState.newQueueFamilyTransfers.clear(); + for(auto it = imageState.subresourceStates.begin(); + it != imageState.subresourceStates.end(); ++it) { - AddAndMerge(barriers, vec, t, make_rdcpair(liveid, state)); + // Set the current image state (`newLayout`, `newQueueFamilyIndex`, `refType`) to the + // initial image state, so that calling `ResetToOldState` will move the image from the + // initial state to the state it was in at the beginning of the capture. + ImageSubresourceState &state = it->state(); + state.newLayout = imageState.GetImageInfo().initialLayout; + state.newQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + } + } + } + if(HasLiveResource(Image)) + { + ResourceId liveid = GetLiveID(Image); + + if(IsLoading(m_State)) + { + auto stit = states.find(liveid); + if(stit == states.end()) + { + imageState.subresourceStates.Unsplit(); + states.insert({liveid, LockingImageState(imageState)}); + } + else + { + auto st = stit->second.LockWrite(); + st->MergeCaptureBeginState(imageState); + st->subresourceStates.Unsplit(); + } + } + else if(IsActiveReplaying(m_State)) + { + auto current = states.find(liveid)->second.LockRead(); + auto stit = states.find(liveid); + for(auto subit = imageState.subresourceStates.begin(); + subit != imageState.subresourceStates.end(); ++subit) + { + uint32_t aspectIndex = 0; + for(auto it = ImageAspectFlagIter::begin(imageState.GetImageInfo().Aspects()); + it != ImageAspectFlagIter::end() && ((*it) & subit->range().aspectMask) == 0; + ++it, ++aspectIndex) + { + } + auto currentSub = current->subresourceStates.SubresourceValue( + aspectIndex, subit->range().baseMipLevel, subit->range().baseArrayLayer, + subit->range().baseDepthSlice); + RDCASSERT(currentSub.refType == subit->state().refType || + subit->state().refType == eFrameRef_Unknown); + RDCASSERT(currentSub.oldLayout == subit->state().oldLayout); + RDCASSERT(currentSub.oldQueueFamilyIndex == subit->state().oldQueueFamilyIndex || + subit->state().oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED); } } } } } - - // we don't have to specify a queue here because all of the images have a specific queue above - ApplyBarriers(VK_QUEUE_FAMILY_IGNORED, vec, states); - - for(size_t i = 0; i < vec.size(); i++) - { - if(barriers[i].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) - barriers[i].oldLayout = vec[i].second.oldLayout; - } - - // erase any do-nothing barriers - for(size_t i = 0; i < barriers.size();) - { - VkImageMemoryBarrier &b = barriers[i]; - - if(b.oldLayout == UNKNOWN_PREV_IMG_LAYOUT) - b.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - if(b.oldLayout == b.newLayout) - barriers.erase(i); - else - i++; - } - - // try to merge images that have been split up by subresource but are now all in the same state - // again. Don't do this for depth/stencil resources in case the aspects are split - for(auto it = states.begin(); it != states.end(); ++it) - { - ImageLayouts &layouts = it->second; - const ImageInfo &imageInfo = layouts.imageInfo; - - if(layouts.subresourceStates.size() > 1 && - layouts.subresourceStates[0].subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT && - layouts.subresourceStates.size() == size_t(imageInfo.layerCount) * size_t(imageInfo.levelCount)) - { - VkImageLayout layout = layouts.subresourceStates[0].newLayout; - - bool allIdentical = true; - - for(size_t i = 0; i < layouts.subresourceStates.size(); i++) - { - if(layouts.subresourceStates[i].newLayout != layout) - { - allIdentical = false; - break; - } - } - - if(allIdentical) - { - layouts.subresourceStates.erase(1, ~0U); - layouts.subresourceStates[0].subresourceRange.baseArrayLayer = 0; - layouts.subresourceStates[0].subresourceRange.baseMipLevel = 0; - layouts.subresourceStates[0].subresourceRange.layerCount = imageInfo.layerCount; - layouts.subresourceStates[0].subresourceRange.levelCount = imageInfo.levelCount; - } - } - } } - -template void VulkanResourceManager::SerialiseImageStates(ReadSerialiser &ser, - std::map &states, - rdcarray &barriers); -template void VulkanResourceManager::SerialiseImageStates(WriteSerialiser &ser, - std::map &states, - rdcarray &barriers); +template void VulkanResourceManager::SerialiseImageStates( + WriteSerialiser &ser, std::map &states); +template void VulkanResourceManager::SerialiseImageStates( + ReadSerialiser &ser, std::map &states); template void DoSerialise(SerialiserType &ser, MemRefInterval &el) @@ -575,28 +489,46 @@ template bool VulkanResourceManager::Serialise_DeviceMemoryRefs(ReadSerialiser & template bool VulkanResourceManager::Serialise_DeviceMemoryRefs(WriteSerialiser &ser, rdcarray &data); -template -bool VulkanResourceManager::Serialise_ImageRefs(SerialiserType &ser, rdcarray &data) +bool VulkanResourceManager::Serialise_ImageRefs(ReadSerialiser &ser, + std::map &states) { + rdcarray data; SERIALISE_ELEMENT(data); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { - // unpack data into m_ImgFrameRefs - for(auto it = data.begin(); it != data.end(); it++) - m_ImgFrameRefs.insert({it->image, it->imgRefs}); + // unpack data into states + for(auto it = data.begin(); it != data.end(); ++it) + { + if(!HasLiveResource(it->image)) + continue; + ResourceId liveid = GetLiveID(it->image); + + auto stit = states.find(liveid); + if(stit == states.end()) + { + RDCWARN("Found ImgRefs for unknown image"); + } + else + { + LockedImageStateRef imst = stit->second.LockWrite(); + imst->subresourceStates.FromImgRefs(it->imgRefs); + FrameRefType maxRefType = eFrameRef_None; + for(auto subit = imst->subresourceStates.begin(); subit != imst->subresourceStates.end(); + ++subit) + { + maxRefType = ComposeFrameRefsDisjoint(maxRefType, subit->state().refType); + } + imst->maxRefType = maxRefType; + } + } } return true; } -template bool VulkanResourceManager::Serialise_ImageRefs(ReadSerialiser &ser, - rdcarray &imageRefs); -template bool VulkanResourceManager::Serialise_ImageRefs(WriteSerialiser &ser, - rdcarray &imageRefs); - void VulkanResourceManager::InsertDeviceMemoryRefs(WriteSerialiser &ser) { rdcarray data; @@ -617,24 +549,6 @@ void VulkanResourceManager::InsertDeviceMemoryRefs(WriteSerialiser &ser) } } -void VulkanResourceManager::InsertImageRefs(WriteSerialiser &ser) -{ - rdcarray data; - data.reserve(m_ImgFrameRefs.size()); - size_t sizeEstimate = 32; - - for(auto it = m_ImgFrameRefs.begin(); it != m_ImgFrameRefs.end(); it++) - { - data.push_back({it->first, it->second}); - sizeEstimate += sizeof(ImgRefsPair) + sizeof(FrameRefType) * it->second.rangeRefs.size(); - } - - { - SCOPED_SERIALISE_CHUNK(VulkanChunk::ImageRefs, sizeEstimate); - Serialise_ImageRefs(ser, data); - } -} - void VulkanResourceManager::MarkSparseMapReferenced(ResourceInfo *sparse) { if(sparse == NULL) @@ -857,6 +771,43 @@ void VulkanResourceManager::ApplyBarriers(uint32_t queueFamilyIndex, } } +void VulkanResourceManager::RecordBarriers(std::map &states, + uint32_t queueFamilyIndex, uint32_t numBarriers, + const VkImageMemoryBarrier *barriers) +{ + TRDBG("Recording %u barriers", numBarriers); + + for(uint32_t ti = 0; ti < numBarriers; ti++) + { + const VkImageMemoryBarrier &t = barriers[ti]; + + ResourceId id = IsReplayMode(m_State) ? GetNonDispWrapper(t.image)->id : GetResID(t.image); + + if(id == ResourceId()) + { + RDCERR("Couldn't get ID for image in barrier"); + continue; + } + + auto stateIt = states.find(id); + if(stateIt == states.end()) + { + LockedConstImageStateRef globalState = m_Core->FindConstImageState(id); + if(!globalState) + { + RDCERR("Recording barrier for unknown image: %s", ToStr(id).c_str()); + continue; + } + stateIt = states.insert({id, globalState->CommandBufferInitialState()}).first; + } + + ImageState &state = stateIt->second; + state.RecordBarrier(t, queueFamilyIndex, m_Core->GetImageTransitionInfo()); + } + + TRDBG("Post-record, there are %u states", (uint32_t)states.size()); +} + ResourceId VulkanResourceManager::GetFirstIDForHandle(uint64_t handle) { for(auto it = m_CurrentResourceMap.begin(); it != m_CurrentResourceMap.end(); ++it) @@ -883,19 +834,6 @@ ResourceId VulkanResourceManager::GetFirstIDForHandle(uint64_t handle) return ResourceId(); } -void VulkanResourceManager::MarkImageFrameReferenced(const VkResourceRecord *img, - const ImageRange &range, FrameRefType refType) -{ - MarkImageFrameReferenced(img->GetResourceID(), img->resInfo->imageInfo, range, refType); -} - -void VulkanResourceManager::MarkImageFrameReferenced(ResourceId img, const ImageInfo &imageInfo, - const ImageRange &range, FrameRefType refType) -{ - FrameRefType maxRef = MarkImageReferenced(m_ImgFrameRefs, img, imageInfo, range, refType); - MarkResourceFrameReferenced(img, maxRef, ComposeFrameRefsDisjoint); -} - void VulkanResourceManager::MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize offset, VkDeviceSize size, FrameRefType refType) { @@ -910,23 +848,6 @@ void VulkanResourceManager::AddMemoryFrameRefs(ResourceId mem) m_MemFrameRefs.insert({mem, MemRefs()}); } -void VulkanResourceManager::AddImageFrameRefs(ResourceId img, const ImageInfo &imageInfo) -{ - m_ImgFrameRefs.insert({img, ImgRefs(imageInfo)}); -} - -void VulkanResourceManager::MergeReferencedImages(std::map &imgRefs) -{ - for(auto j = imgRefs.begin(); j != imgRefs.end(); j++) - { - auto i = m_ImgFrameRefs.find(j->first); - if(i == m_ImgFrameRefs.end()) - m_ImgFrameRefs.insert(*j); - else - i->second.Merge(j->second); - } -} - void VulkanResourceManager::MergeReferencedMemory(std::map &memRefs) { SCOPED_LOCK(m_Lock); @@ -941,11 +862,6 @@ void VulkanResourceManager::MergeReferencedMemory(std::map } } -void VulkanResourceManager::ClearReferencedImages() -{ - m_ImgFrameRefs.clear(); -} - void VulkanResourceManager::ClearReferencedMemory() { SCOPED_LOCK(m_Lock); diff --git a/renderdoc/driver/vulkan/vk_manager.h b/renderdoc/driver/vulkan/vk_manager.h index 7afbbc5d8..b68073827 100644 --- a/renderdoc/driver/vulkan/vk_manager.h +++ b/renderdoc/driver/vulkan/vk_manager.h @@ -264,18 +264,18 @@ public: rdcarray > &states, std::map &layouts); + void RecordBarriers(std::map &states, uint32_t queueFamilyIndex, + uint32_t numBarriers, const VkImageMemoryBarrier *barriers); + template - void SerialiseImageStates(SerialiserType &ser, std::map &states, - rdcarray &barriers); + void SerialiseImageStates(SerialiserType &ser, std::map &states); template bool Serialise_DeviceMemoryRefs(SerialiserType &ser, rdcarray &data); - template - bool Serialise_ImageRefs(SerialiserType &ser, rdcarray &data); + bool Serialise_ImageRefs(ReadSerialiser &ser, std::map &states); void InsertDeviceMemoryRefs(WriteSerialiser &ser); - void InsertImageRefs(WriteSerialiser &ser); ResourceId GetID(WrappedVkRes *res) { @@ -422,18 +422,11 @@ public: void SetInternalResource(ResourceId id); - void MarkImageFrameReferenced(const VkResourceRecord *img, const ImageRange &range, - FrameRefType refType); - void MarkImageFrameReferenced(ResourceId img, const ImageInfo &imageInfo, const ImageRange &range, - FrameRefType refType); void MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize start, VkDeviceSize end, FrameRefType refType); void AddMemoryFrameRefs(ResourceId mem); - void AddImageFrameRefs(ResourceId img, const ImageInfo &imageInfo); void MergeReferencedMemory(std::map &memRefs); - void MergeReferencedImages(std::map &imgRefs); - void ClearReferencedImages(); void ClearReferencedMemory(); MemRefs *FindMemRefs(ResourceId mem); ImgRefs *FindImgRefs(ResourceId img); diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 13c08078e..e95ed4b4e 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -3442,8 +3442,10 @@ void VkResourceRecord::MarkImageFrameReferenced(VkResourceRecord *img, const Ima if(img->resInfo && img->resInfo->IsSparse()) cmdInfo->sparse.insert(img->resInfo); - FrameRefType maxRef = - MarkImageReferenced(cmdInfo->imgFrameRefs, id, img->resInfo->imageInfo, range, refType); + ImageSubresourceRange range2(range); + + FrameRefType maxRef = MarkImageReferenced(cmdInfo->imageStates, id, img->resInfo->imageInfo, + range2, pool->queueFamilyIndex, refType); // maintain the reference type of the image itself as the maximum reference type of any // subresource @@ -3465,18 +3467,33 @@ void VkResourceRecord::MarkImageViewFrameReferenced(VkResourceRecord *view, cons if(refType != eFrameRef_Read && refType != eFrameRef_None) cmdInfo->dirtied.insert(img); - ImageRange imgRange; + ImageSubresourceRange imgRange; imgRange.aspectMask = view->viewRange.aspectMask; - imgRange.baseMipLevel = view->viewRange.baseMipLevel + range.baseMipLevel; - imgRange.levelCount = range.levelCount; - imgRange.baseArrayLayer = view->viewRange.baseArrayLayer + range.baseArrayLayer; - imgRange.layerCount = range.layerCount; - imgRange.offset = range.offset; - imgRange.extent = range.extent; - imgRange.viewType = view->viewRange.viewType(); - FrameRefType maxRef = - MarkImageReferenced(cmdInfo->imgFrameRefs, img, view->resInfo->imageInfo, imgRange, refType); + imgRange.baseMipLevel = range.baseMipLevel; + imgRange.levelCount = range.levelCount; + SanitiseLevelRange(imgRange.baseMipLevel, imgRange.levelCount, view->viewRange.levelCount()); + imgRange.baseMipLevel += view->viewRange.baseMipLevel; + + if(view->resInfo->imageInfo.imageType == VK_IMAGE_TYPE_3D && + view->viewRange.viewType() != VK_IMAGE_VIEW_TYPE_3D) + { + imgRange.baseDepthSlice = range.baseArrayLayer; + imgRange.sliceCount = range.layerCount; + SanitiseLayerRange(imgRange.baseDepthSlice, imgRange.sliceCount, view->viewRange.layerCount()); + imgRange.baseDepthSlice += view->viewRange.baseArrayLayer; + } + else + { + imgRange.baseArrayLayer = range.baseArrayLayer; + imgRange.layerCount = range.layerCount; + SanitiseLayerRange(imgRange.baseArrayLayer, imgRange.layerCount, view->viewRange.layerCount()); + imgRange.baseArrayLayer += view->viewRange.baseArrayLayer; + } + imgRange.Sanitise(view->resInfo->imageInfo); + + FrameRefType maxRef = MarkImageReferenced(cmdInfo->imageStates, img, view->resInfo->imageInfo, + imgRange, pool->queueFamilyIndex, refType); // maintain the reference type of the image itself as the maximum reference type of any // subresource @@ -3854,6 +3871,20 @@ void ResourceInfo::Update(uint32_t numBindings, const VkSparseMemoryBind *pBindi } } +FrameRefType MarkImageReferenced(std::map &imageStates, ResourceId img, + const ImageInfo &imageInfo, const ImageSubresourceRange &range, + uint32_t queueFamilyIndex, FrameRefType refType) +{ + if(refType == eFrameRef_None) + return refType; + auto it = imageStates.find(img); + if(it == imageStates.end()) + it = imageStates.insert({img, ImageState(VK_NULL_HANDLE, imageInfo, refType)}).first; + it->second.Update(range, ImageSubresourceState(queueFamilyIndex, UNKNOWN_PREV_IMG_LAYOUT, refType), + ComposeFrameRefs); + return it->second.maxRefType; +} + #if ENABLED(ENABLE_UNIT_TESTS) #undef None diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index e92f142b0..e954a6ed6 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -998,6 +998,7 @@ struct ResourceInfo struct MemRefs; struct ImgRefs; +struct ImageState; struct CmdBufferRecordingInfo { @@ -1007,8 +1008,6 @@ struct CmdBufferRecordingInfo VkResourceRecord *framebuffer = NULL; VkResourceRecord *allocRecord = NULL; - rdcarray > imgbarriers; - // sparse resources referenced by this command buffer (at submit time // need to go through the sparse mapping and reference all memory) std::set sparse; @@ -1028,7 +1027,8 @@ struct CmdBufferRecordingInfo rdcarray subcmds; - std::map imgFrameRefs; + std::map imageStates; + std::map memFrameRefs; // AdvanceFrame/Present should be called after this buffer is submitted @@ -1064,7 +1064,7 @@ struct DescriptorSetData static const uint32_t SPARSE_REF_BIT = 0x80000000; std::map > bindFrameRefs; std::map bindMemRefs; - std::map bindImgRefs; + std::map bindImageStates; }; struct PipelineLayoutData @@ -1979,6 +1979,10 @@ inline FrameRefType MarkImageReferenced(std::map &imgRefs, return MarkImageReferenced(imgRefs, img, imageInfo, range, refType, ComposeFrameRefs); } +FrameRefType MarkImageReferenced(std::map &imageStates, ResourceId img, + const ImageInfo &imageInfo, const ImageSubresourceRange &range, + uint32_t queueFamilyIndex, FrameRefType refType); + template FrameRefType MarkMemoryReferenced(std::map &memRefs, ResourceId mem, VkDeviceSize offset, VkDeviceSize size, FrameRefType refType, @@ -2030,10 +2034,10 @@ public: SwapChunks(bakedCommands); cmdInfo->dirtied.swap(bakedCommands->cmdInfo->dirtied); cmdInfo->boundDescSets.swap(bakedCommands->cmdInfo->boundDescSets); - cmdInfo->imgbarriers.swap(bakedCommands->cmdInfo->imgbarriers); cmdInfo->subcmds.swap(bakedCommands->cmdInfo->subcmds); cmdInfo->sparse.swap(bakedCommands->cmdInfo->sparse); - cmdInfo->imgFrameRefs.swap(bakedCommands->cmdInfo->imgFrameRefs); + RDCASSERT(bakedCommands->cmdInfo->imageStates.empty()); + cmdInfo->imageStates.swap(bakedCommands->cmdInfo->imageStates); cmdInfo->memFrameRefs.swap(bakedCommands->cmdInfo->memFrameRefs); } @@ -2069,7 +2073,7 @@ public: rdcpair &p = descInfo->bindFrameRefs[view->baseResource]; if((p.first & ~DescriptorSetData::SPARSE_REF_BIT) == 0) { - descInfo->bindImgRefs.erase(view->baseResource); + descInfo->bindImageStates.erase(view->baseResource); p.first = 1; p.second = eFrameRef_None; } @@ -2081,8 +2085,9 @@ public: ImageRange imgRange = ImageRange((VkImageSubresourceRange)view->viewRange); imgRange.viewType = view->viewRange.viewType(); - FrameRefType maxRef = MarkImageReferenced(descInfo->bindImgRefs, view->baseResource, - view->resInfo->imageInfo, imgRange, refType); + FrameRefType maxRef = + MarkImageReferenced(descInfo->bindImageStates, view->baseResource, view->resInfo->imageInfo, + ImageSubresourceRange(imgRange), pool->queueFamilyIndex, refType); p.second = ComposeFrameRefsDisjoint(p.second, maxRef); } diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index b29554d32..991bb812a 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -561,6 +561,7 @@ 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)]; } @@ -1683,12 +1684,8 @@ void WrappedVulkan::vkCmdEndRenderPass(VkCommandBuffer commandBuffer) const rdcarray &barriers = record->cmdInfo->rpbarriers; // apply the implicit layout transitions here - { - SCOPED_LOCK(m_ImageLayoutsLock); - GetResourceManager()->RecordBarriers(GetRecord(commandBuffer)->cmdInfo->imgbarriers, - m_ImageLayouts, (uint32_t)barriers.size(), - barriers.data()); - } + GetResourceManager()->RecordBarriers(record->cmdInfo->imageStates, record->pool->queueFamilyIndex, + (uint32_t)barriers.size(), barriers.data()); } } @@ -2197,12 +2194,8 @@ void WrappedVulkan::vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const rdcarray &barriers = record->cmdInfo->rpbarriers; // apply the implicit layout transitions here - { - SCOPED_LOCK(m_ImageLayoutsLock); - GetResourceManager()->RecordBarriers(GetRecord(commandBuffer)->cmdInfo->imgbarriers, - m_ImageLayouts, (uint32_t)barriers.size(), - barriers.data()); - } + GetResourceManager()->RecordBarriers(record->cmdInfo->imageStates, record->pool->queueFamilyIndex, + (uint32_t)barriers.size(), barriers.data()); } } @@ -3040,9 +3033,8 @@ void WrappedVulkan::vkCmdPipelineBarrier( if(imageMemoryBarrierCount > 0) { - SCOPED_LOCK(m_ImageLayoutsLock); - GetResourceManager()->RecordBarriers(GetRecord(commandBuffer)->cmdInfo->imgbarriers, - m_ImageLayouts, imageMemoryBarrierCount, + GetResourceManager()->RecordBarriers(record->cmdInfo->imageStates, + record->pool->queueFamilyIndex, imageMemoryBarrierCount, pImageMemoryBarriers); } } @@ -3661,8 +3653,8 @@ void WrappedVulkan::vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t execRecord->bakedCommands->cmdInfo->boundDescSets.end()); record->cmdInfo->subcmds.push_back(execRecord); - GetResourceManager()->MergeBarriers(record->cmdInfo->imgbarriers, - execRecord->bakedCommands->cmdInfo->imgbarriers); + ImageState::Merge(record->cmdInfo->imageStates, + execRecord->bakedCommands->cmdInfo->imageStates, GetImageTransitionInfo()); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index 784269481..bf7d9629a 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -196,10 +196,8 @@ void WrappedVulkan::vkDestroyImage(VkDevice device, VkImage obj, if(obj == VK_NULL_HANDLE) return; - { - SCOPED_LOCK(m_ImageLayoutsLock); - m_ImageLayouts.erase(GetResID(obj)); - } + EraseImageState(GetResID(obj)); + VkImage unwrappedObj = Unwrap(obj); GetResourceManager()->ReleaseWrappedResource(obj, true); return ObjDisp(device)->DestroyImage(Unwrap(device), unwrappedObj, pAllocator); @@ -724,16 +722,13 @@ VkResult WrappedVulkan::vkCreateFramebuffer(VkDevice device, GetResourceManager()->GetCurrentHandle(attRecord->baseResource); record->imageAttachments[a].barrier.subresourceRange = attRecord->viewRange; - ImageLayouts *layout = NULL; { - SCOPED_LOCK(m_ImageLayoutsLock); - layout = &m_ImageLayouts[attRecord->GetResourceID()]; - } - - if(layout->imageInfo.extent.depth > 1) - { - record->imageAttachments[a].barrier.subresourceRange.baseArrayLayer = 0; - record->imageAttachments[a].barrier.subresourceRange.layerCount = 1; + auto state = FindImageState(attRecord->GetResourceID()); + if(state && state->GetImageInfo().extent.depth > 1) + { + record->imageAttachments[a].barrier.subresourceRange.baseArrayLayer = 0; + record->imageAttachments[a].barrier.subresourceRange.layerCount = 1; + } } // if the renderpass specifies an aspect mask that mean split depth/stencil handling, so diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index e0d29e327..0eafd3eb9 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -821,8 +821,6 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount, std::set refdIDs; - VkResourceRecord *queueRecord = GetRecord(queue); - for(uint32_t s = 0; s < submitCount; s++) { for(uint32_t i = 0; i < pSubmits[s].commandBufferCount; i++) @@ -832,12 +830,7 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount, VkResourceRecord *record = GetRecord(pSubmits[s].pCommandBuffers[i]); present |= record->bakedCommands->cmdInfo->present; - { - SCOPED_LOCK(m_ImageLayoutsLock); - GetResourceManager()->ApplyBarriers(queueRecord->queueFamilyIndex, - record->bakedCommands->cmdInfo->imgbarriers, - m_ImageLayouts); - } + UpdateImageStates(record->bakedCommands->cmdInfo->imageStates); for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) @@ -896,7 +889,7 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount, GetResourceManager()->MarkSparseMapReferenced(sparserecord->resInfo); } } - GetResourceManager()->MergeReferencedImages(setrecord->descInfo->bindImgRefs); + UpdateImageStates(setrecord->descInfo->bindImageStates); GetResourceManager()->MergeReferencedMemory(setrecord->descInfo->bindMemRefs); } @@ -908,35 +901,32 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount, record->bakedCommands->AddResourceReferences(GetResourceManager()); record->bakedCommands->AddReferencedIDs(refdIDs); - GetResourceManager()->MergeReferencedImages(record->bakedCommands->cmdInfo->imgFrameRefs); GetResourceManager()->MergeReferencedMemory(record->bakedCommands->cmdInfo->memFrameRefs); // ref the parent command buffer's alloc record, this will pull in the cmd buffer pool GetResourceManager()->MarkResourceFrameReferenced( record->cmdInfo->allocRecord->GetResourceID(), eFrameRef_Read); - for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++) - { - record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddResourceReferences( - GetResourceManager()); - record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddReferencedIDs(refdIDs); - GetResourceManager()->MergeReferencedImages( - record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->cmdInfo->imgFrameRefs); - GetResourceManager()->MergeReferencedMemory( - record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->cmdInfo->memFrameRefs); - GetResourceManager()->MarkResourceFrameReferenced( - record->bakedCommands->cmdInfo->subcmds[sub]->cmdInfo->allocRecord->GetResourceID(), - eFrameRef_Read); + const rdcarray &subcmds = record->bakedCommands->cmdInfo->subcmds; - record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddRef(); + for(size_t sub = 0; sub < subcmds.size(); sub++) + { + VkResourceRecord *bakedSubcmds = subcmds[sub]->bakedCommands; + bakedSubcmds->AddResourceReferences(GetResourceManager()); + bakedSubcmds->AddReferencedIDs(refdIDs); + UpdateImageStates(bakedSubcmds->cmdInfo->imageStates); + GetResourceManager()->MergeReferencedMemory(bakedSubcmds->cmdInfo->memFrameRefs); + GetResourceManager()->MarkResourceFrameReferenced( + subcmds[sub]->cmdInfo->allocRecord->GetResourceID(), eFrameRef_Read); + + bakedSubcmds->AddRef(); } { SCOPED_LOCK(m_CmdBufferRecordsLock); m_CmdBufferRecords.push_back(record->bakedCommands); - for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++) - m_CmdBufferRecords.push_back( - record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands); + for(size_t sub = 0; sub < subcmds.size(); sub++) + m_CmdBufferRecords.push_back(subcmds[sub]->bakedCommands); } record->bakedCommands->AddRef(); diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index e1180d68d..0a6727f11 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -1049,14 +1049,14 @@ VkResult WrappedVulkan::vkBindImageMemory(VkDevice device, VkImage image, VkDevi chunk = scope.Get(); } - ImageLayouts *layout = NULL; { - SCOPED_LOCK(m_ImageLayoutsLock); - layout = &m_ImageLayouts[GetResID(image)]; + LockedImageStateRef state = FindImageState(GetResID(image)); + if(!state) + RDCERR("Binding memory to unknown image %s", ToStr(GetResID(image)).c_str()); + else + state->isMemoryBound = true; } - layout->isMemoryBound = true; - // memory object bindings are immutable and must happen before creation or use, // so this can always go into the record, even if a resource is created and bound // to memory mid-frame @@ -1858,43 +1858,7 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo * m_CreationInfo.m_Image[id].Init(GetResourceManager(), m_CreationInfo, pCreateInfo); } - VkImageSubresourceRange range; - range.baseMipLevel = range.baseArrayLayer = 0; - range.levelCount = pCreateInfo->mipLevels; - range.layerCount = pCreateInfo->arrayLayers; - - ImageLayouts *layout = NULL; - { - SCOPED_LOCK(m_ImageLayoutsLock); - layout = &m_ImageLayouts[id]; - } - layout->imageInfo = ImageInfo(*pCreateInfo); - - layout->initialLayout = pCreateInfo->initialLayout; - layout->subresourceStates.clear(); - - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - if(IsDepthOnlyFormat(pCreateInfo->format)) - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if(IsStencilOnlyFormat(pCreateInfo->format)) - range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - else if(IsDepthOrStencilFormat(pCreateInfo->format)) - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - // if we don't support separate depth/stencil, track both aspects together - if(!SeparateDepthStencil() && IsDepthAndStencilFormat(pCreateInfo->format)) - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - - layout->subresourceStates.push_back(ImageRegionState( - VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, pCreateInfo->initialLayout)); - - // if we do support separate depth stencil, add a separate stencil aspect tracker - if(SeparateDepthStencil() && IsDepthAndStencilFormat(pCreateInfo->format)) - { - range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - layout->subresourceStates.push_back(ImageRegionState( - VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, pCreateInfo->initialLayout)); - } + InsertImageState(*pImage, id, ImageInfo(*pCreateInfo), eFrameRef_None); } return ret; @@ -2204,14 +2168,15 @@ VkResult WrappedVulkan::vkBindImageMemory2(VkDevice device, uint32_t bindInfoCou chunk = scope.Get(); } - ImageLayouts *layout = NULL; { - SCOPED_LOCK(m_ImageLayoutsLock); - layout = &m_ImageLayouts[imgrecord->GetResourceID()]; + ResourceId id = imgrecord->GetResourceID(); + LockedImageStateRef state = FindImageState(id); + if(!state) + RDCERR("Binding memory for unknown image %s", ToStr(id).c_str()); + else + state->isMemoryBound = true; } - layout->isMemoryBound = true; - // memory object bindings are immutable and must happen before creation or use, // so this can always go into the record, even if a resource is created and bound // to memory mid-frame diff --git a/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp index 9fad282cd..5a18525d4 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_sync_funcs.cpp @@ -917,9 +917,8 @@ void WrappedVulkan::vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t even if(imageMemoryBarrierCount > 0) { - SCOPED_LOCK(m_ImageLayoutsLock); - GetResourceManager()->RecordBarriers(GetRecord(commandBuffer)->cmdInfo->imgbarriers, - m_ImageLayouts, imageMemoryBarrierCount, + GetResourceManager()->RecordBarriers(record->cmdInfo->imageStates, + record->pool->queueFamilyIndex, imageMemoryBarrierCount, pImageMemoryBarriers); } diff --git a/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp index 1eac8fc5b..ef39a2d86 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_wsi_funcs.cpp @@ -500,6 +500,9 @@ void WrappedVulkan::WrapAndProcessCreatedSwapchain(VkDevice device, swapInfo.imageInfo = ImageInfo(*pCreateInfo); + swapInfo.shared = (pCreateInfo->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || + pCreateInfo->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR); + VkResult vkr = VK_SUCCESS; const VkDevDispatchTable *vt = ObjDisp(device); @@ -587,18 +590,11 @@ void WrappedVulkan::WrapAndProcessCreatedSwapchain(VkDevice device, range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // fill out image info so we track resource state barriers - ImageLayouts *layout = NULL; { - SCOPED_LOCK(m_ImageLayoutsLock); - layout = &m_ImageLayouts[imid]; + LockedImageStateRef state = InsertImageState( + images[i], imid, GetRecord(images[i])->resInfo->imageInfo, eFrameRef_None); + state->isMemoryBound = true; } - layout->imageInfo = GetRecord(images[i])->resInfo->imageInfo; - layout->isMemoryBound = true; - layout->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - layout->subresourceStates.clear(); - layout->subresourceStates.push_back(ImageRegionState( - VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED)); { VkImageViewCreateInfo info = {