버퍼를 통해 데이터를 다시 읽습니다.
GPU에서 데이터를 다시 읽으려면(예: 스크린샷 캡처) 다시 읽기 힙을 사용합니다. 이 기술은 버퍼 통해 텍스처 데이터를 업로드하는관련이 있으며 몇 가지 차이점이 있습니다.
- 데이터를 다시 읽으려면 D3D12_HEAP_TYPE_UPLOAD대신 D3D12_HEAP_TYPED3D12_HEAP_TYPE_READBACK설정하여 힙을 만듭니다.
- 읽기-뒤로 힙의 리소스는 항상 D3D12_RESOURCE_DIMENSION_BUFFER.
- 펜스를 사용하여 GPU가 프레임 처리를 완료하는 시기를 감지합니다(출력 버퍼에 데이터 쓰기가 완료되면). 이는 ID3D12Resource::Map 메서드가 GPU와 동기화되지 않기 때문에 중요합니다(반대로 Direct3D 11에 해당하는 동기화되지). Direct3D 12 Map 호출은 NO_OVERWRITE 플래그와 동등한 Direct3D 11을 호출한 것처럼 동작합니다.
- 데이터가 준비되면(필요한 리소스 장벽 포함) ID3D12Resource::Map 호출하여 다시 읽기 데이터를 CPU에 표시합니다.
코드 예제
아래 코드 예제에서는 버퍼를 통해 GPU에서 CPU로 데이터를 다시 읽는 프로세스의 일반적인 개요를 보여줍니다.
// The output buffer (created below) is on a default heap, so only the GPU can access it.
D3D12_HEAP_PROPERTIES defaultHeapProperties{ CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT) };
D3D12_RESOURCE_DESC outputBufferDesc{ CD3DX12_RESOURCE_DESC::Buffer(outputBufferSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) };
winrt::com_ptr<::ID3D12Resource> outputBuffer;
winrt::check_hresult(d3d12Device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&outputBufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
__uuidof(outputBuffer),
outputBuffer.put_void()));
// The readback buffer (created below) is on a readback heap, so that the CPU can access it.
D3D12_HEAP_PROPERTIES readbackHeapProperties{ CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK) };
D3D12_RESOURCE_DESC readbackBufferDesc{ CD3DX12_RESOURCE_DESC::Buffer(outputBufferSize) };
winrt::com_ptr<::ID3D12Resource> readbackBuffer;
winrt::check_hresult(d3d12Device->CreateCommittedResource(
&readbackHeapProperties,
D3D12_HEAP_FLAG_NONE,
&readbackBufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
__uuidof(readbackBuffer),
readbackBuffer.put_void()));
{
D3D12_RESOURCE_BARRIER outputBufferResourceBarrier
{
CD3DX12_RESOURCE_BARRIER::Transition(
outputBuffer.get(),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_COPY_SOURCE)
};
commandList->ResourceBarrier(1, &outputBufferResourceBarrier);
}
commandList->CopyResource(readbackBuffer.get(), outputBuffer.get());
// Code goes here to close, execute (and optionally reset) the command list, and also
// to use a fence to wait for the command queue.
// The code below assumes that the GPU wrote FLOATs to the buffer.
D3D12_RANGE readbackBufferRange{ 0, outputBufferSize };
FLOAT * pReadbackBufferData{};
winrt::check_hresult(
readbackBuffer->Map
(
0,
&readbackBufferRange,
reinterpret_cast<void**>(&pReadbackBufferData)
)
);
// Code goes here to access the data via pReadbackBufferData.
D3D12_RANGE emptyRange{ 0, 0 };
readbackBuffer->Unmap
(
0,
&emptyRange
);
렌더링 대상 텍스처를 읽고 디스크에 파일로 쓰는 스크린샷 루틴의 전체 구현은 DX12용 DirectX 도구 키트ScreenGrab참조하세요.
관련 항목
- 버퍼 내의 하위 할당