Prevent deadlock in vulkan recursively acquiring RW lock

This commit is contained in:
baldurk committed 2021-07-07 19:18:32 +01:00
1 parent ca0b4eabf3
commit e5121198e3
3 files changed
+60 -70

No files matched your search

+3 -4
View File
@@ -715,10 +715,6 @@ private:
// All IDs are original IDs, not live.
VulkanRenderState m_RenderState;
// an internal structure used to differentiate forced vkFlushMappedMemoryRanges due to coherent
// map writes from real calls to vkFlushMappedMemoryRanges
VkBaseInStructure internalMemoryFlushMarker = {};
bool InRerecordRange(ResourceId cmdid);
bool HasRerecordCmdBuf(ResourceId cmdid);
bool ShouldUpdateRenderState(ResourceId cmdid, bool forcePrimary = false);
@@ -932,6 +928,9 @@ private:
void CaptureQueueSubmit(VkQueue queue, const rdcarray<VkCommandBuffer> &commandBuffers,
VkFence fence);
void ReplayQueueSubmit(VkQueue queue, VkSubmitInfo2KHR submitInfo, rdcstr basename);
void InternalFlushMemoryRange(VkDevice device, const VkMappedMemoryRange &memRange,
bool internalFlush, bool capframe);
void DoSubmit(VkQueue queue, VkSubmitInfo2KHR submitInfo);
rdcarray<VulkanActionTreeNode *> m_ActionStack;
@@ -1128,12 +1128,12 @@ void WrappedVulkan::CaptureQueueSubmit(VkQueue queue,
ToStr(record->GetResourceID()).c_str(), (uint64_t)diffStart, (uint64_t)diffEnd);
VkMappedMemoryRange range = {
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
&internalMemoryFlushMarker,
NULL,
(VkDeviceMemory)(uint64_t)record->Resource,
state.mapOffset + diffStart,
diffEnd - diffStart,
};
vkFlushMappedMemoryRanges(dev, 1, &range);
InternalFlushMemoryRange(dev, range, true, capframe);
}
}
else
@@ -1152,6 +1152,57 @@ bool WrappedVulkan::Serialise_vkFlushMappedMemoryRanges(SerialiserType &ser, VkD
return true;
}
void WrappedVulkan::InternalFlushMemoryRange(VkDevice device, const VkMappedMemoryRange &memRange,
bool internalFlush, bool capframe)
{
ResourceId memid = GetResID(memRange.memory);
VkResourceRecord *record = GetRecord(memRange.memory);
MemMapState *state = record->memMapState;
if(!internalFlush)
state->mapFlushed = true;
if(state->mappedPtr == NULL)
{
RDCERR("Flushing memory %s that isn't currently mapped", ToStr(memid).c_str());
return;
}
if(capframe)
{
SCOPED_LOCK_OPTIONAL(state->mrLock, !internalFlush);
CACHE_THREAD_SERIALISER();
SCOPED_SERIALISE_CHUNK(internalFlush ? VulkanChunk::CoherentMapWrite
: VulkanChunk::vkFlushMappedMemoryRanges);
Serialise_vkFlushMappedMemoryRanges(ser, device, 1, &memRange);
m_FrameCaptureRecord->AddChunk(scope.Get());
}
if(capframe)
{
VkDeviceSize offs = memRange.offset;
VkDeviceSize size = memRange.size;
// map VK_WHOLE_SIZE into a specific size
if(size == VK_WHOLE_SIZE)
size = state->mapOffset + state->mapSize - offs;
GetResourceManager()->MarkMemoryFrameReferenced(memid, offs, size, eFrameRef_CompleteWrite);
}
else
{
FrameRefType refType = eFrameRef_PartialWrite;
if(memRange.offset == 0 && memRange.size >= record->Length)
refType = eFrameRef_CompleteWrite;
GetResourceManager()->MarkResourceFrameReferenced(memid, refType);
}
}
VkResult WrappedVulkan::vkFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
const VkMappedMemoryRange *pMemRanges)
{
@@ -1163,28 +1214,13 @@ VkResult WrappedVulkan::vkFlushMappedMemoryRanges(VkDevice device, uint32_t memR
}
VkResult ret;
bool internalFlush = false;
// don't call the driver for a fake coherent map flush
if(memRangeCount == 1 && pMemRanges->pNext == &internalMemoryFlushMarker)
{
ret = VK_SUCCESS;
internalFlush = true;
// for simplicity we set the pNext to NULL after we've seen our internal marker. We can safely
// modify this because it's a temporary variable in the calling stackframe
VkMappedMemoryRange *range = (VkMappedMemoryRange *)pMemRanges;
range->pNext = NULL;
}
else
{
SERIALISE_TIME_CALL(
ret = ObjDisp(device)->FlushMappedMemoryRanges(Unwrap(device), memRangeCount, unwrapped));
}
SERIALISE_TIME_CALL(
ret = ObjDisp(device)->FlushMappedMemoryRanges(Unwrap(device), memRangeCount, unwrapped));
if(IsCaptureMode(m_State))
{
bool capframe = false;
{
SCOPED_READLOCK(m_CapTransitionLock);
capframe = IsActiveCapturing(m_State);
@@ -1192,52 +1228,7 @@ VkResult WrappedVulkan::vkFlushMappedMemoryRanges(VkDevice device, uint32_t memR
for(uint32_t i = 0; i < memRangeCount; i++)
{
ResourceId memid = GetResID(pMemRanges[i].memory);
VkResourceRecord *record = GetRecord(pMemRanges[i].memory);
MemMapState *state = record->memMapState;
if(!internalFlush)
state->mapFlushed = true;
if(state->mappedPtr == NULL)
{
RDCERR("Flushing memory %s that isn't currently mapped", ToStr(memid).c_str());
continue;
}
if(capframe)
{
SCOPED_LOCK_OPTIONAL(state->mrLock, !internalFlush);
CACHE_THREAD_SERIALISER();
SCOPED_SERIALISE_CHUNK(internalFlush ? VulkanChunk::CoherentMapWrite
: VulkanChunk::vkFlushMappedMemoryRanges);
Serialise_vkFlushMappedMemoryRanges(ser, device, 1, pMemRanges + i);
m_FrameCaptureRecord->AddChunk(scope.Get());
}
if(capframe)
{
VkDeviceSize offs = pMemRanges[i].offset;
VkDeviceSize size = pMemRanges[i].size;
// map VK_WHOLE_SIZE into a specific size
if(size == VK_WHOLE_SIZE)
size = state->mapOffset + state->mapSize - offs;
GetResourceManager()->MarkMemoryFrameReferenced(memid, offs, size, eFrameRef_CompleteWrite);
}
else
{
FrameRefType refType = eFrameRef_PartialWrite;
if(pMemRanges[i].offset == 0 && pMemRanges[i].size >= record->Length)
refType = eFrameRef_CompleteWrite;
GetResourceManager()->MarkResourceFrameReferenced(memid, refType);
}
InternalFlushMemoryRange(device, pMemRanges[i], false, capframe);
}
}