Use a dedicated transfer queue for D3D12 GPU readbacks

* This prevents a potential deadlock/failed readback situation if the queue
  we're submitting on at the time memory needs to be read is currently blocked
  by a pending wait and can't execute more code.
This commit is contained in:
baldurk
2024-02-23 13:09:34 +00:00
parent ec17ee5999
commit 58cc331e27
3 changed files with 39 additions and 49 deletions
@@ -908,45 +908,26 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists
{
QueueReadbackData &queueReadback = m_pDevice->GetQueueReadbackData();
D3D12_COMMAND_LIST_TYPE type = GetDesc().Type;
D3D12_HEAP_PROPERTIES heapProps;
res->GetHeapProperties(&heapProps, NULL);
if(type >= ARRAY_COUNT(queueReadback.lists))
if(heapProps.Type == D3D12_HEAP_TYPE_UPLOAD ||
heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE)
{
RDCERR("Unexpected invalid queue type %s", ToStr(type).c_str());
}
else
{
ID3D12GraphicsCommandList *list = queueReadback.lists[type];
ID3D12CommandAllocator *alloc = queueReadback.allocs[type];
RDCLOG("Doing GPU readback of mapped memory");
D3D12_HEAP_PROPERTIES heapProps;
res->GetHeapProperties(&heapProps, NULL);
queueReadback.lock.Lock();
if(heapProps.Type == D3D12_HEAP_TYPE_UPLOAD ||
heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE)
{
if(!list)
{
RDCERR("No readback list prepared for queue type %s", ToStr(type).c_str());
}
else
{
queueReadback.lock.Lock();
queueReadback.Resize(size);
queueReadback.Resize(size);
queueReadback.list->Reset(queueReadback.alloc, NULL);
queueReadback.list->CopyBufferRegion(queueReadback.readbackBuf, 0, res, 0, size);
queueReadback.list->Close();
ID3D12CommandList *listptr = Unwrap(queueReadback.list);
queueReadback.unwrappedQueue->ExecuteCommandLists(1, &listptr);
m_pDevice->GPUSync(queueReadback.unwrappedQueue, Unwrap(queueReadback.fence));
list->Reset(alloc, NULL);
list->CopyBufferRegion(queueReadback.readbackBuf, 0, res, 0, size);
list->Close();
ID3D12CommandList *listptr = Unwrap(list);
m_pReal->ExecuteCommandLists(1, &listptr);
m_pDevice->GPUSync(this);
data = queueReadback.readbackMapped;
}
}
data = queueReadback.readbackMapped;
}
if(ref)
+22 -13
View File
@@ -3825,18 +3825,26 @@ void WrappedID3D12Device::CreateInternalResources()
m_QueueReadbackData.Resize(4 * 1024 * 1024);
InternalRef();
for(D3D12_COMMAND_LIST_TYPE type :
{D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_LIST_TYPE_COMPUTE,
D3D12_COMMAND_LIST_TYPE_COPY})
{
CreateCommandAllocator(type, __uuidof(ID3D12CommandAllocator),
(void **)&m_QueueReadbackData.allocs[type]);
D3D12_COMMAND_QUEUE_DESC desc = {};
desc.Type = D3D12_COMMAND_LIST_TYPE_COPY;
// make this queue as unwrapped so that it doesn't get included in captures
GetReal()->CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue),
(void **)&m_QueueReadbackData.unwrappedQueue);
InternalRef();
CreateCommandList(0, type, m_QueueReadbackData.allocs[type], NULL,
__uuidof(ID3D12GraphicsCommandList),
(void **)&m_QueueReadbackData.lists[type]);
m_QueueReadbackData.unwrappedQueue->SetName(L"m_QueueReadbackData.queue");
CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, __uuidof(ID3D12CommandAllocator),
(void **)&m_QueueReadbackData.alloc);
m_QueueReadbackData.alloc->SetName(L"m_QueueReadbackData.alloc");
InternalRef();
CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, m_QueueReadbackData.alloc, NULL,
__uuidof(ID3D12GraphicsCommandList), (void **)&m_QueueReadbackData.list);
InternalRef();
m_QueueReadbackData.list->Close();
CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
(void **)&m_QueueReadbackData.fence);
m_QueueReadbackData.fence->SetName(L"m_QueueReadbackData.fence");
InternalRef();
m_QueueReadbackData.lists[type]->Close();
}
}
@@ -3844,6 +3852,7 @@ void WrappedID3D12Device::CreateInternalResources()
(void **)&m_Alloc);
InternalRef();
CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), (void **)&m_GPUSyncFence);
m_GPUSyncFence->SetName(L"m_GPUSyncFence");
InternalRef();
m_GPUSyncHandle = ::CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -3929,10 +3938,10 @@ void WrappedID3D12Device::DestroyInternalResources()
SAFE_RELEASE(m_DataUploadList[i]);
SAFE_RELEASE(m_DataUploadAlloc);
for(size_t i = 0; i < ARRAY_COUNT(m_QueueReadbackData.allocs); i++)
SAFE_RELEASE(m_QueueReadbackData.allocs[i]);
for(size_t i = 0; i < ARRAY_COUNT(m_QueueReadbackData.lists); i++)
SAFE_RELEASE(m_QueueReadbackData.lists[i]);
SAFE_RELEASE(m_QueueReadbackData.unwrappedQueue);
SAFE_RELEASE(m_QueueReadbackData.alloc);
SAFE_RELEASE(m_QueueReadbackData.list);
SAFE_RELEASE(m_QueueReadbackData.fence);
m_QueueReadbackData.Resize(0);
SAFE_RELEASE(m_Alloc);
+4 -4
View File
@@ -68,10 +68,10 @@ struct QueueReadbackData
byte *readbackMapped = NULL;
uint64_t readbackSize = 0;
static const uint32_t NumCommandTypes = 7;
ID3D12GraphicsCommandList *lists[NumCommandTypes] = {};
ID3D12CommandAllocator *allocs[NumCommandTypes] = {};
ID3D12CommandQueue *unwrappedQueue = NULL;
ID3D12GraphicsCommandList *list = NULL;
ID3D12CommandAllocator *alloc = NULL;
ID3D12Fence *fence = NULL;
void Resize(uint64_t size);