Files
DX12/docs/changelogs/2026-03/20260331-d3d12-swap-chain.md
SpecialX 95d8893182 feat(d3d12): 实现交换链与渲染表面管理
- 新增 d3d12_surface 类,管理交换链和渲染目标
- 实现三重缓冲后台缓冲区管理
- 添加视口和裁剪矩形配置
- 修复 GraphicsPlatformInterface.h 循环包含问题
- 添加完整的中文 Doxygen 注释
- 更新 D3D12 学习 Wiki,添加交换链章节
2026-03-31 11:12:11 +08:00

232 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 变更记录:交换链与渲染表面实现
**提交日期**: 2026-03-31
**提交哈希**: `待定`
**变更类型**: 功能新增
---
## 变更概述
本次提交实现了 D3D12 交换链Swap Chain和渲染表面管理完成了渲染输出的基础架构。同时修复了循环包含问题确保编译正确。
## 修改文件
### 新增文件
| 文件 | 说明 |
|------|------|
| `D3D12Surface.h` | 交换链和渲染目标管理类头文件 |
| `D3D12Surface.cpp` | 交换链实现 |
### 修改文件
| 文件 | 变更说明 |
|------|----------|
| `GraphicsPlatformInterface.h` | 修复循环包含,添加 `surface_id` 定义 |
| `Renderer.h` | 移除循环包含,保持类型定义 |
| `Renderer.cpp` | 实现表面相关函数 |
| `D3D12Core.h/cpp` | 添加描述符堆访问函数 |
| `D3D12Interface.cpp` | 更新平台接口 |
| `D3D12CommonHeader.h` | 编码修复 |
---
## 技术要点
### 1. 交换链Swap Chain原理
#### 什么是交换链?
交换链是 DXGI 提供的机制,用于管理前后缓冲区的交换:
```
┌─────────────────────────────────────────────────────────────┐
│ 交换链工作原理 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 后台缓冲 │ │ 后台缓冲 │ │ 后台缓冲 │ │
│ │ 0 │ │ 1 │ │ 2 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └─────────────┼─────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Present() │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 前台缓冲 │ ───► 显示器 │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
#### 三重缓冲优势
| 特性 | 说明 |
|------|------|
| **减少撕裂** | 前台缓冲独立于后台缓冲,避免部分更新 |
| **提高并行性** | CPU 可提前录制多帧命令 |
| **平滑帧率** | 缓冲区平滑帧时间波动 |
### 2. d3d12_surface 类设计
#### 核心职责
```cpp
class d3d12_surface
{
// 交换链管理
IDXGISwapChain4* _swap_chain;
// 渲染目标管理(每个后台缓冲区一个)
render_target_data _render_target_data[frame_buffer_count];
// 视口和裁剪
D3D12_VIEWPORT _viewport;
D3D12_RECT _scissor_rect;
};
```
#### 生命周期
```
构造 d3d12_surface(window)
create_swap_chain(factory, cmd_queue, format)
├─► 创建 IDXGISwapChain4
├─► 分配 RTV 描述符
└─► 初始化视口/裁剪矩形
渲染循环
├─► back_buffer() 获取当前缓冲区
├─► rtv() 获取渲染目标视图
└─► present() 呈现帧
析构 ~d3d12_surface()
└─► release() 释放资源
```
### 3. 交换链创建流程
```cpp
void d3d12_surface::create_swap_chain(...)
{
// 1. 配置交换链描述
DXGI_SWAP_CHAIN_DESC1 desc{};
desc.BufferCount = frame_buffer_count; // 3 个后台缓冲区
desc.Format = to_non_srgb(format); // 像素格式
desc.Width = _window.width();
desc.Height = _window.height();
desc.SampleDesc.Count = 1; // 禁用 MSAA
// 2. 创建交换链
factory->CreateSwapChainForHwnd(cmd_queue, hwnd, &desc, ...);
// 3. 禁用 Alt+Enter 全屏切换(由应用处理)
factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
// 4. 分配 RTV 描述符
for(u32 i = 0; i < frame_buffer_count; ++i)
{
_render_target_data[i].rtv = core::rtv_heap().allocate();
}
// 5. 创建渲染目标视图
finalize();
}
```
### 4. 渲染目标视图创建
```cpp
void d3d12_surface::finalize()
{
for(u32 i = 0; i < frame_buffer_count; ++i)
{
// 获取后台缓冲区资源
_swap_chain->GetBuffer(i, IID_PPV_ARGS(&data.resource));
// 创建渲染目标视图
D3D12_RENDER_TARGET_VIEW_DESC desc{};
desc.Format = core::default_render_target_format();
desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
core::device()->CreateRenderTargetView(data.resource, &desc, data.rtv.cpu);
}
// 设置视口和裁剪矩形
_viewport = {0, 0, (float)width, (float)height, 0.0f, 1.0f};
_scissor_rect = {0, 0, (s32)width, (s32)height};
}
```
### 5. 循环包含修复
#### 问题
```
GraphicsPlatformInterface.h → Renderer.h → GraphicsPlatformInterface.h (循环!)
```
#### 解决方案
`surface_id` 定义移到 `Renderer.h``GraphicsPlatformInterface.h` 包含 `Renderer.h`
```
Renderer.h (定义 surface_id)
GraphicsPlatformInterface.h (使用 surface_id)
```
---
## 视口与裁剪矩形
### 视口Viewport
```cpp
D3D12_VIEWPORT _viewport{
.TopLeftX = 0.0f,
.TopLeftY = 0.0f,
.Width = (float)width,
.Height = (float)height,
.MinDepth = 0.0f,
.MaxDepth = 1.0f
};
```
定义光栅化阶段的渲染区域和深度范围。
### 裁剪矩形Scissor Rect
```cpp
D3D12_RECT _scissor_rect{0, 0, (s32)width, (s32)height};
```
定义像素输出的裁剪区域,区域外的像素将被丢弃。
---
## 后续工作
- [ ] 实现深度模板视图
- [ ] 渲染第一个三角形
- [ ] 实现根签名和管线状态对象
---
## 相关文档
- [D3D12学习Wiki](../wiki/D3D12学习Wiki.md)