Files
XCEngine/docs/used/RHI模块测试重构.md
ssdfasd 16e2065c6c Unified logging: Replace LogSystem with EditorConsoleSink
- Created EditorConsoleSink (implements ILogSink interface)
- EditorConsoleSink stores logs in memory buffer (max 1000 entries)
- Added to Debug::Logger in Application::Initialize()
- ConsolePanel now reads from EditorConsoleSink via static GetInstance()
- Removed separate LogSystem singleton
- Removed editor/src/Core/LogEntry.h (no longer needed)

Now Editor and Engine share the same Debug::Logger, with ConsolePanel
displaying logs via EditorConsoleSink.
2026-03-25 16:13:02 +08:00

24 KiB
Raw Blame History

最最最重要的是在重构RHI测试的过程中如果发现了RHI模块设计上的根本问题需要紧急向我汇报

RHI 模块单元测试重构计划

1. 项目背景

本文档分析 XCEngine RHI渲染硬件抽象层模块的三个单元测试层次的覆盖度和质量问题并提出重构建议。

1.1 测试层次结构

层次 位置 测试数量 特点
RHI 抽象层 tests/RHI/unit/ 75 tests × 2 backends = 150 参数化测试,跨 D3D12/OpenGL
D3D12 后端 tests/RHI/D3D12/unit/ ~58 tests 非参数化,直接测试 D3D12 API
OpenGL 后端 tests/RHI/OpenGL/unit/ ~58 tests 非参数化,直接测试 OpenGL API

1.2 当前测试文件分布

RHI 抽象层 (tests/RHI/unit/)

文件 测试数 测试类
test_device.cpp 8 RHIDevice
test_buffer.cpp 8 RHIBuffer
test_texture.cpp 5 RHITexture
test_swap_chain.cpp 4 RHISwapChain
test_command_list.cpp 14 RHICommandList
test_command_queue.cpp 6 RHICommandQueue
test_shader.cpp 7 RHIShader
test_fence.cpp 10 RHIFence
test_sampler.cpp 4 RHISampler
test_factory.cpp 5 RHIFactory
test_pipeline_state.cpp 10 RHIPipelineState
test_render_pass.cpp 10 RHIRenderPass
test_framebuffer.cpp 8 RHIFramebuffer
test_compute.cpp 8 Compute/Dispatch

D3D12 后端 (tests/RHI/D3D12/unit/)

文件 测试数 测试类/功能
test_device.cpp 6 D3D12Device
test_fence.cpp 9 D3D12Fence
test_command_queue.cpp 2 D3D12CommandQueue
test_command_allocator.cpp 3 D3D12CommandAllocator
test_command_list.cpp 2 D3D12CommandList
test_buffer.cpp 6 D3D12Buffer
test_texture.cpp 4 D3D12Texture
test_descriptor_heap.cpp 9 D3D12DescriptorHeap
test_shader.cpp 3 D3D12Shader (trivial)
test_root_signature.cpp 2 D3D12RootSignature
test_pipeline_state.cpp 2 D3D12 PSO (trivial)
test_views.cpp 4 RTV/DSV/CBV
test_swap_chain.cpp 5 D3D12SwapChain

OpenGL 后端 (tests/RHI/OpenGL/unit/)

文件 测试数 测试类/功能
test_device.cpp 2 OpenGLDevice
test_buffer.cpp 6 OpenGLBuffer
test_fence.cpp 8 OpenGLFence
test_texture.cpp 5 OpenGLTexture
test_shader.cpp 4 OpenGLShader
test_pipeline_state.cpp 3 OpenGLPipelineState
test_vertex_array.cpp 5 OpenGLVertexArray
test_command_list.cpp 9 OpenGLCommandList
test_render_target_view.cpp 4 OpenGLRenderTargetView
test_depth_stencil_view.cpp 4 OpenGLDepthStencilView
test_swap_chain.cpp 3 OpenGLSwapChain
test_sampler.cpp 4 OpenGLSampler

2. 严重问题P0 - 必须修复)

2.1 tests/RHI/unit/test_shader.cpp - 9个测试完全相同 已修复

状态: 已完成 (2026-03-25)

