diff --git a/Engine/Graphics/Direct3D12/D3D12Resource.cpp b/Engine/Graphics/Direct3D12/D3D12Resource.cpp index fc39172..1c58c65 100644 --- a/Engine/Graphics/Direct3D12/D3D12Resource.cpp +++ b/Engine/Graphics/Direct3D12/D3D12Resource.cpp @@ -194,6 +194,83 @@ d3d12_texture::release() } //////////// D3D12 RENDER TEXTURE //////////// +d3d12_render_texture::d3d12_render_texture(d3d12_texture_init_info info) + : _texture(info) +{ + assert(info.desc); + _mip_count = resource()->GetDesc().MipLevels; + assert(_mip_count && _mip_count <= d3d12_texture::max_mips); + + descriptor_heap& rtv_heap {core::rtv_heap()}; + D3D12_RENDER_TARGET_VIEW_DESC desc{}; + desc.Format = info.desc->Format; + desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipSlice = 0; + + auto *const device {core::device()}; + assert(device); + for(u32 i{0}; i<_mip_count;++i) + { + _rtv[i] = rtv_heap.allocate(); + device->CreateRenderTargetView(resource(), &desc, _rtv[i].cpu); + ++desc.Texture2D.MipSlice; + } +} + +void +d3d12_render_texture::release() +{ + for(u32 i{0}; i<_mip_count;++i) core::srv_heap().free(_rtv[i]); + _texture.release(); + _mip_count = 0; +} + +//////////// D3D12 DEPTH TEXTURE //////////// +d3d12_depth_buffer::d3d12_depth_buffer(d3d12_texture_init_info info) + : _texture(info) +{ + assert(info.desc); + const DXGI_FORMAT dsv_format {info.desc->Format}; + + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc{}; + if(info.desc->Format == DXGI_FORMAT_D32_FLOAT) + { + info.desc->Format = DXGI_FORMAT_R32_TYPELESS; + srv_desc.Format = DXGI_FORMAT_R32_FLOAT; + } + + srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srv_desc.Texture2D.MipLevels = 1; + srv_desc.Texture2D.MostDetailedMip = 0; + srv_desc.Texture2D.PlaneSlice = 0; + srv_desc.Texture2D.ResourceMinLODClamp = 0.f; + + assert(!info.srv_desc && !info.resource); + info.srv_desc = &srv_desc; + _texture = d3d12_texture(info); + + D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc{}; + dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsv_desc.Flags = D3D12_DSV_FLAG_NONE; + dsv_desc.Format = dsv_format; + dsv_desc.Texture2D.MipSlice = 0; + + _dsv = core::dsv_heap().allocate(); + auto *const device {core::device()}; + assert(device); + device->CreateDepthStencilView(resource(), &dsv_desc, _dsv.cpu); + + +} +void +d3d12_depth_buffer::release() +{ + core::dsv_heap().free(_dsv); + _texture.release(); + _dsv = {}; +} + } //XEngine::graphics::d3d12 \ No newline at end of file diff --git a/Engine/Graphics/Direct3D12/D3D12Resources.h b/Engine/Graphics/Direct3D12/D3D12Resources.h index 5d317c0..b8f01ee 100644 --- a/Engine/Graphics/Direct3D12/D3D12Resources.h +++ b/Engine/Graphics/Direct3D12/D3D12Resources.h @@ -435,6 +435,7 @@ public: constexpr static u32 max_mips{ 14 }; d3d12_texture() = default; explicit d3d12_texture(d3d12_texture_init_info info); + ~d3d12_texture() { release(); } DISABLE_COPY(d3d12_texture); constexpr d3d12_texture(d3d12_texture&& o) : _resource(o._resource), _srv(o._srv) //这些值只是指针和句柄,不需要move @@ -475,6 +476,86 @@ private: descriptor_handle _srv; }; +class d3d12_render_texture +{ +public: + d3d12_render_texture() = default; + explicit d3d12_render_texture(d3d12_texture_init_info info); + DISABLE_COPY(d3d12_render_texture); + ~d3d12_render_texture() { release(); } + constexpr d3d12_render_texture(d3d12_render_texture&& o) + : _texture{std::move(o._texture)}, _mip_count{o._mip_count} + { + for(u32 i = 0; i < o._mip_count; ++i) _rtv[i] = o._rtv[i]; + o.reset(); + } + constexpr d3d12_render_texture& operator=(d3d12_render_texture&& o) + { + assert(this != &o); + if(this != &o) + { + reset(); + move(o); + } + return *this; + } + + void release(); + constexpr u32 mip_count() const { return _mip_count; } + constexpr D3D12_CPU_DESCRIPTOR_HANDLE rtv(u32 mip) const { assert(mip < _mip_count); return _rtv[mip].cpu; } + constexpr descriptor_handle srv() const { return _texture.srv(); } + constexpr ID3D12Resource *const resource() const { return _texture.resource(); } +private: + constexpr void move(d3d12_render_texture& o) + { + _texture = std::move(o._texture); + for(u32 i = 0; i < o._mip_count; ++i) _rtv[i] = o._rtv[i]; + o.reset(); + } + + constexpr void reset() + { + for(u32 i = 0; i < _mip_count; ++i) _rtv[i] = {}; + _mip_count = 0; + } + + d3d12_texture _texture{}; + descriptor_handle _rtv[d3d12_texture::max_mips]{}; + u32 _mip_count{0}; +}; + +class d3d12_depth_buffer +{ +public : + d3d12_depth_buffer() = default; + explicit d3d12_depth_buffer(d3d12_texture_init_info info); + DISABLE_COPY(d3d12_depth_buffer); + ~d3d12_depth_buffer() { release(); } + constexpr d3d12_depth_buffer(d3d12_depth_buffer&& o) + : _texture{std::move(o._texture)}, _dsv(o._dsv) + { + o._dsv = {}; + } + constexpr d3d12_depth_buffer& operator=(d3d12_depth_buffer&& o) + { + assert(this != &o); + if(this != &o) + { + _texture = std::move(o._texture); + _dsv = o._dsv; + o._dsv = {}; + } + return *this; + } + + void release(); + constexpr D3D12_CPU_DESCRIPTOR_HANDLE dsv() const { return _dsv.cpu; } + constexpr descriptor_handle srv() const { return _texture.srv(); } + constexpr ID3D12Resource *const resource() const { return _texture.resource(); } +private: + d3d12_texture _texture{}; + descriptor_handle _dsv{}; +}; } // namespace XEngine::graphics::d3d12 diff --git a/docs/changelogs/2026-04/20260401-render-texture-depth-buffer.md b/docs/changelogs/2026-04/20260401-render-texture-depth-buffer.md new file mode 100644 index 0000000..367f021 --- /dev/null +++ b/docs/changelogs/2026-04/20260401-render-texture-depth-buffer.md @@ -0,0 +1,212 @@ +# 变更记录:渲染目标纹理与深度缓冲区实现 + +**提交日期**: 2026-04-01 +**提交哈希**: `57afd12` +**变更类型**: 功能新增 + +--- + +## 变更概述 + +本次提交实现了 `d3d12_render_texture`(渲染目标纹理)和 `d3d12_depth_buffer`(深度缓冲区)类,为纹理资源类添加了析构函数。 + +## 修改文件 + +| 文件 | 变更说明 | +|------|----------| +| `D3D12Resources.h` | 为纹理类添加析构函数,完善 `d3d12_render_texture` 和 `d3d12_depth_buffer` 类定义 | +| `D3D12Resource.cpp` | 实现 `d3d12_render_texture` 和 `d3d12_depth_buffer` 构造与释放逻辑 | + +--- + +## d3d12_render_texture 类 + +### 功能说明 + +渲染目标纹理类,支持多 Mip 级别的渲染目标视图(RTV): + +```cpp +class d3d12_render_texture +{ +public: + d3d12_render_texture() = default; + explicit d3d12_render_texture(d3d12_texture_init_info info); + ~d3d12_render_texture() { release(); } + + // 移动语义 + d3d12_render_texture(d3d12_render_texture&& o); + d3d12_render_texture& operator=(d3d12_render_texture&& o); + + // 禁用拷贝 + DISABLE_COPY(d3d12_render_texture); + + void release(); + u32 mip_count() const; + D3D12_CPU_DESCRIPTOR_HANDLE rtv(u32 mip) const; + descriptor_handle srv() const; + ID3D12Resource* resource() const; + +private: + d3d12_texture _texture{}; + descriptor_handle _rtv[d3d12_texture::max_mips]{}; // 每个 Mip 一个 RTV + u32 _mip_count{0}; +}; +``` + +### 构造流程 + +```cpp +d3d12_render_texture::d3d12_render_texture(d3d12_texture_init_info info) + : _texture(info) // 先创建基础纹理 +{ + // 获取 Mip 级别数 + _mip_count = resource()->GetDesc().MipLevels; + + // 为每个 Mip 级别创建 RTV + D3D12_RENDER_TARGET_VIEW_DESC desc{}; + desc.Format = info.desc->Format; + desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + + for(u32 i = 0; i < _mip_count; ++i) + { + _rtv[i] = rtv_heap.allocate(); + device->CreateRenderTargetView(resource(), &desc, _rtv[i].cpu); + ++desc.Texture2D.MipSlice; // 下一个 Mip 切片 + } +} +``` + +### 使用场景 + +- 离屏渲染(Render-to-Texture) +- 多级渐远纹理生成 +- 后处理效果 + +--- + +## d3d12_depth_buffer 类 + +### 功能说明 + +深度缓冲区类,封装深度模板视图(DSV)和着色器资源视图(SRV): + +```cpp +class d3d12_depth_buffer +{ +public: + d3d12_depth_buffer() = default; + explicit d3d12_depth_buffer(d3d12_texture_init_info info); + ~d3d12_depth_buffer() { release(); } + + // 移动语义 + d3d12_depth_buffer(d3d12_depth_buffer&& o); + d3d12_depth_buffer& operator=(d3d12_depth_buffer&& o); + + // 禁用拷贝 + DISABLE_COPY(d3d12_depth_buffer); + + void release(); + D3D12_CPU_DESCRIPTOR_HANDLE dsv() const; + descriptor_handle srv() const; + ID3D12Resource* resource() const; + +private: + d3d12_texture _texture{}; + descriptor_handle _dsv{}; +}; +``` + +### 构造流程 + +```cpp +d3d12_depth_buffer::d3d12_depth_buffer(d3d12_texture_init_info info) +{ + // 深度缓冲区需要特殊处理格式 + // DSV 使用 D32_FLOAT,SRV 使用 R32_FLOAT + + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc{}; + if(info.desc->Format == DXGI_FORMAT_D32_FLOAT) + { + info.desc->Format = DXGI_FORMAT_R32_TYPELESS; // 资源使用无类型格式 + srv_desc.Format = DXGI_FORMAT_R32_FLOAT; // SRV 使用浮点格式 + } + + // 创建纹理和 SRV + info.srv_desc = &srv_desc; + _texture = d3d12_texture(info); + + // 创建 DSV + D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc{}; + dsv_desc.Format = DXGI_FORMAT_D32_FLOAT; // DSV 使用深度格式 + dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + + _dsv = dsv_heap.allocate(); + device->CreateDepthStencilView(resource(), &dsv_desc, _dsv.cpu); +} +``` + +### 格式转换说明 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 深度缓冲区格式处理 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ 用户指定格式:DXGI_FORMAT_D32_FLOAT │ +│ │ │ +│ ▼ │ +│ 资源格式:DXGI_FORMAT_R32_TYPELESS(无类型) │ +│ │ │ +│ ┌──────────┴──────────┐ │ +│ ▼ ▼ │ +│ DSV 格式:D32_FLOAT SRV 格式:R32_FLOAT │ +│ (深度测试用) (着色器采样用) │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +**为什么要这样处理?** + +- 深度缓冲区需要作为着色器资源被采样(如阴影映射、SSAO) +- DSV 格式(D32_FLOAT)不能直接用于 SRV +- 使用 TYPELESS 格式允许同一资源创建不同格式的视图 + +--- + +## 析构函数添加 + +为所有纹理类添加了析构函数,确保资源自动释放: + +```cpp +class d3d12_texture { +public: + ~d3d12_texture() { release(); } + // ... +}; + +class d3d12_render_texture { +public: + ~d3d12_render_texture() { release(); } + // ... +}; + +class d3d12_depth_buffer { +public: + ~d3d12_depth_buffer() { release(); } + // ... +}; +``` + +--- + +## 后续工作 + +- [ ] 实现根签名和管线状态对象 +- [ ] 渲染第一个三角形 +- [ ] 实现常量缓冲区 + +--- + +## 相关文档 + +- [D3D12学习Wiki](../wiki/D3D12学习Wiki.md) diff --git a/docs/wiki/D3D12学习Wiki.md b/docs/wiki/D3D12学习Wiki.md index c110483..6923a93 100644 --- a/docs/wiki/D3D12学习Wiki.md +++ b/docs/wiki/D3D12学习Wiki.md @@ -778,6 +778,143 @@ ID3D12Resource* resource = texture.resource(); descriptor_handle srv = texture.srv(); ``` +### 7.12 渲染目标纹理(d3d12_render_texture) + +#### 功能说明 + +渲染目标纹理类,支持多 Mip 级别的渲染目标视图(RTV),用于离屏渲染: + +```cpp +class d3d12_render_texture +{ +public: + explicit d3d12_render_texture(d3d12_texture_init_info info); + ~d3d12_render_texture() { release(); } + + void release(); + u32 mip_count() const; + D3D12_CPU_DESCRIPTOR_HANDLE rtv(u32 mip) const; // 获取指定 Mip 的 RTV + descriptor_handle srv() const; // 获取 SRV + ID3D12Resource* resource() const; + +private: + d3d12_texture _texture{}; + descriptor_handle _rtv[d3d12_texture::max_mips]{}; // 每个 Mip 一个 RTV + u32 _mip_count{0}; +}; +``` + +#### 多 Mip RTV 创建 + +```cpp +d3d12_render_texture::d3d12_render_texture(d3d12_texture_init_info info) + : _texture(info) +{ + _mip_count = resource()->GetDesc().MipLevels; + + D3D12_RENDER_TARGET_VIEW_DESC desc{}; + desc.Format = info.desc->Format; + desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipSlice = 0; + + for(u32 i = 0; i < _mip_count; ++i) + { + _rtv[i] = rtv_heap.allocate(); + device->CreateRenderTargetView(resource(), &desc, _rtv[i].cpu); + ++desc.Texture2D.MipSlice; + } +} +``` + +#### 使用场景 + +| 场景 | 说明 | +|------|------| +| 离屏渲染 | 将场景渲染到纹理而非屏幕 | +| 多级渐远纹理 | 生成 Mip Chain | +| 后处理 | 渲染结果作为后处理输入 | + +### 7.13 深度缓冲区(d3d12_depth_buffer) + +#### 功能说明 + +深度缓冲区类,同时提供深度模板视图(DSV)和着色器资源视图(SRV): + +```cpp +class d3d12_depth_buffer +{ +public: + explicit d3d12_depth_buffer(d3d12_texture_init_info info); + ~d3d12_depth_buffer() { release(); } + + void release(); + D3D12_CPU_DESCRIPTOR_HANDLE dsv() const; // 深度模板视图 + descriptor_handle srv() const; // 着色器资源视图 + ID3D12Resource* resource() const; + +private: + d3d12_texture _texture{}; + descriptor_handle _dsv{}; +}; +``` + +#### 格式转换处理 + +深度缓冲区需要特殊处理格式,以支持同时作为 DSV 和 SRV 使用: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 深度缓冲区格式处理 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ 用户指定格式:DXGI_FORMAT_D32_FLOAT │ +│ │ │ +│ ▼ │ +│ 资源格式:DXGI_FORMAT_R32_TYPELESS(无类型) │ +│ │ │ +│ ┌──────────┴──────────┐ │ +│ ▼ ▼ │ +│ DSV 格式:D32_FLOAT SRV 格式:R32_FLOAT │ +│ (深度测试用) (着色器采样用) │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +#### 构造实现 + +```cpp +d3d12_depth_buffer::d3d12_depth_buffer(d3d12_texture_init_info info) +{ + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc{}; + if(info.desc->Format == DXGI_FORMAT_D32_FLOAT) + { + info.desc->Format = DXGI_FORMAT_R32_TYPELESS; + srv_desc.Format = DXGI_FORMAT_R32_FLOAT; + } + + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srv_desc.Texture2D.MipLevels = 1; + + info.srv_desc = &srv_desc; + _texture = d3d12_texture(info); + + D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc{}; + dsv_desc.Format = DXGI_FORMAT_D32_FLOAT; + dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + + _dsv = dsv_heap.allocate(); + device->CreateDepthStencilView(resource(), &dsv_desc, _dsv.cpu); +} +``` + +#### 使用场景 + +| 场景 | 说明 | +|------|------| +| 深度测试 | 作为 DSV 用于深度缓冲 | +| 阴影映射 | 作为 SRV 采样深度值 | +| SSAO | 采样深度重建位置 | + ## 8. 交换链(Swap Chain) ### 8.1 什么是交换链?