From c3f1ccc38ea8de99172caef6e33148c22bd5490d Mon Sep 17 00:00:00 2001 From: James Sumihiro Date: Thu, 10 Apr 2025 08:42:13 -0700 Subject: [PATCH] Fix image state merge with secondary command buffers. If a secondary command buffer referenced an image but its layout is unknown, it remains unknown when merged into a primary command buffer. --- renderdoc/driver/vulkan/vk_image_states.cpp | 10 +++++++++- renderdoc/driver/vulkan/vk_resources.h | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/renderdoc/driver/vulkan/vk_image_states.cpp b/renderdoc/driver/vulkan/vk_image_states.cpp index 67c516a4e..4138d2191 100644 --- a/renderdoc/driver/vulkan/vk_image_states.cpp +++ b/renderdoc/driver/vulkan/vk_image_states.cpp @@ -941,7 +941,15 @@ void ImageState::Merge(rdcflatmap &states, { if(it == states.end() || dstIt->first < it->first) { - it = states.insert(it, {dstIt->first, dstIt->second.InitialState()}); + // If we're merging in an image state our source hasn't seen before, we first add an initial + // state for that image, then merge in the current image state. However, if the destination + // only referenced the image and never recorded an explicit layout transition the layout of + // that image will be unknown. In that case we copy it as-is to avoid improperly recording a + // transition back to initial state. + if(dstIt->second.subresourceStates.IsInitialised()) + it = states.insert(it, {dstIt->first, dstIt->second.InitialState()}); + else + it = states.insert(it, *dstIt); } else if(it->first < dstIt->first) { diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 09e078d6d..9b93ec3fc 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -1593,6 +1593,16 @@ public: m_value = ImageSubresourceState(VK_QUEUE_FAMILY_IGNORED, UNKNOWN_PREV_IMG_LAYOUT, refType); } + bool IsInitialised() const + { + // When merging image states from a secondary command buffer into a primary, some of those image + // states may have been added in an unknown layout when the image was referenced and never + // updated. These cases need to be detected and handled separately, otherwise the layout + // transitions recorded to the primary may be improperly overwritten. + return (!m_values.empty() || m_value.oldLayout != UNKNOWN_PREV_IMG_LAYOUT || + m_value.newLayout != UNKNOWN_PREV_IMG_LAYOUT); + } + void ToArray(rdcarray &arr); void FromArray(const rdcarray &arr);