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访问权限。因此需要拆分资源,分别处理深度写入和上采样操作:
- 创建独立的深度模板缓冲区:仅用于光栅化阶段的深度测试与写入,不开启UAV权限。
- 创建独立的可读写纹理:开启
ALLOW_UNORDERED_ACCESS标志,作为上采样的目标载体。 - 数据流转:光栅化完成后,将深度缓冲区的内容复制到可读写纹理,再执行上采样计算。
修改后的代码示例:
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限制:
- 创建深度纹理(格式
GL_DEPTH_COMPONENT32F),用于光栅化的深度测试与写入。 - 创建浮点纹理(格式
GL_R32F),开启读写权限(OpenGL中可绑定为图像纹理GL_IMAGE_2D),作为上采样目标。 - 光栅化完成后,将深度纹理内容复制到浮点纹理,再执行上采样计算。
这种拆分方式在DX12和OpenGL中均适用,可复用大部分管线逻辑。
内容的提问来源于stack exchange,提问作者TheChamp
相关产品推荐
相关产品推荐

