mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-26 23:55:46 +00:00
Implement GPU-pushed readback for memory when optimal on D3D12
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user