# 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} $/run_integration_test.py $ minimal.ppm ${CMAKE_CURRENT_SOURCE_DIR}/minimal/GT_minimal.ppm 5 WORKING_DIRECTORY $ ) ``` ### 3.4 Golden Image 规范 | 属性 | 值 | |------|-----| | 格式 | PPM (P6) | | 命名 | `GT_.ppm` | | 阈值 | 默认 5% | | 存储位置 | `tests/RHI/D3D12/integration//` | ### 3.5 Golden Image 生成流程 1. 在干净硬件环境运行集成测试 2. 截图保存为 `GT_.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)