Aracılığıyla paylaş


Arabellek aracılığıyla verileri geri okuma

GPU'dan verileri geri okumak için (örneğin, ekran görüntüsü yakalamak için) bir geri okuma yığını kullanırsınız. Bu teknik, Doku verilerini bir arabellekaracılığıyla karşıya yükleme ile ilgilidir ve birkaç fark vardır.

  • Verileri geri okumak için, D3D12_HEAP_TYPE_UPLOADyerine D3D12_HEAP_TYPED3D12_HEAP_TYPE_READBACKolarak ayarlanmış bir yığın oluşturursunuz.
  • Geri okuma yığınındaki kaynak her zaman bir D3D12_RESOURCE_DIMENSION_BUFFERolmalıdır.
  • GPU'nın bir çerçeveyi işlemeyi ne zaman tamamladuğunu algılamak için bir çit kullanırsınız (çıktı arabelleğinize veri yazmayı bitirdiğinde). Id3D12Resource::Mapyöntemi GPU ile eşitlenmediğinden (diğer bir, Direct3D 11 eşdeğeri eşitleme) bu önemlidir. Direct3D 12 Map çağrıları, NO_OVERWRITE bayrağıyla direct3D 11 eşdeğerini çağırmış gibi davranır.
  • Veriler hazır olduktan sonra (gerekli tüm kaynak engelleri dahil), geri okuma verilerini CPU'ya görünür hale getirmek için ID3D12Resource::Mapçağrısı yapın.

Kod örneği

Aşağıdaki kod örneği, bir arabellek aracılığıyla GPU'dan CPU'ya veri okuma işleminin genel ana hattını gösterir.


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

İşleme hedef dokusunu okuyan ve bunu diske dosya olarak yazan ekran görüntüsü yordamının tam uygulaması için bkz. DX12 için DirectX Tool KitScreenGrab.