修复内容:

  1. Shader 编译抽象重构 - 扩展 ShaderCompileDesc 支持内嵌源码:

    struct ShaderCompileDesc {
        std::wstring fileName;           // 文件路径(可选)
        std::vector<uint8_t> source;     // 内嵌源码(可选)
        ShaderLanguage sourceLanguage;    // 源码语言HLSL/GLSL/SPIRV
        std::wstring entryPoint;         // Entry point 名称
        std::wstring profile;            // Profile
        std::vector<ShaderCompileMacro> macros;
    };
    
  2. 新增 ShaderLanguage 枚举:

    enum class ShaderLanguage : uint8_t {
        Unknown,
        HLSL,    // D3D11/D3D12
        GLSL,    // OpenGL/Vulkan
        SPIRV    // Vulkan (pre-compiled)
    };
    
  3. 测试重构 - 9个相同测试 → 7个有效测试

    • Shader_Compile_EmptyDesc_ReturnsNullptr - 空描述符测试
    • Shader_Compile_ValidVertexShader - 顶点着色器编译测试
    • Shader_Compile_ValidFragmentShader - 片段着色器编译测试
    • Shader_GetType_VertexShader - 获取顶点着色器类型
    • Shader_GetType_FragmentShader - 获取片段着色器类型
    • Shader_GetNativeHandle_ValidShader - 获取原生句柄
    • Shader_Shutdown_Invalidates - 关闭后验证失效

测试结果: 14/14 通过 (D3D12: 7, OpenGL: 7)


2.2 关键 RHI 抽象类完全没有测试

严重程度: 🔴 致命

问题描述:

以下 RHI 抽象类在 tests/RHI/unit/ 中完全没有测试:

说明 影响
RHIPipelineState 管线状态对象 无法验证 PSO 创建、配置、绑定
RHIPipelineLayout 管线布局 无法验证 descriptor layout
RHIDescriptorPool 描述符池 Descriptor 管理完全未覆盖
RHIDescriptorSet 描述符集 无法验证 descriptor 更新
RHIRenderPass 渲染通道 RenderPass API 完全未覆盖
RHIFramebuffer 帧缓冲 Framebuffer API 完全未覆盖

修复建议 - 新增 test_pipeline_state.cpp:

// 文件: tests/RHI/unit/test_pipeline_state.cpp
#include "fixtures/RHITestFixture.h"
#include "XCEngine/RHI/RHIPipelineState.h"
#include "XCEngine/RHI/RHIDevice.h"

using namespace XCEngine::RHI;

TEST_P(RHITestFixture, PipelineState_Create) {
    GraphicsPipelineDesc desc = {};
    // 配置基本描述符
    RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
    ASSERT_NE(pso, nullptr);
    pso->Shutdown();
    delete pso;
}

TEST_P(RHITestFixture, PipelineState_SetGet_RasterizerState) {
    GraphicsPipelineDesc desc = {};
    RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
    ASSERT_NE(pso, nullptr);
    
    RasterizerDesc rasterizer = {};
    rasterizer.cullMode = CullMode::Back;
    pso->SetRasterizerState(rasterizer);
    
    EXPECT_EQ(pso->GetRasterizerState().cullMode, CullMode::Back);
    pso->Shutdown();
    delete pso;
}

TEST_P(RHITestFixture, PipelineState_SetGet_BlendState) {
    // ...
}

TEST_P(RHITestFixture, PipelineState_SetGet_DepthStencilState) {
    // ...
}

TEST_P(RHITestFixture, PipelineState_Finalize) {
    GraphicsPipelineDesc desc = {};
    RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
    ASSERT_NE(pso, nullptr);
    
    bool finalized = pso->Finalize();
    EXPECT_TRUE(finalized);
    EXPECT_TRUE(pso->IsFinalized());
    
    pso->Shutdown();
    delete pso;
}

TEST_P(RHITestFixture, PipelineState_Bind_Unbind) {
    // ...
}

修复建议 - 新增 test_render_pass.cpp:

// 文件: tests/RHI/unit/test_render_pass.cpp
#include "fixtures/RHITestFixture.h"
#include "XCEngine/RHI/RHIRenderPass.h"

using namespace XCEngine::RHI;

TEST_P(RHITestFixture, RenderPass_Create) {
    AttachmentDesc colorAttachment = {};
    colorAttachment.format = Format::R8G8B8A8_UNorm;
    colorAttachment.loadOp = LoadAction::Clear;
    colorAttachment.storeOp = StoreAction::Store;
    
    RHIRenderPass* renderPass = GetDevice()->CreateRenderPass(1, &colorAttachment, nullptr);
    ASSERT_NE(renderPass, nullptr);
    
    EXPECT_EQ(renderPass->GetColorAttachmentCount(), 1);
    renderPass->Shutdown();
    delete renderPass;
}

TEST_P(RHITestFixture, RenderPass_BeginEnd) {
    // 需要先创建 framebuffer
    // cmdList->BeginRenderPass(renderPass, framebuffer, ...);
    // cmdList->EndRenderPass();
}

修复建议 - 新增 test_framebuffer.cpp:

// 文件: tests/RHI/unit/test_framebuffer.cpp
#include "fixtures/RHITestFixture.h"
#include "XCEngine/RHI/RHIFramebuffer.h"

using namespace XCEngine::RHI;

TEST_P(RHITestFixture, Framebuffer_Create) {
    // 先创建 renderPass 和 texture
    RHIRenderPass* renderPass = ...;
    RHITexture* texture = ...;
    RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(texture, {});
    
    RHIFramebuffer* fb = GetDevice()->CreateFramebuffer(renderPass, 1, &rtv, nullptr, 256, 256);
    ASSERT_NE(fb, nullptr);
    
    EXPECT_EQ(fb->GetWidth(), 256);
    EXPECT_EQ(fb->GetHeight(), 256);
    EXPECT_TRUE(fb->IsValid());
    
    fb->Shutdown();
    delete fb;
}

修复建议 - 新增 test_descriptor.cpp:

// 文件: tests/RHI/unit/test_descriptor.cpp
#include "fixtures/RHITestFixture.h"
#include "XCEngine/RHI/RHIDescriptorPool.h"
#include "XCEngine/RHI/RHIDescriptorSet.h"

using namespace XCEngine::RHI;

TEST_P(RHITestFixture, DescriptorPool_Create) {
    DescriptorPoolDesc desc = {};
    desc.maxSets = 10;
    desc.poolSize = 100;
    
    RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(desc);
    ASSERT_NE(pool, nullptr);
    pool->Shutdown();
}

TEST_P(RHITestFixture, DescriptorSet_Allocate_Update) {
    // 创建 pool
    RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(desc);
    
    // 创建 layout
    DescriptorSetLayoutDesc layoutDesc = {};
    DescriptorSetLayoutBinding binding = {};
    binding.binding = 0;
    binding.type = DescriptorType::CBV;
    binding.count = 1;
    layoutDesc.bindings = &binding;
    layoutDesc.bindingCount = 1;
    
    RHIDescriptorSet* set = GetDevice()->CreateDescriptorSet(pool, layoutDesc);
    ASSERT_NE(set, nullptr);
    
    EXPECT_EQ(set->GetBindingCount(), 1);
    
    set->Shutdown();
    pool->Shutdown();
}

3. 中等问题P1 - 应该修复)

3.1 tests/RHI/unit/test_command_list.cpp - 大量测试传递 nullptr

问题描述:

很多 CommandList 测试只验证调用不崩溃,不验证实际功能:

// 这些测试传递 nullptr无法验证真实功能
TEST_P(RHITestFixture, CommandList_ClearRenderTarget) {
    // ... 创建了 texture 但实际传递 nullptr
    cmdList->ClearRenderTarget(static_cast<RHIResourceView*>(nullptr), color);
    // 没有验证任何实际行为
}

TEST_P(RHITestFixture, CommandList_TransitionBarrier) {
    // 创建了 texture 但传递 nullptr
    cmdList->TransitionBarrier(static_cast<RHIResourceView*>(nullptr), ...);
}

TEST_P(RHITestFixture, CommandList_SetVertexBuffer_WithResourceView) {
    // 直接传递 nullptr
    RHIResourceView* buffer = nullptr;
    cmdList->SetVertexBuffers(0, 1, &buffer, nullptr, nullptr);
}

缺少的真实测试:

测试内容 状态 建议
有资源的 SetVertexBuffer 添加
有资源的 SetIndexBuffer 添加
有资源的 ClearRenderTarget 添加
BeginRenderPass/EndRenderPass 添加
Dispatch (计算着色器) 添加
SetGraphicsDescriptorSets 添加
SetComputeDescriptorSets 添加

修复建议:

// 新增真实资源测试
TEST_P(RHITestFixture, CommandList_SetVertexBuffer_WithRealBuffer) {
    // 1. 创建 buffer
    BufferDesc bufDesc = {};
    bufDesc.size = 1024;
    RHIBuffer* buffer = GetDevice()->CreateBuffer(bufDesc);
    ASSERT_NE(buffer, nullptr);
    
    // 2. 创建 cmdList 并设置
    RHICommandList* cmdList = GetDevice()->CreateCommandList({});
    cmdList->Reset();
    
    RHIResourceView* bufferView = buffer->GetView();
    cmdList->SetVertexBuffers(0, 1, &bufferView, nullptr, nullptr);
    
    cmdList->Close();
    
    // 3. 清理
    cmdList->Shutdown();
    buffer->Shutdown();
    delete buffer;
    delete cmdList;
}

TEST_P(RHITestFixture, CommandList_BeginEndRenderPass) {
    // 1. 创建 renderPass
    AttachmentDesc colorDesc = {};
    colorDesc.format = Format::R8G8B8A8_UNorm;
    RHIRenderPass* renderPass = GetDevice()->CreateRenderPass(1, &colorDesc, nullptr);
    ASSERT_NE(renderPass, nullptr);
    
    // 2. 创建 framebuffer
    TextureDesc texDesc = {};
    texDesc.width = 256;
    texDesc.height = 256;
    RHITexture* texture = GetDevice()->CreateTexture(texDesc);
    RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(texture, {});
    
    RHIFramebuffer* fb = GetDevice()->CreateFramebuffer(renderPass, 1, &rtv, nullptr, 256, 256);
    
    // 3. 测试 Begin/End
    RHICommandList* cmdList = GetDevice()->CreateCommandList({});
    cmdList->Reset();
    
    Rect renderArea = {0, 0, 256, 256};
    ClearValue clearValue = {};
    cmdList->BeginRenderPass(renderPass, fb, renderArea, 1, &clearValue);
    cmdList->EndRenderPass();
    
    cmdList->Close();
    
    // 清理
    cmdList->Shutdown();
    fb->Shutdown();
    delete fb;
    delete rtv;
    texture->Shutdown();
    delete texture;
    renderPass->Shutdown();
    delete renderPass;
}

TEST_P(RHITestFixture, CommandList_Dispatch) {
    // 1. 创建 compute shader
    ShaderCompileDesc csDesc = {};
    RHIShader* computeShader = GetDevice()->CompileShader(csDesc);
    // ...
    
    // 2. 创建并设置 compute pipeline
    RHIPipelineState* computePSO = GetDevice()->CreatePipelineState(computeDesc);
    computePSO->SetComputeShader(computeShader);
    computePSO->Finalize();
    
    // 3. 测试 Dispatch
    RHICommandList* cmdList = GetDevice()->CreateCommandList({});
    cmdList->Reset();
    cmdList->SetPipelineState(computePSO);
    cmdList->Dispatch(8, 8, 1);
    cmdList->Close();
    
    // 清理
    cmdList->Shutdown();
    computePSO->Shutdown();
    delete computePSO;
    computeShader->Shutdown();
    delete computeShader;
}

3.2 D3D12 后端测试问题

文件 问题 建议
test_pipeline_state.cpp 只测试 struct 默认值 添加真实 PSO 创建测试
test_shader.cpp 只做字符串比较 添加 shader 编译测试
test_root_signature.cpp 只测试空签名和 CBV 添加复杂参数测试
test_command_list.cpp 只有 2 个测试 补充 Reset/ClearRenderTargetView 等

