簡體   English   中英

在directx12中將深度緩沖區值讀回CPU

[英]Reading depth buffer values back to CPU in directx12

我想將深度緩沖區的內容復制回 CPU 以便能夠讀取它們。

我通過以下方式創建深度緩沖區(視圖):

// Create the depth stencil view.
{
    D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};
    depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
    depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
    depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE;

    D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
    depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;
    depthOptimizedClearValue.DepthStencil.Depth = 0.0f;
    depthOptimizedClearValue.DepthStencil.Stencil = 0;

    ThrowIfFailed(m_device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL),
        D3D12_RESOURCE_STATE_DEPTH_WRITE,
        &depthOptimizedClearValue,
        IID_PPV_ARGS(&m_depthStencil)
    ));

    NAME_D3D12_OBJECT(m_depthStencil);

    m_device->CreateDepthStencilView(m_depthStencil.Get(), &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
}

對於管道,我對深度緩沖區使用以下描述:

D3D12_DEPTH_STENCIL_DESC depthDesc;
ZeroMemory(&depthDesc, sizeof(D3D12_DEPTH_STENCIL_DESC));
depthDesc.DepthEnable = TRUE;
depthDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
depthDesc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
depthDesc.StencilEnable = FALSE;

到目前為止一切正常,使用 NSight,我可以看到在渲染通道完成后,正確的值存儲在深度緩沖區中。

現在我想將值讀回 CPU,如果我使用: D3D12_HEAP_PROPERTIES readbackHeapProperties{ CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK) };

堆類型回讀我無法分配與深度緩沖區具有相同描述的緩沖區。 但是,如果我稍后使用CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT)我無法“映射” memory(根據微軟文檔Z5E056C500A1C4B6A7110B50D807BADEwindow/docs.microsoft.com/en-uswindow/reads.microsoft.com/en-uswindow -堆

復制的 rest 我會模擬記錄的示例:

D3D12_RESOURCE_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc = m_depthStencil->GetDesc();

//D3D12_HEAP_PROPERTIES readbackHeapProperties{ CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK) };
//D3D12_RESOURCE_DESC readbackBufferDesc{ CD3DX12_RESOURCE_DESC::Buffer(500 * 500) };

D3D12_RESOURCE_DESC readbackBufferDesc = m_depthStencil->GetDesc();

ComPtr<ID3D12Resource> readbackBuffer;
ThrowIfFailed(m_device->CreateCommittedResource(
//&readbackHeapProperties,
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&readbackBufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
__uuidof(readbackBuffer),
&readbackBuffer));

將深度緩沖區帶入正確的 state。

{
    D3D12_RESOURCE_BARRIER outputBufferResourceBarrier
    {
        CD3DX12_RESOURCE_BARRIER::Transition(
            m_depthStencil.Get(),
            D3D12_RESOURCE_STATE_DEPTH_WRITE,
            D3D12_RESOURCE_STATE_COPY_SOURCE)
    };
    m_commandList->ResourceBarrier(1, &outputBufferResourceBarrier);
}

m_commandList->CopyResource(readbackBuffer.Get(), m_depthStencil.Get());

ThrowIfFailed(m_commandList->Close());

ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);



D3D12_RANGE readbackBufferRange{ 0, 500 * 500 }; // outputbuffer size = 500x500 = window size?
FLOAT* pReadbackBufferData{};
ThrowIfFailed(
    readbackBuffer->Map
    (
        0,
        &readbackBufferRange,
        reinterpret_cast<void**>(&pReadbackBufferData)
    )
);

D3D12_RANGE emptyRange{ 0, 0 };
readbackBuffer->Unmap
(
    0,
    &emptyRange
);

將深度緩沖區轉換為原始 state。

{
    D3D12_RESOURCE_BARRIER outputBufferResourceBarrier
    {
        CD3DX12_RESOURCE_BARRIER::Transition(
            m_depthStencil.Get(),
            D3D12_RESOURCE_STATE_COPY_SOURCE,
            D3D12_RESOURCE_STATE_DEPTH_WRITE)
    };
    m_commandList->ResourceBarrier(1, &outputBufferResourceBarrier);
}

我會很感激任何幫助!

在 DirectX 12 中,您不會創建與 GPU 資源格式相同的“回讀”緩沖區。 相反,您只需創建一個與源字節數相同的一維緩沖區。

“訣竅”是您需要與原始資源具有相同的音高。

CD3DX12_HEAP_PROPERTIES readBackHeapProperties(D3D12_HEAP_TYPE_READBACK);

// Readback resources must be buffers
D3D12_RESOURCE_DESC bufferDesc = {};
bufferDesc.DepthOrArraySize = 1;
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
bufferDesc.Height = 1;
bufferDesc.Width = srcPitch * m_height; // <<----
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
bufferDesc.MipLevels = 1;
bufferDesc.SampleDesc.Count = 1;

srcPitch是從原始資源中獲取的:

auto depthBufferDesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);

UINT64 totalResourceSize = 0;
UINT64 fpRowPitch = 0;
UINT fpRowCount = 0;
m_device->GetCopyableFootprints(
        &depthBufferDesc,
        0,
        1,
        0,
        nullptr,
        &fpRowCount,
        &fpRowPitch,
        &totalResourceSize);

// Round up the srcPitch to multiples of 256
UINT64 srcPitch = (fpRowPitch + 255) & ~0xFFu;

請參閱DirectX Tool Kit for DX12中的ScreenGrab

我還對該 Microsoft Docs 頁面進行了編輯。 它使用了一個緩沖區讀回緩沖區的示例,但沒有提到讀回資源始終是緩沖區的重要細節。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM