- Add D3D12Screenshot::Capture(D3D12Device&, D3D12CommandQueue&, D3D12Texture&, const char*) wrapper overload - Update minimal integration test to use encapsulated APIs - Add DescriptorHeap wrapper unit tests - Document minimal GetBuffer native call as known limitation in TEST_SPEC.md
324 lines
8.2 KiB
Markdown
324 lines
8.2 KiB
Markdown
# D3D12 测试专项规范
|
||
|
||
本文档是 XCEngine 测试规范的 D3D12 专项补充。
|
||
|
||
**前置阅读**: [tests/TEST_SPEC.md](../TEST_SPEC.md) - 通用测试规范
|
||
|
||
---
|
||
|
||
## 1. 概述
|
||
|
||
### 1.1 D3D12 测试特点
|
||
|
||
| 特点 | 说明 |
|
||
|------|------|
|
||
| 硬件依赖 | 需要支持 D3D12 的显卡 |
|
||
| 窗口依赖 | 集成测试需要 GUI 窗口 |
|
||
| GPU 状态 | 测试间可能有 GPU 状态污染 |
|
||
|
||
### 1.2 测试层级
|
||
|
||
| 层级 | 位置 | 执行方式 | 框架 |
|
||
|------|------|----------|------|
|
||
| 单元测试 | `tests/RHI/D3D12/unit/` | CTest | Google Test |
|
||
| 集成测试 | `tests/RHI/D3D12/integration/` | CTest + Python | Python wrapper |
|
||
|
||
---
|
||
|
||
## 2. 单元测试规范
|
||
|
||
### 2.1 Fixture 设计
|
||
|
||
每个测试独立创建设备,避免 GPU 状态污染:
|
||
|
||
```cpp
|
||
class D3D12TestFixture : public ::testing::Test {
|
||
protected:
|
||
void SetUp() override; // 创建设备、命令队列等
|
||
void TearDown() override; // 清理资源
|
||
|
||
ID3D12Device* GetDevice();
|
||
ID3D12CommandQueue* GetCommandQueue();
|
||
ID3D12CommandAllocator* GetCommandAllocator();
|
||
ID3D12GraphicsCommandList* GetCommandList();
|
||
|
||
void WaitForGPU();
|
||
};
|
||
```
|
||
|
||
### 2.2 测试前缀对应
|
||
|
||
| 类名 | 测试前缀 |
|
||
|------|---------|
|
||
| D3D12Device | Device |
|
||
| D3D12CommandQueue | CommandQueue |
|
||
| D3D12CommandAllocator | CommandAllocator |
|
||
| D3D12CommandList | CommandList |
|
||
| D3D12Buffer | Buffer |
|
||
| D3D12Texture | Texture |
|
||
| D3D12DescriptorHeap | DescriptorHeap |
|
||
| D3D12Fence | Fence |
|
||
| D3D12PipelineState | PipelineState |
|
||
| D3D12RootSignature | RootSignature |
|
||
| D3D12Shader | Shader |
|
||
| D3D12RenderTargetView | RTV |
|
||
| D3D12DepthStencilView | DSV |
|
||
|
||
### 2.3 当前测试统计
|
||
|
||
| 组件 | 测试数 | 状态 |
|
||
|------|--------|------|
|
||
| Device | 6 | ✅ 通过 |
|
||
| Fence | 5 | ✅ 通过 |
|
||
| CommandQueue | 2 | ✅ 通过 |
|
||
| CommandAllocator | 3 | ✅ 通过 |
|
||
| CommandList | 2 | ✅ 通过 |
|
||
| Buffer | 5 | ✅ 通过 |
|
||
| Texture | 4 | ✅ 通过 |
|
||
| DescriptorHeap | 5 | ✅ 通过 |
|
||
| PipelineState | 2 | ✅ 通过 |
|
||
| RootSignature | 2 | ✅ 通过 |
|
||
| Shader | 3 | ✅ 通过 |
|
||
| Views | 4 | ✅ 通过 |
|
||
| **总计** | **44** | **全部通过** |
|
||
|
||
---
|
||
|
||
## 3. 集成测试规范
|
||
|
||
### 3.1 目录结构
|
||
|
||
每个集成测试独占一个子文件夹,资源相互隔离:
|
||
|
||
```
|
||
integration/
|
||
├── CMakeLists.txt # 构建配置
|
||
├── run_integration_test.py # 公共测试运行脚本
|
||
├── compare_ppm.py # PPM 图像比对脚本
|
||
├── run.bat # Windows 启动脚本
|
||
├── minimal/ # 最小化测试
|
||
│ ├── main.cpp
|
||
│ ├── GT_minimal.ppm
|
||
│ └── Res/
|
||
│ └── Shader/
|
||
│ ├── ndctriangle.hlsl
|
||
│ └── gs.hlsl
|
||
├── render_model/ # 模型渲染测试
|
||
│ ├── main.cpp
|
||
│ ├── GT.ppm
|
||
│ └── Res/
|
||
│ ├── Image/
|
||
│ ├── Model/
|
||
│ └── Shader/
|
||
└── triangle/ # 三角形渲染测试 (待实现)
|
||
├── main.cpp
|
||
├── GT_triangle.ppm
|
||
└── Res/
|
||
```
|
||
|
||
### 3.2 Python Wrapper
|
||
|
||
**位置**: `tests/RHI/D3D12/integration/run_integration_test.py`
|
||
|
||
**职责**:
|
||
1. 启动 D3D12 exe
|
||
2. 等待进程完成
|
||
3. 检查输出文件 (PPM 截图)
|
||
4. 调用 `compare_ppm.py` 比对 Golden Image
|
||
5. 返回 0(成功)/1(失败)
|
||
|
||
### 3.3 CTest 注册格式
|
||
|
||
```cmake
|
||
add_test(NAME D3D12_Minimal_Integration
|
||
COMMAND ${Python3_EXECUTABLE} $<TARGET_FILE_DIR:D3D12_Minimal>/run_integration_test.py
|
||
$<TARGET_FILE:D3D12_Minimal>
|
||
minimal.ppm
|
||
${CMAKE_CURRENT_SOURCE_DIR}/minimal/GT_minimal.ppm
|
||
5
|
||
WORKING_DIRECTORY $<TARGET_FILE_DIR:D3D12_Minimal>
|
||
)
|
||
```
|
||
|
||
### 3.4 Golden Image 规范
|
||
|
||
| 属性 | 值 |
|
||
|------|-----|
|
||
| 格式 | PPM (P6) |
|
||
| 命名 | `GT_<test_name>.ppm` |
|
||
| 阈值 | 默认 5% |
|
||
| 存储位置 | `tests/RHI/D3D12/integration/<test_name>/` |
|
||
|
||
### 3.5 Golden Image 生成流程
|
||
|
||
1. 在干净硬件环境运行集成测试
|
||
2. 截图保存为 `GT_<name>.ppm`
|
||
3. 人工验证截图正确性
|
||
4. 提交到版本控制
|
||
|
||
### 3.6 当前集成测试
|
||
|
||
| 测试名 | Golden Image | 状态 |
|
||
|--------|-------------|------|
|
||
| D3D12_Minimal_Integration | `minimal/GT_minimal.ppm` | ✅ 通过 |
|
||
| D3D12_RenderModel_Integration | `render_model/GT.ppm` | ❌ 待修复 |
|
||
| D3D12_Triangle_Integration | `triangle/GT_triangle.ppm` | 🔄 待实现 |
|
||
|
||
---
|
||
|
||
## 4. 测试执行
|
||
|
||
### 4.1 单元测试
|
||
|
||
```bash
|
||
# 方式 1: 使用统一脚本
|
||
python scripts/run_tests.py --unit-only
|
||
|
||
# 方式 2: 直接使用 CTest
|
||
cd build/tests/RHI/D3D12/unit
|
||
ctest -C Debug --output-on-failure
|
||
```
|
||
|
||
### 4.2 集成测试
|
||
|
||
```bash
|
||
# 方式 1: 使用统一脚本
|
||
python scripts/run_tests.py --integration
|
||
|
||
# 方式 2: 直接使用 CTest
|
||
cd build/tests/RHI/D3D12/integration
|
||
ctest -C Debug --output-on-failure
|
||
```
|
||
|
||
### 4.3 构建和测试
|
||
|
||
```bash
|
||
# 构建
|
||
cmake --build . --target D3D12_Minimal D3D12_RenderModel --config Debug
|
||
|
||
# 运行测试
|
||
python scripts/run_tests.py --build
|
||
```
|
||
|
||
---
|
||
|
||
## 5. CI 集成
|
||
|
||
### 5.1 GitHub Actions 配置
|
||
|
||
```yaml
|
||
name: D3D12 Tests
|
||
on: [push, pull_request]
|
||
|
||
jobs:
|
||
test:
|
||
runs-on: windows-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Configure CMake
|
||
run: cmake -B build -DCMAKE_BUILD_TYPE=Debug
|
||
|
||
- name: Build D3D12 Tests
|
||
run: cmake --build build --target D3D12_Minimal D3D12_RenderModel --config Debug
|
||
|
||
- name: Run Unit Tests
|
||
run: cd build/tests/RHI/D3D12/unit && ctest -C Debug --output-on-failure
|
||
|
||
- name: Run Integration Tests
|
||
run: python scripts/run_tests.py --integration
|
||
```
|
||
|
||
### 5.2 CI 模式
|
||
|
||
`--ci` 模式会跳过需要 GUI 的集成测试:
|
||
```bash
|
||
python scripts/run_tests.py --ci # 仅运行单元测试
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 文件结构
|
||
|
||
```
|
||
tests/RHI/D3D12/
|
||
├── CMakeLists.txt
|
||
├── TEST_SPEC.md # 本文档 (D3D12 专项)
|
||
├── TEST_IMPROVEMENT_PLAN.md # 改进计划
|
||
├── unit/
|
||
│ ├── CMakeLists.txt
|
||
│ ├── fixtures/
|
||
│ │ ├── D3D12TestFixture.h
|
||
│ │ └── D3D12TestFixture.cpp
|
||
│ ├── test_device.cpp
|
||
│ ├── test_buffer.cpp
|
||
│ └── ...
|
||
└── integration/
|
||
├── CMakeLists.txt
|
||
├── run_integration_test.py # 公共脚本
|
||
├── compare_ppm.py # 公共脚本
|
||
├── run.bat # 公共脚本
|
||
├── minimal/ # 测试子文件夹
|
||
│ ├── main.cpp
|
||
│ ├── GT_minimal.ppm
|
||
│ └── Res/
|
||
├── render_model/ # 测试子文件夹
|
||
│ ├── main.cpp # 有 API 问题,待修复
|
||
│ ├── GT.ppm
|
||
│ └── Res/
|
||
└── triangle/ # 测试子文件夹 (待实现)
|
||
├── main.cpp
|
||
├── GT_triangle.ppm
|
||
└── Res/
|
||
|
||
engine/
|
||
└── third_party/
|
||
└── stb/ # stb 图像库
|
||
├── stb_image.h
|
||
└── stb_image.cpp
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 已知问题
|
||
|
||
### 7.1 render_model API 不兼容
|
||
|
||
**问题**: `D3D12Buffer::Initialize` 和 `D3D12Screenshot::Capture` API 签名变更
|
||
|
||
**影响**: `D3D12_RenderModel_Integration` 无法编译
|
||
|
||
**状态**: 待修复
|
||
|
||
### 7.2 minimal GetBuffer 原生调用
|
||
|
||
**问题**: `minimal/main.cpp` 第 127-129 行仍使用原生 D3D12 API:
|
||
|
||
```cpp
|
||
ID3D12Resource* buffer = nullptr;
|
||
gSwapChain.GetSwapChain()->GetBuffer(i, IID_PPV_ARGS(&buffer));
|
||
gColorRTs[i].InitializeFromExisting(buffer);
|
||
```
|
||
|
||
**原因**: SwapChain back buffer 获取后需要通过 `InitializeFromExisting()` 绑定到已有的 `D3D12Texture` 对象。当前没有优雅的封装方案保留此语义。
|
||
|
||
**影响**: minimal 集成测试仍包含少量原生 D3D12 代码
|
||
|
||
**状态**: 标记为已知限制,暂不修复
|
||
|
||
---
|
||
|
||
## 8. 规范更新记录
|
||
|
||
| 版本 | 日期 | 变更 |
|
||
|------|------|------|
|
||
| 1.0 | 2026-03-20 | 初始版本 |
|
||
| 1.1 | 2026-03-20 | 添加 CI 集成章节,补充 Phase 5 内容 |
|
||
| 1.2 | 2026-03-20 | 重构集成测试目录结构,每个测试独立子文件夹,stb 库移至 engine/third_party/stb/ |
|
||
|
||
---
|
||
|
||
**规范版本**: 1.2
|
||
**最后更新**: 2026-03-20
|
||
**前置文档**: [tests/TEST_SPEC.md](../TEST_SPEC.md)
|