Share via


Lire les données à l’aide d’une mémoire tampon

Pour lire des données à partir du GPU (par exemple, pour capturer une capture d’écran), vous utilisez un tas de données en lecture différée. Cette technique est liée au chargement de données de texture via une mémoire tampon, avec quelques différences.

  • Pour lire les données, vous créez un tas avec le D3D12_HEAP_TYPE défini sur D3D12_HEAP_TYPE_READBACK, au lieu de D3D12_HEAP_TYPE_UPLOAD.
  • La ressource sur le tas de lecture arrière doit toujours être une D3D12_RESOURCE_DIMENSION_BUFFER.
  • Vous utilisez une clôture pour détecter quand le GPU termine le traitement d’une trame (lorsqu’il est terminé d’écrire des données dans votre mémoire tampon de sortie). Cela est important, car la méthode ID3D12Resource::Map ne se synchronise pas avec le GPU (à l’inverse, l’équivalent Direct3D 11 ne se synchronise pas). Les appels de mappage Direct3D 12 se comportent comme si vous appeliez l’équivalent Direct3D 11 avec l’indicateur NO_OVERWRITE.
  • Une fois les données prêtes (y compris toute barrière de ressources nécessaire), appelez ID3D12Resource::Map pour rendre les données de lecture visibles pour le processeur.

Exemple de code

L’exemple de code ci-dessous montre le plan général du processus de lecture des données du GPU vers le processeur par le biais d’une mémoire tampon.


// 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
);

Pour obtenir une implémentation complète d’une routine de capture d’écran qui lit la texture cible de rendu et l’écrit sur le disque sous forme de fichier, consultez Le Kit d’outils DirectX pour ScreenGrab de DX12.