Lesen von Daten über einen Puffer
Zum Lesen von Daten aus der GPU (z. B. zum Erfassen eines Screenshots) verwenden Sie einen Readback-Heap. Diese Technik bezieht sich auf Hochladen von Texturdaten über einen Puffermit einigen Unterschieden.
- Um Daten zu lesen, erstellen Sie einen Heap mit dem D3D12_HEAP_TYPE auf D3D12_HEAP_TYPE_READBACKund nicht auf D3D12_HEAP_TYPE_UPLOADfestgelegt.
- Die Ressource im Lese-Zurück-Heap muss immer eine D3D12_RESOURCE_DIMENSION_BUFFERsein.
- Sie verwenden einen Zaun, um zu erkennen, wann die GPU die Verarbeitung eines Frames abgeschlossen hat (wenn das Schreiben von Daten in Den Ausgabepuffer abgeschlossen ist). Dies ist wichtig, da die ID3D12Resource::Map-Methode nicht mit der GPU synchronisiert wird (umgekehrt wird das Direct3D 11-Äquivalent synchronisiert). Direct3D 12-Zuordnung Aufrufe verhalten sich so, als ob Sie die Direct3D 11-Entsprechung mit dem NO_OVERWRITE-Flag aufgerufen haben.
- Nachdem die Daten bereit sind (einschließlich aller erforderlichen Ressourcenbarrieren), rufen Sie ID3D12Resource::Map auf, um die Lesedaten für die CPU sichtbar zu machen.
Codebeispiel
Das folgende Codebeispiel zeigt die allgemeine Gliederung des Prozesses des Lesens von Daten aus der GPU über einen Puffer auf die 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
);
Eine vollständige Implementierung einer Screenshotroutine, die die Renderzieltextur liest und als Datei auf den Datenträger schreibt, finden Sie unter DirectX Tool Kit für DX12's ScreenGrab.