You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DirectX 12中如何对深度纹理进行上采样?

深度缓冲区上采样的DX12实现问题与解决方案

我开发了一款图形应用,在渲染管线中需要将光栅化深度缓冲区上采样至更高分辨率,初始实现代码如下:

nbBool DX12Renderer::createDepthStencilBuffers(const Math::Uvec2& upsampledBufferSize)
{
    const DXGI_FORMAT format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;//DXGI_FORMAT_D32_FLOAT

    D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
    depthOptimizedClearValue.Format = format;
    depthOptimizedClearValue.DepthStencil.Depth = 1.0f;
    depthOptimizedClearValue.DepthStencil.Stencil = 0;

    HRESULT hr = D3D12Device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Tex2D(format, upsampledBufferSize.x, upsampledBufferSize.y, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL),
        D3D12_RESOURCE_STATE_DEPTH_WRITE,
        &depthOptimizedClearValue,
        IID_PPV_ARGS(&m_depthStencilBuffer)
    );

    Dx12TextureHandle dst;
    dst.buffer = m_depthStencilBuffer;
    dst.format = DXGI_FORMAT_R32_FLOAT;
    createUAV(D3D12_UAV_DIMENSION_TEXTURE2D, dst);// CreateUnorderedAccessView happens here.
}

运行代码时遇到两个DX12错误:

  • 错误1:D3D12 ERROR: ID3D12Device::CreateUnorderedAccessView: 对于资源格式D32_FLOAT_S8X24_UINT,创建D3D视图时,视图格式不能为R32_FLOAT。请查阅文档了解该资源格式对应的有效视图格式集合,确定资源(或其部分)在着色器中的呈现方式。[ STATE_CREATION ERROR #342: CREATEUNORDEREDACCESSVIEW_INVALIDFORMAT]
  • 错误2:D3D12 ERROR: ID3D12Device::CreateUnorderedAccessView: 无法为未指定D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS标志的资源创建无序访问视图。[ STATE_CREATION ERROR #340: CREATEUNORDEREDACCESSVIEW_INVALIDRESOURCE]

尝试修复时遇到的新问题

  • 修复错误1:由于纹理格式与视图格式不匹配,改用DXGI_FORMAT_D32_FLOAT深度格式搭配DXGI_FORMAT_R32_FLOAT视图解决了格式问题。
  • 修复错误2:添加D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS标志后,触发新错误:D3D12 ERROR: ID3D12Device::CreateCommittedResource: D3D12_RESOURCE_DESC::Flags不能同时设置D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL与D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET、D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS或D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS。[ STATE_CREATION ERROR #599: CREATERESOURCE_INVALIDMISCFLAGS]

解决方案

DX12专属方案

DX12的核心限制是:深度模板资源(带ALLOW_DEPTH_STENCIL标志)无法同时启用UAV访问权限。因此需要拆分资源,分别处理深度写入和上采样操作:

  1. 创建独立的深度模板缓冲区:仅用于光栅化阶段的深度测试与写入,不开启UAV权限。
  2. 创建独立的可读写纹理:开启ALLOW_UNORDERED_ACCESS标志,作为上采样的目标载体。
  3. 数据流转:光栅化完成后,将深度缓冲区的内容复制到可读写纹理,再执行上采样计算。

修改后的代码示例:

nbBool DX12Renderer::createDepthStencilBuffers(const Math::Uvec2& upsampledBufferSize)
{
    // 1. 创建光栅化专用的深度模板缓冲区
    const DXGI_FORMAT depthFormat = DXGI_FORMAT_D32_FLOAT;
    D3D12_CLEAR_VALUE depthClearValue = {};
    depthClearValue.Format = depthFormat;
    depthClearValue.DepthStencil.Depth = 1.0f;
    depthClearValue.DepthStencil.Stencil = 0;

    HRESULT hr = D3D12Device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Tex2D(depthFormat, upsampledBufferSize.x, upsampledBufferSize.y, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL),
        D3D12_RESOURCE_STATE_DEPTH_WRITE,
        &depthClearValue,
        IID_PPV_ARGS(&m_depthStencilBuffer)
    );
    if (FAILED(hr)) return false;

    // 创建深度视图,用于光栅化阶段绑定
    D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
    dsvDesc.Format = depthFormat;
    dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
    D3D12Device->CreateDepthStencilView(m_depthStencilBuffer, &dsvDesc, m_depthStencilViewHandle);

    // 2. 创建上采样专用的可读写纹理(支持UAV访问)
    const DXGI_FORMAT upsampleFormat = DXGI_FORMAT_R32_FLOAT;
    D3D12_CLEAR_VALUE upsampleClearValue = {};
    upsampleClearValue.Format = upsampleFormat;
    upsampleClearValue.Color[0] = 1.0f; // 初始化对应深度最大值

    hr = D3D12Device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Tex2D(upsampleFormat, upsampledBufferSize.x, upsampledBufferSize.y, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS),
        D3D12_RESOURCE_STATE_COMMON,
        &upsampleClearValue,
        IID_PPV_ARGS(&m_upsampledDepthBuffer)
    );
    if (FAILED(hr)) return false;

    // 创建UAV,用于上采样阶段写入
    Dx12TextureHandle dst;
    dst.buffer = m_upsampledDepthBuffer;
    dst.format = upsampleFormat;
    createUAV(D3D12_UAV_DIMENSION_TEXTURE2D, dst);

    return true;
}

后续管线流程:

  • 光栅化阶段绑定m_depthStencilViewHandle,将深度数据写入m_depthStencilBuffer。
  • 上采样前,将m_depthStencilBuffer的资源状态转换为D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,通过像素着色器采样深度视图并写入m_upsampledDepthBuffer的UAV;或直接使用CopyResource完成数据复制(需注意资源状态同步)。
  • 对m_upsampledDepthBuffer执行上采样滤波(如Compute Shader实现的双边滤波、高斯滤波等)。

跨平台通用方案(适配OpenGL)

核心逻辑与DX12一致,通过拆分资源规避API限制:

  1. 创建深度纹理(格式GL_DEPTH_COMPONENT32F),用于光栅化的深度测试与写入。
  2. 创建浮点纹理(格式GL_R32F),开启读写权限(OpenGL中可绑定为图像纹理GL_IMAGE_2D),作为上采样目标。
  3. 光栅化完成后,将深度纹理内容复制到浮点纹理,再执行上采样计算。

这种拆分方式在DX12和OpenGL中均适用,可复用大部分管线逻辑。


内容的提问来源于stack exchange,提问作者TheChamp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:43:14