Files
XCEngine/tests/RHI/D3D12/TEST_SPEC.md
ssdfasd 3cd3b04c7e D3D12: Add Screenshot wrapper overload and document known limitations
- 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
2026-03-20 17:36:51 +08:00

324 lines
8.2 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.
# 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)