# 变更记录：Fence 同步机制实现

**提交日期**: 2026-03-27  
**提交哈希**: `b00a906`  
**变更类型**: 功能实现

---

## 变更概述

本次提交实现了 D3D12 Fence（围栏）同步机制，完成 CPU-GPU 帧同步，确保命令列表执行顺序正确，避免资源冲突。

## 修改文件

### Engine/Graphics/Direct3D12/

| 文件 | 变更说明 |
|------|----------|
| `D3D12Core.cpp` | 添加 Fence 同步机制，实现 `wait()`、`flush()` 方法 |

### EngineTest/

| 文件 | 变更说明 |
|------|----------|
| `TestRenderer.cpp` | 在 `run()` 中调用 `graphics::render()` |

---

## 技术要点

### 1. Fence 对象

```cpp
ID3D12Fence1* _fence{ nullptr };
u64 _fence_value{ 0 };
HANDLE _fence_event{ nullptr };
```

- **Fence**: GPU 可设置的计数器，用于同步
- **Fence Value**: 64位无符号整数，每帧递增
- **Fence Event**: Windows 事件对象，用于 CPU 等待

### 2. command_frame 结构

```cpp
struct command_frame
{
    ID3D12CommandAllocator* cmd_allocator{ nullptr };
    u64 fence_value{ 0 };  // 该帧的围栏值

    void wait(HANDLE fence_event, ID3D12Fence1* fence);
};
```

每帧记录其围栏值，用于判断 GPU 是否完成该帧。

### 3. 帧同步等待

```cpp
void wait(HANDLE fence_event, ID3D12Fence1* fence)
{
    if(fence->GetCompletedValue() < fence_value)
    {
        fence->SetEventOnCompletion(fence_value, fence_event);
        WaitForSingleObject(fence_event, INFINITE);
    }
}
```

- 检查 GPU 是否完成到目标围栏值
- 未完成则设置事件并等待

### 4. 帧结束信号

```cpp
void end_frame()
{
    // ... 提交命令列表 ...
    ++_fence_value;
    _cmd_frames[_frame_index].fence_value = _fence_value;
    _cmd_queue->Signal(_fence, _fence_value);
    _frame_index = (_frame_index + 1) % frame_buffer_count;
}
```

- 递增围栏值
- 记录当前帧的围栏值
- 向 GPU 发送信号

### 5. flush 方法

```cpp
void flush()
{
    for(u32 i{ 0 }; i < frame_buffer_count; ++i)
    {
        _cmd_frames[i].wait(_fence_event, _fence);
    }
    _frame_index = 0;
}
```

等待所有帧完成，用于资源释放前确保 GPU 完成。

---

## 同步流程

```
begin_frame()
    │
    ├─► 检查当前帧的 fence_value
    │
    └─► 如果 GPU 未完成，CPU 等待
            │
            └─► 重置分配器和命令列表

end_frame()
    │
    ├─► 提交命令列表
    │
    ├─► ++fence_value
    │
    ├─► 记录当前帧的 fence_value
    │
    ├─► Signal(fence, fence_value)
    │
    └─► 递增帧索引
```

---

## 围栏值溢出问题

```cpp
// 64位无符号整数，即便每秒1000帧，也需要5.8亿年才能回绕
u64 _fence_value{ 0 };
```

无需担心溢出问题。

---

## 后续工作

- [ ] 交换链实现
- [ ] 描述符堆
- [ ] 渲染目标视图

---

## 相关文档

- [D3D12学习Wiki](../wiki/D3D12学习Wiki.md)