修复建议 - test_pipeline_state.cpp:

// 当前只有 trivial 测试
TEST_F(D3D12TestFixture, PipelineState_Get_GraphicsPipelineDescDefaults) {
    D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
    // 只验证 struct 默认值
    EXPECT_EQ(psoDesc.PrimitiveTopologyType, ...);
}

// 应该添加
TEST_F(D3D12TestFixture, PipelineState_Create_GraphicsPipeline) {
    // 1. 创建 root signature
    D3D12_ROOT_SIGNATURE_DESC rootSigDesc = {};
    D3D12RootSignature rootSig;
    rootSig.Initialize(GetDevice()->GetDevice(), rootSigDesc);
    
    // 2. 创建 shader (需要 HLSL 源码或编译好的 bytecode)
    D3D12Shader* vs = new D3D12Shader();
    vs->CompileFromFile(L"shaders/vertex.cso");
    
    // 3. 创建 PSO
    D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
    psoDesc.pRootSignature = rootSig.GetRootSignature();
    psoDesc.VS = vs->GetBytecode();
    // ... 设置其他字段
    
    ID3D12PipelineState* d3d12PSO = nullptr;
    HRESULT hr = GetDevice()->GetDevice()->CreateGraphicsPipelineState(
        &psoDesc, IID_PPV_ARGS(&d3d12PSO));
    ASSERT_EQ(hr, S_OK);
    
    d3d12PSO->Release();
    rootSig.Shutdown();
}

3.3 OpenGL 后端测试问题

文件 问题 建议
test_command_list.cpp 缺少 SetShader/SetUniform 测试 添加
test_shader.cpp 无 compute shader 测试 添加 GL_COMPUTE_SHADER
无 compute 相关测试 缺少 Dispatch 测试 添加

修复建议:

// 新增 test_compute.cpp
TEST_F(OpenGLTestFixture, ComputeShader_Compile) {
    const char* computeSrc = R"(
        #version 460
        layout(local_size_x = 1, local_size_y = 1) in;
        void main() {
            // compute shader
        }
    )";
    
    OpenGLShader computeShader;
    bool compiled = computeShader.CompileCompute(computeSrc);
    EXPECT_TRUE(compiled);
}

TEST_F(OpenGLTestFixture, CommandList_Dispatch) {
    // 编译 compute shader
    OpenGLShader computeShader;
    computeShader.CompileCompute(computeSrc);
    
    // 创建 pipeline state
    OpenGLPipelineState pipeline;
    pipeline.SetComputeShader(&computeShader);
    pipeline.Apply();
    
    // 测试 Dispatch
    OpenGLCommandList cmdList;
    cmdList.Reset();
    cmdList.SetPipelineState(&pipeline);
    cmdList.Dispatch(8, 8, 1);
    cmdList.Close();
}

4. 测试覆盖度矩阵

4.1 RHI 抽象层覆盖度

RHI 抽象接口 覆盖状态 备注
Device 创建/初始化 已覆盖
Buffer 创建/映射 已覆盖
Texture 创建 已覆盖
SwapChain 已覆盖
CommandList 基础 ⚠️ 太弱 大部分传递 nullptr
CommandQueue 已覆盖
Fence 已覆盖
Sampler 已覆盖
Shader 编译 已覆盖 7个有效测试使用内嵌源码
PipelineState 已覆盖 10个测试已完成
PipelineLayout 无测试 必须添加
DescriptorPool 已覆盖 8个测试已完成
DescriptorSet ⚠️ 部分覆盖 OpenGL 需要 GL context
RenderPass 已覆盖 10个测试已完成
Framebuffer 已覆盖 8个测试已完成
Compute/Dispatch 已覆盖 8个测试已完成

4.2 D3D12 后端覆盖度

D3D12 特定功能 覆盖状态 备注
设备特性检测 已覆盖
Descriptor Heap 已覆盖
Command Allocator 已覆盖
Fence Timeline 已覆盖
RootSignature ⚠️ 只测试空签名和 CBV
PipelineState ⚠️ 只测试 struct 默认值
Shader ⚠️ 只做字符串比较
SwapChain 已覆盖
Views (RTV/DSV) 已覆盖

