首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在directx12中将深度缓冲区值读取回CPU

在directx12中将深度缓冲区值读取回CPU
EN

Stack Overflow用户
提问于 2020-12-28 12:56:11
回答 1查看 714关注 0票数 0

我希望将深度缓冲区的内容复制回CPU,以便能够读取它们。

我以以下方式创建深度缓冲区(视图):

代码语言:javascript
运行
复制
// 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());
}

对于管道,我对深度缓冲区使用以下描述:

代码语言:javascript
运行
复制
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,我可以看到,在完成呈现传递之后,正确的值将存储在深度缓冲区中。

现在,如果我使用: D3D12_HEAP_PROPERTIES readbackHeapProperties{ D3D12_HEAP_PROPERTIES},我想将这些值读入CPU,在那里遇到问题;

堆类型readback我不能分配与深度缓冲区相同的描述的缓冲区。但是如果我使用CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),我以后就无法“映射”内存(根据microsoft文档https://learn.microsoft.com/en-us/windows/win32/direct3d12/readback-data-using-heaps)。

我要复制的其余部分类似于文档中的示例:

代码语言:javascript
运行
复制
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));

使深度缓冲区进入正确的状态。

代码语言:javascript
运行
复制
{
    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
);

将深度缓冲区转换为原始状态。

代码语言:javascript
运行
复制
{
    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);
}

我会感谢你的帮助!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-28 19:36:02

在DirectX 12中,您不会创建与GPU资源格式相同的“readback”缓冲区。相反,您只需创建一个与源的字节数相同的一维缓冲区。

“诀窍”是,你需要有与原始资源相同的音高。

代码语言:javascript
运行
复制
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是从原始资源获得的:

代码语言:javascript
运行
复制
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工具包中的DX12。

我还为那个Microsoft页面提交了一个编辑。它使用了一个缓冲区读取回缓冲区的示例,但没有提到读回资源始终是缓冲区的重要细节。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65477969

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档