Extend lifetime of images and image views similar to buffers

* With descriptor buffers we need to ensure images and image views also do not
  get destroyed mid capture, similar to what we do for buffers and memory. The
  same reasoning applies - we don't want a single BDA to refer to two different
  buffers, and we also don't want a single descriptor to alias multiple
  resources either.
This commit is contained in:
baldurk
2025-09-09 18:57:34 +01:00
parent b687f30c17
commit 06b8dd9051
3 changed files with 69 additions and 3 deletions
+35
View File
@@ -2820,6 +2820,8 @@ bool WrappedVulkan::EndFrameCapture(DeviceOwnedWindow devWnd)
rdcarray<VkDeviceMemory> DeadMemories;
rdcarray<VkBuffer> DeadBuffers;
rdcarray<VkImage> DeadImages;
rdcarray<VkImageView> DeadImageViews;
// transition back to IDLE atomically
{
@@ -2846,6 +2848,8 @@ bool WrappedVulkan::EndFrameCapture(DeviceOwnedWindow devWnd)
SCOPED_LOCK(m_DeviceAddressResourcesLock);
DeadMemories.swap(m_DeviceAddressResources.DeadMemories);
DeadBuffers.swap(m_DeviceAddressResources.DeadBuffers);
DeadImages.swap(m_DeviceAddressResources.DeadImages);
DeadImageViews.swap(m_DeviceAddressResources.DeadImageViews);
}
}
@@ -2855,6 +2859,12 @@ bool WrappedVulkan::EndFrameCapture(DeviceOwnedWindow devWnd)
for(VkBuffer b : DeadBuffers)
vkDestroyBuffer(m_Device, b, NULL);
for(VkImage i : DeadImages)
vkDestroyImage(m_Device, i, NULL);
for(VkImageView v : DeadImageViews)
vkDestroyImageView(m_Device, v, NULL);
// gather backbuffer screenshot
const uint32_t maxSize = 2048;
RenderDoc::FramePixels fp;
@@ -3224,6 +3234,11 @@ bool WrappedVulkan::DiscardFrameCapture(DeviceOwnedWindow devWnd)
m_CapturedFrames.pop_back();
rdcarray<VkDeviceMemory> DeadMemories;
rdcarray<VkBuffer> DeadBuffers;
rdcarray<VkImage> DeadImages;
rdcarray<VkImageView> DeadImageViews;
// transition back to IDLE atomically
{
SCOPED_WRITELOCK(m_CapTransitionLock);
@@ -3243,8 +3258,28 @@ bool WrappedVulkan::DiscardFrameCapture(DeviceOwnedWindow devWnd)
(*it)->memMapState->needRefData = false;
}
}
{
SCOPED_LOCK(m_DeviceAddressResourcesLock);
DeadMemories.swap(m_DeviceAddressResources.DeadMemories);
DeadBuffers.swap(m_DeviceAddressResources.DeadBuffers);
DeadImages.swap(m_DeviceAddressResources.DeadImages);
DeadImageViews.swap(m_DeviceAddressResources.DeadImageViews);
}
}
for(VkDeviceMemory m : DeadMemories)
vkFreeMemory(m_Device, m, NULL);
for(VkBuffer b : DeadBuffers)
vkDestroyBuffer(m_Device, b, NULL);
for(VkImage i : DeadImages)
vkDestroyImage(m_Device, i, NULL);
for(VkImageView v : DeadImageViews)
vkDestroyImageView(m_Device, v, NULL);
Atomic::Inc32(&m_ReuseEnabled);
// delete cmd buffers now - had to keep them alive until after serialiser flush.
+4
View File
@@ -1031,6 +1031,10 @@ private:
rdcarray<VkDeviceMemory> DeadMemories;
rdcarray<VkBuffer> DeadBuffers;
rdcarray<ResourceId> IDs;
// with descriptor buffers, we also need to hold onto images and image views
rdcarray<VkImage> DeadImages;
rdcarray<VkImageView> DeadImageViews;
} m_DeviceAddressResources;
Threading::CriticalSection m_DeviceAddressResourcesLock;
@@ -194,6 +194,20 @@ void WrappedVulkan::vkDestroyImageView(VkDevice device, VkImageView obj, const V
{
if(obj == VK_NULL_HANDLE)
return;
// with descriptor buffers, extend the lifespan of image views to ensure descriptors don't falsely
// alias
if(DescriptorBuffers())
{
SCOPED_READLOCK(m_CapTransitionLock);
SCOPED_LOCK(m_DeviceAddressResourcesLock);
if(IsActiveCapturing(m_State))
{
m_DeviceAddressResources.DeadImageViews.push_back(obj);
return;
}
}
VkImageView unwrappedObj = Unwrap(obj);
{
SCOPED_LOCK(m_ForcedReferencesLock);
@@ -289,9 +303,6 @@ void WrappedVulkan::vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAl
if(buffer == VK_NULL_HANDLE)
return;
if(IsCaptureMode(m_State))
UntrackBufferAddress(device, buffer);
// artificially extend the lifespan of buffer device address memory or buffers, to ensure their
// opaque capture address isn't re-used before the capture completes
{
@@ -305,6 +316,9 @@ void WrappedVulkan::vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAl
m_DeviceAddressResources.IDs.removeOne(GetResID(buffer));
}
if(IsCaptureMode(m_State))
UntrackBufferAddress(device, buffer);
VkBuffer unwrappedObj = Unwrap(buffer);
if(IsCaptureMode(m_State))
@@ -387,6 +401,19 @@ void WrappedVulkan::vkDestroyImage(VkDevice device, VkImage obj, const VkAllocat
if(obj == VK_NULL_HANDLE)
return;
// with descriptor buffers, extend the lifespan of images to ensure descriptors don't falsely
// alias
if(DescriptorBuffers())
{
SCOPED_READLOCK(m_CapTransitionLock);
SCOPED_LOCK(m_DeviceAddressResourcesLock);
if(IsActiveCapturing(m_State))
{
m_DeviceAddressResources.DeadImages.push_back(obj);
return;
}
}
{
SCOPED_LOCK(m_ForcedReferencesLock);
m_ForcedReferences.removeOne(GetRecord(obj));