4.3 OpenGL 后端覆盖度

OpenGL 特定功能 覆盖状态 备注
Buffer (VBO/IBO/UBO) 已覆盖
Texture (2D/Cube) 已覆盖
VertexArray 已覆盖
Shader 编译 已覆盖
PipelineState 已覆盖
Sampler 已覆盖
Fence 已覆盖
SwapChain 已覆盖
Compute Shader 无测试 必须添加
Dispatch 无测试 必须添加
Memory Barrier 无测试 可选

5. 重构优先级总结

P0 - 必须修复(影响功能验证)

优先级 问题 工作量 影响 状态
1 Shader 测试重构 9个测试无效 已完成
2 添加 PipelineState 测试 RHI 核心组件无测试 已完成
3 添加 RenderPass 测试 重要 API 未覆盖 已完成
4 添加 Framebuffer 测试 重要 API 未覆盖 已完成

P1 - 应该修复(提高覆盖率)

优先级 问题 工作量 影响 状态
5 添加 DescriptorPool 测试 已实现未测试 已完成 (DescriptorPool)
5b DescriptorSet 测试 OpenGL 需要 GL context暂跳过 ⚠️ 待完成
6 CommandList 测试增强 大部分传递 nullptr 待完成
7 添加 Compute/Dispatch 测试 重要功能缺失 已完成
8 D3D12 PSO/shader 测试增强 当前测试 trivial 待完成

P2 - 可以修复(完善细节)

优先级 问题 工作量 影响
9 OpenGL CommandList SetShader 测试 缺失测试
10 复杂 RootSignature 参数测试 当前只测试 CBV
11 OpenGL Compute Shader 测试 缺失测试

6. 新增测试文件清单

文件路径 测试内容 优先级 状态
tests/RHI/unit/test_pipeline_state.cpp PipelineState 创建/配置/绑定 P0 已完成
tests/RHI/unit/test_render_pass.cpp RenderPass 创建/Begin/End P0 已完成
tests/RHI/unit/test_framebuffer.cpp Framebuffer 创建/绑定 P0 已完成
tests/RHI/unit/test_descriptor.cpp DescriptorPool 创建/更新 P1 DescriptorPool完成, Set待完成
tests/RHI/unit/test_compute.cpp Compute shader/Dispatch P1 已完成
tests/RHI/unit/test_pipeline_layout.cpp PipelineLayout 创建 P2 待完成

7. 测试质量改进建议

7.1 测试命名规范

遵循 Component_Category_SubBehavior 格式:

Good:
- Buffer_Create_DefaultHeap
- CommandList_SetViewport_ValidRect
- Shader_Compile_ValidSource

Bad:
- Test1
- BufferTest
- test_buffer

7.2 测试结构规范

每个测试应包含:

TEST_P(RHITestFixture, CommandList_SetVertexBuffer_WithRealBuffer) {
    // 1. Arrange - 准备测试数据
    BufferDesc bufDesc = {};
    bufDesc.size = 1024;
    RHIBuffer* buffer = GetDevice()->CreateBuffer(bufDesc);
    ASSERT_NE(buffer, nullptr);  // 使用 ASSERT 防止空指针解引用
    
    // 2. Act - 执行被测操作
    RHICommandList* cmdList = GetDevice()->CreateCommandList({});
    cmdList->Reset();
    RHIResourceView* view = buffer->GetView();
    cmdList->SetVertexBuffers(0, 1, &view, nullptr, nullptr);
    cmdList->Close();
    
    // 3. Assert - 验证结果
    // 注意:有些测试难以直接验证结果,可以通过不崩溃来间接验证
    
    // 4. Cleanup - 清理资源
    cmdList->Shutdown();
    delete cmdList;
    buffer->Shutdown();
    delete buffer;
}

7.3 避免的问题

// 问题1: 测试逻辑完全相同
TEST_P(RHITestFixture, Shader_Test1) { shader = nullptr; EXPECT_EQ(shader, nullptr); }
TEST_P(RHITestFixture, Shader_Test2) { shader = nullptr; EXPECT_EQ(shader, nullptr); } // 相同!

