Implement GPU-pushed readback for memory when optimal on D3D12

This commit is contained in:
baldurk
2022-11-11 15:25:51 +00:00
parent 7b96647dac
commit 7291567fff
3 changed files with 139 additions and 2 deletions
@@ -916,6 +916,52 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists
// the resource has been unmapped on another thread before we got here.
if(data)
{
QueueReadbackData &queueReadback = m_pDevice->GetQueueReadbackData();
D3D12_COMMAND_LIST_TYPE type = GetDesc().Type;
if(type >= ARRAY_COUNT(queueReadback.lists))
{
RDCERR("Unexpected invalid queue type %s", ToStr(type).c_str());
}
else if(1)
{
}
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);
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);
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;
}
}
}
if(ref)
found = FindDiffRange(data, ref, size, diffStart, diffEnd);
else
@@ -945,6 +991,9 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists
{
RDCDEBUG("Persistent map flush not needed for %s", ToStr(res->GetResourceID()).c_str());
}
if(data == queueReadback.readbackMapped)
queueReadback.lock.Unlock();
}
res->UnlockMaps();
+74 -2
View File
@@ -724,10 +724,9 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara
m_pInfoQueue->ClearStoredMessages();
m_pInfoQueue->SetMuteDebugOutput(false);
if(RenderDoc::Inst().IsReplayApp())
{
m_pInfoQueue->SetMuteDebugOutput(false);
D3D12_MESSAGE_ID mute[] = {
// the runtime cries foul when you use normal APIs in expected ways (for simple markers)
D3D12_MESSAGE_ID_CORRUPTED_PARAMETER2,
@@ -3473,6 +3472,54 @@ void WrappedID3D12Device::FreeRTV(D3D12_CPU_DESCRIPTOR_HANDLE handle)
}
}
void QueueReadbackData::Resize(uint64_t size)
{
size = AlignUp(size, 4096ULL);
if(readbackSize >= size && size != 0)
return;
if(readbackBuf)
{
Unwrap(readbackBuf)->Unmap(0, NULL);
SAFE_RELEASE(readbackBuf);
readbackMapped = NULL;
}
readbackSize = size;
if(size == 0)
return;
RDCLOG("Resizing GPU readback window to %llu", size);
D3D12_RESOURCE_DESC readbackDesc;
readbackDesc.Alignment = 0;
readbackDesc.DepthOrArraySize = 1;
readbackDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
readbackDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
readbackDesc.Format = DXGI_FORMAT_UNKNOWN;
readbackDesc.Height = 1;
readbackDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
readbackDesc.MipLevels = 1;
readbackDesc.SampleDesc.Count = 1;
readbackDesc.SampleDesc.Quality = 0;
readbackDesc.Width = size;
D3D12_HEAP_PROPERTIES heapProps;
heapProps.Type = D3D12_HEAP_TYPE_READBACK;
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapProps.CreationNodeMask = 1;
heapProps.VisibleNodeMask = 1;
device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &readbackDesc,
D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource),
(void **)&readbackBuf);
// don't intercept the map
Unwrap(readbackBuf)->Map(0, NULL, (void **)&readbackMapped);
}
void WrappedID3D12Device::CreateInternalResources()
{
if(IsReplayMode(m_State))
@@ -3498,6 +3545,25 @@ void WrappedID3D12Device::CreateInternalResources()
// we don't want replay-only shaders added in WrappedID3D12Shader to pollute the list of resources
WrappedID3D12Shader::InternalResources(true);
{
m_QueueReadbackData.device = this;
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]);
InternalRef();
CreateCommandList(0, type, m_QueueReadbackData.allocs[type], NULL,
__uuidof(ID3D12GraphicsCommandList),
(void **)&m_QueueReadbackData.lists[type]);
InternalRef();
}
}
CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator),
(void **)&m_Alloc);
InternalRef();
@@ -3587,6 +3653,12 @@ 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]);
m_QueueReadbackData.Resize(0);
SAFE_RELEASE(m_Alloc);
SAFE_RELEASE(m_GPUSyncFence);
CloseHandle(m_GPUSyncHandle);
+16
View File
@@ -61,6 +61,20 @@ struct D3D12InitParams
DECLARE_REFLECTION_STRUCT(D3D12InitParams);
struct QueueReadbackData
{
Threading::CriticalSection lock;
ID3D12Resource *readbackBuf = NULL;
byte *readbackMapped = NULL;
uint64_t readbackSize = 0;
ID3D12GraphicsCommandList *lists[6] = {};
ID3D12CommandAllocator *allocs[6] = {};
void Resize(uint64_t size);
WrappedID3D12Device *device;
};
class WrappedID3D12Device;
class WrappedID3D12Resource;
class WrappedID3D12PipelineState;
@@ -588,6 +602,7 @@ private:
WrappedID3D12CommandQueue *m_Queue;
ID3D12CommandAllocator *m_Alloc = NULL, *m_DataUploadAlloc = NULL;
QueueReadbackData m_QueueReadbackData;
ID3D12GraphicsCommandList *m_DataUploadList[64] = {};
size_t m_CurDataUpload = 0;
ID3D12DescriptorHeap *m_RTVHeap = NULL;
@@ -806,6 +821,7 @@ public:
void FirstFrame(IDXGISwapper *swapper);
const ActionDescription *GetAction(uint32_t eventId);
QueueReadbackData &GetQueueReadbackData() { return m_QueueReadbackData; }
bool IsBindlessResourceUseActive() const { return m_BindlessResourceUseActive; }
ResourceId GetFrameCaptureResourceId() { return m_FrameCaptureRecord->GetResourceID(); }
void AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src, rdcstr d);