Lectura de datos a través de un búfer
Para volver a leer datos de la GPU (por ejemplo, para capturar una captura de pantalla), use un montón de lectura diferida. Esta técnica está relacionada con la carga de datos de textura a través de un búfer, con algunas diferencias.
- Para volver a 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 pendiente siempre debe ser un D3D12_RESOURCE_DIMENSION_BUFFER.
- Se usa una barrera para detectar cuándo la GPU finaliza el procesamiento de un fotograma (cuando se termina de escribir 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 sí se sincroniza). Las llamadas de Mapa de Direct3D 12 se comportan como si llamara al equivalente de Direct3D 11 con la marca NO_OVERWRITE.
- Una vez listos los datos (incluida la barrera de recursos necesaria), llame a ID3D12Resource::Map para que los datos de lectura diferida 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 el disco como un archivo, vea Kit de herramientas de DirectX paraScreenGrab de DX12.