Ok, so I made little example of how to do this.
Short version
You need to allocate additional buffer with heap type D3D12_HEAP_TYPE_READBACK and resource state set to D3D12_RESOURCE_STATE_COPY_DEST. Then create command list with type D3D12_COMMAND_LIST_TYPE_COPY. After dispatch compute shader use fence to check if buffer is ready, then copy from this buffer to buffer on D3D12_HEAP_TYPE_READBACK heap. Check again with fence if copying is finished and call Map on this buffer.
I would suggest that you stop reading here and try implement it from description above and check longer version if its still doesn't work. Copy/Past isn't the best way to learn :)
Longer version
First lets create new command list.
ID3D12CommandQueue* copyQueue;
ID3D12CommandAllocator* copyAllocator;
ID3D12GraphicsCommandList* copyList;
D3D12_COMMAND_QUEUE_DESC descCopyQueue = {};
descCopyQueue.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
descCopyQueue.Type = D3D12_COMMAND_LIST_TYPE_COPY;
device->CreateCommandQueue(&descCopyQueue, IID_PPV_ARGS(©Queue));
device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(©Allocator));
device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, copyAllocator, nullptr, IID_PPV_ARGS(©List));
Notice type D3D12_COMMAND_LIST_TYPE_COPY.
Next thing is new buffer.
D3D12_HEAP_PROPERTIES const heapPropertiesReadback =
{
/*Type*/ D3D12_HEAP_TYPE_READBACK
/*CPUPageProperty*/ ,D3D12_CPU_PAGE_PROPERTY_UNKNOWN
/*MemoryPoolPreference*/ ,D3D12_MEMORY_POOL_UNKNOWN
/*CreationNodeMask*/ ,0
/*VisibleNodeMask*/ ,0
};
D3D12_RESOURCE_DESC buffersDesc = {};
buffersDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
buffersDesc.Alignment = 0;
buffersDesc.Width = sizeof( unsigned int ) * 5;
buffersDesc.Height = 1;
buffersDesc.DepthOrArraySize = 1;
buffersDesc.MipLevels = 1;
buffersDesc.Format = DXGI_FORMAT_UNKNOWN;
buffersDesc.SampleDesc.Count = 1;
buffersDesc.SampleDesc.Quality = 0;
buffersDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
buffersDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* bufferReadback;
device->CreateCommittedResource(&heapPropertiesReadback, D3D12_HEAP_FLAG_NONE, &buffersDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&bufferReadback));
Remember to set D3D12_RESOURCE_DESC ::Width to size of your buffers.
Then after you Dispatch compute list and call ExecuteCommandLists on compute queue you need to use fence, copy buffer and use fence again.
computeQueue->Signal(fence, fenceValue);
fence->SetEventOnCompletion(fenceValue, fenceEvent);
++fenceValue;
WaitForSingleObject(fenceEvent, INFINITE);
copyList->CopyResource(bufferReadback, bufferB);
copyList->Close();
copyQueue->ExecuteCommandLists(1, (ID3D12CommandList**)(©List));
copyQueue->Signal(fence, fenceValue);
fence->SetEventOnCompletion(fenceValue, fenceEvent);
++fenceValue;
WaitForSingleObject(fenceEvent, INFINITE);
After this you can call Map on resource.
unsigned int* data;
bufferReadback->Map(0, nullptr, reinterpret_cast<void**>(&data));
I hope this will help, let me know if you have any questions.
UAVbut maybe it will work, just setDstRowPitchandDstDepthPitchto buffer size (in bytes) and you will see if its work. I don't see why it shouldn't work (but maybe it don't) – Derag Apr 20 '17 at 21:18ThrowIfFailed(m_device->CreateCommittedResource( &defaultHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_InputBuffer1[0])));
and later on when I try to read it back as follows, the compiler throws an exception!
UINT8* pDataBegin; m_InputBuffer1[0]->ReadFromSubresource(reinterpret_cast<void*>(&pDataBegin),5,5,0,0); printf("The value pointed to is %d", pDataBegin);
any idea why this is happening ?
– Madhu Apr 21 '17 at 00:43ID3D12Resource::ReadFromSubresourcedoesn't allocate memory for you and it get pointer not pointer to pointer, so you need to allocate memory and castpDataBegintovoid*notvoid**. Remember to free allocated memory – Derag Apr 21 '17 at 09:07D3D12_RESOURCE_STATE_COPY_DESTbut i don't see whole code so can't tell if its should be this resource state. – Derag Apr 21 '17 at 09:18std::vector pDataBegin;
ThrowIfFailed(m_InputBuffer1[0]->Map(0, NULL, reinterpret_cast<void**>(&pDataBegin)));
but then again even this throws an error :(
– Madhu Apr 24 '17 at 18:36ReadFromSubresource? Did you do steps pointed on Microsoft page? – Derag Apr 24 '17 at 22:43If i keep the heap type DEFAULT and call Map, there is nothing returned into *pDataBegin
– Madhu Apr 24 '17 at 23:06