// 问题2: 传递 nullptr 不验证功能
TEST_P(RHITestFixture, CommandList_Test) {
    cmdList->ClearRenderTarget(nullptr, color);  // 无意义
}

// 问题3: 不清理资源
TEST_P(RHITestFixture, Buffer_Test) {
    RHIBuffer* buffer = device->CreateBuffer(desc);
    // 忘记 buffer->Shutdown() 和 delete buffer
}

// 问题4: 缺少 ASSERT
TEST_P(RHITestFixture, Buffer_Test) {
    RHIBuffer* buffer = device->CreateBuffer(desc);
    buffer->SetData(...);  // 如果 buffer 是 nullptr 则崩溃
    // 应该先 ASSERT_NE(buffer, nullptr);
}

8. 附录:测试执行命令

# 增量构建 RHI 测试
cmake --build . --target rhi_unit_tests --config Debug
cmake --build . --target rhi_d3d12_tests --config Debug
cmake --build . --target rhi_opengl_tests --config Debug

# 运行 RHI 抽象层测试 (同时验证 D3D12 和 OpenGL)
ctest -R "^D3D12/|^OpenGL/" -C Debug --output-on-failure

# 运行 D3D12 后端专用测试
ctest -R "D3D12TestFixture|SwapChainTestFixture" -C Debug --output-on-failure

# 运行 OpenGL 后端专用测试
ctest -R "OpenGLTestFixture" -C Debug --output-on-failure

# 运行所有 RHI 测试
ctest -R "D3D12|OpenGL|RHITestFixture" -C Debug --output-on-failure

文档版本: 1.4 最后更新: 2026-03-25 作者: XCEngine Team

更新日志

v1.4 (2026-03-25)

  • P1-7: Compute/Dispatch 测试 已完成
    • 新增 test_compute.cpp8个测试
    • 测试通过D3D12 8 + OpenGL 8 = 16 tests
    • 修复 shader type bugs:
      • D3D12Shader::Compile 不设置 m_type
      • OpenGLShader::Compile(const void*,...) 硬编码 Fragment
      • OpenGLShader::CompileCompute 不设置 m_type
    • 修复 D3D12CommandList::SetPipelineState 对 Compute PSO 用错 handle
  • 测试结果D3D12 116测试 + OpenGL 116测试 = 232测试全部通过
  • 集成测试8/8 全部通过

v1.3 (2026-03-25)

  • P1-5: DescriptorPool 测试 已完成
    • 新增 test_descriptor.cpp8个 DescriptorPool 测试
    • 测试通过D3D12 8 + OpenGL 8 = 16 tests
    • DescriptorSet 测试暂跳过OpenGL 需要 GL context
  • 测试结果D3D12 108测试 + OpenGL 108测试 = 216测试全部通过
  • 集成测试8/8 全部通过

v1.2 (2026-03-25)

  • P0-3: RenderPass 测试 已完成
    • 新增 test_render_pass.cpp10个测试
    • 添加 CreateRenderPass/CreateFramebufferRHIDevice 接口
    • 实现 D3D12 和 OpenGL 后端
    • 修复 D3D12 depth stencil 资源创建(自动设置 D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL
    • 修复 D3D12 RTV/DSV 空指针检查
  • P0-4: Framebuffer 测试 已完成
    • 新增 test_framebuffer.cpp8个测试
    • 修复 D3D12RenderPassStoreAndResolve 映射问题
  • 测试结果D3D12 100测试 + OpenGL 100测试 = 200测试全部通过
  • 集成测试8/8 全部通过

v1.1 (2026-03-25)

  • P0-1: Shader 测试重构 已完成
    • 添加 ShaderLanguage 枚举
    • 扩展 ShaderCompileDesc 支持内嵌源码
    • 9个相同测试 → 7个有效测试
  • P0-2: PipelineState 测试 已完成
    • 新增 test_pipeline_state.cpp
    • 修复 PSO 验证接口:IsFinalized/FinalizeIsValid/EnsureValid
    • 10个测试覆盖创建、配置、状态查询、生命周期

v1.0 (2026-03-25)

  • 初始版本