Leer datos a través de un búfer
Para leer los datos de la GPU (por ejemplo, para capturar una captura de pantalla), use un montón de reescritura. Esta técnica está relacionada con Carga de datos de textura a través de unde búfer, con algunas diferencias.
- Para leer los datos, cree un montón con el D3D12_HEAP_TYPE establecido en D3D12_HEAP_TYPE_READBACK, en lugar de D3D12_HEAP_TYPE_UPLOAD.
- El recurso del montón de lectura inversa debe ser siempre un D3D12_RESOURCE_DIMENSION_BUFFER.
- Se usa una barrera para detectar cuándo la GPU completa el procesamiento de un fotograma (cuando se realiza la escritura de datos en el búfer de salida). Esto es importante, porque el método ID3D12Resource::Map no se sincroniza con la GPU (por el contrario, el equivalente de Direct3D 11 sincroniza). Las llamadas de Direct3D 12 Map se comportan como si llamara al equivalente de Direct3D 11 con la marca NO_OVERWRITE.
- Una vez que los datos estén listos (incluidas las barreras de recursos necesarias), llame a ID3D12Resource::Map para que los datos de readback sean visibles para la CPU.
Ejemplo de código
En el ejemplo de código siguiente se muestra el esquema general del proceso de lectura de datos de la GPU a la CPU a través de un búfer.
// 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
);
Para obtener una implementación completa de una rutina de captura de pantalla que lee la textura de destino de representación y la escribe en disco como un archivo, consulte Kit de herramientas de DirectX para DX12ScreenGrab.
Temas relacionados
- Suballocation dentro de un de búfer