diff --git a/docs/D3D12后端测试设计.md b/docs/D3D12后端测试设计.md index 137fc301..c0a7bd7b 100644 --- a/docs/D3D12后端测试设计.md +++ b/docs/D3D12后端测试设计.md @@ -586,9 +586,804 @@ jobs: | D3D12Shader | ✓ | - | - | - | | RTV/DSV/SRV/UAV | ✓ | ✓ | ✓ | - | -## 10. 后续改进 +## 10. 组件详细测试用例设计 -- [ ] 实现所有组件的基础单元测试 +基于对所有 D3D12 组件源代码的深入分析,以下是每个组件的具体可测试 API 点和测试用例设计。 + +### 10.1 D3D12Device 测试 + +**文件**: `test_device.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_WithDebugLayer` | 启用 Debug Layer 后设备创建成功 | +| 初始化 | `Initialize_WithoutDebugLayer` | 不启用 Debug Layer 正常创建 | +| 初始化 | `Initialize_InvalidAdapter` | 无效适配器返回失败 | +| 适配器 | `EnumerateAdapters_ReturnsValidList` | 返回至少一个适配器 | +| 适配器 | `EnumerateAdapters_ContainsRequiredInfo` | 适配器信息包含 Name/VRAM | +| 特性查询 | `CheckFeatureSupport_FeatureLevels` | 查询支持的特性等级 | +| 特性查询 | `CheckFeatureSupport_D3D12Options` | 查询 D3D12 选项支持 | +| 描述符 | `GetDescriptorHandleIncrementSize_RTV` | RTV 描述符增量大小正确 | +| 描述符 | `GetDescriptorHandleIncrementSize_DSV` | DSV 描述符增量大小正确 | +| 描述符 | `GetDescriptorHandleIncrementSize_CBV_SRV_UAV` | SRV/CBV/UAV 增量正确 | +| 工厂方法 | `CreateCommandQueue_ReturnsValidObject` | 创建命令队列成功 | +| 工厂方法 | `CreateBuffer_ReturnsValidObject` | 创建 Buffer 成功 | +| 工厂方法 | `CreateTexture_ReturnsValidObject` | 创建 Texture 成功 | +| 工厂方法 | `CreateDescriptorHeap_ReturnsValidObject` | 创建描述符堆成功 | +| 工厂方法 | `CreatePipelineState_ReturnsValidObject` | 创建 PSO 成功 | +| 工厂方法 | `CreateRootSignature_ReturnsValidObject` | 创建根签名成功 | +| 设备状态 | `SetDeviceRemoved_MarksAsRemoved` | 设备移除标记正确 | +| 设备状态 | `IsDeviceRemoved_ReturnsCorrectState` | 移除状态查询正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12Device, Initialize_WithDebugLayer_Success) { + D3D12Device device; + bool result = device.Initialize(true); + + ASSERT_TRUE(result); + ASSERT_NE(device.GetDevice(), nullptr); + + // 验证 Debug Layer 已启用 + ComPtr debugDevice; + if (SUCCEEDED(device.GetDevice()->QueryInterface(IID_PPV_ARGS(&debugDevice)))) { + ASSERT_NE(debugDevice.Get(), nullptr); + } + + device.Shutdown(); +} + +TEST(D3D12Device, EnumerateAdapters_ContainsValidInfo) { + D3D12Device device; + device.Initialize(); + + auto adapters = device.EnumerateAdapters(); + + ASSERT_FALSE(adapters.empty()); + for (const auto& info : adapters) { + EXPECT_FALSE(info.name.empty()); + EXPECT_GE(info.vram, 0); + } +} + +TEST(D3D12Device, CreateBuffer_FactoryMethod) { + D3D12Device device; + device.Initialize(); + + BufferDesc desc; + desc.size = 1024; + desc.usage = ResourceUsage::VertexBuffer; + + auto* buffer = device.CreateBuffer(desc); + ASSERT_NE(buffer, nullptr); + ASSERT_EQ(buffer->GetSize(), 1024); +} +``` + +--- + +### 10.2 D3D12CommandQueue 测试 + +**文件**: `test_command_queue.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_DirectQueue` | Direct 类型队列创建成功 | +| 初始化 | `Initialize_ComputeQueue` | Compute 类型队列创建成功 | +| 初始化 | `Initialize_CopyQueue` | Copy 类型队列创建成功 | +| 同步 | `Signal_SetsFenceValue` | Signal 设置围栏值 | +| 同步 | `Wait_BlocksUntilSignal` | Wait 阻塞直到信号 | +| 同步 | `SignalAndWait_Completes` | 信号后等待完成 | +| 同步 | `WaitForIdle_BlocksAllWork` | 等待空闲完成所有工作 | +| 查询 | `GetTimestampFrequency_ReturnsValid` | 时间戳频率有效 | +| 查询 | `GetType_ReturnsCorrect` | 队列类型正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12CommandQueue, Signal_SetsFenceValue) { + D3D12Fence fence; + fence.Initialize(GetDevice(), 0); + + GetCommandQueue()->Signal(fence.GetFence(), 1); + + // 需要等待完成 + fence.Wait(1); + EXPECT_EQ(fence.GetCompletedValue(), 1); +} + +TEST(D3D12CommandQueue, WaitForIdle_BlocksAllWork) { + // 先执行一些命令 + D3D12Buffer buffer; + buffer.Initialize(GetDevice(), 256, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_TYPE_UPLOAD); + + GetCommandList()->Close(); + ID3D12CommandList* lists[] = { GetCommandList() }; + GetCommandQueue()->ExecuteCommandLists(1, lists); + + // 等待空闲 + GetCommandQueue()->WaitForIdle(); + + // 验证完成 + EXPECT_TRUE(true); // 如果没崩溃说明成功 +} +``` + +--- + +### 10.3 D3D12CommandAllocator 测试 + +**文件**: `test_command_allocator.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_DirectType` | Direct 类型创建成功 | +| 初始化 | `Initialize_ComputeType` | Compute 类型创建成功 | +| 初始化 | `Initialize_CopyType` | Copy 类型创建成功 | +| 重置 | `Reset_AfterCommandList` | 命令列表执行后重置成功 | +| 状态 | `IsReady_BeforeAndAfterReset` | 重置前后状态正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12CommandAllocator, Reset_AfterCommandListExecution) { + D3D12CommandAllocator allocator; + allocator.Initialize(GetDevice(), CommandQueueType::Direct); + + // 执行命令列表 + GetCommandList()->Close(); + ID3D12CommandList* lists[] = { GetCommandList() }; + GetCommandQueue()->ExecuteCommandLists(1, lists); + WaitForGPU(); + + // 重置分配器 + allocator.Reset(); + + // 验证可以创建新的命令列表 + ComPtr newList; + HRESULT hr = GetDevice()->CreateCommandList( + 0, D3D12_COMMAND_LIST_TYPE_DIRECT, + allocator.GetCommandAllocator(), nullptr, + IID_PPV_ARGS(&newList) + ); + ASSERT_TRUE(SUCCEEDED(hr)); +} +``` + +--- + +### 10.4 D3D12CommandList 测试 + +**文件**: `test_command_list.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 生命周期 | `Initialize_CreatesValidList` | 创建成功 | +| 生命周期 | `Reset_ReusesAllocator` | 重置成功 | +| 生命周期 | `Close_BeforeExecute` | 关闭后可以执行 | +| 资源屏障 | `TransitionBarrier_ValidStates` | 状态转换正确 | +| 资源屏障 | `UAVBarrier_CreatesBarrier` | UAV 屏障创建 | +| 资源屏障 | `AliasBarrier_CreatesBarrier` | 别名屏障创建 | +| 状态设置 | `SetViewport_SetsCorrectValues` | 视口设置正确 | +| 状态设置 | `SetScissorRect_SetsCorrectValues` | 裁剪矩形设置正确 | +| 状态设置 | `SetPrimitiveTopology_TriangleList` | 图元拓扑设置 | +| 绘制 | `Draw_ValidParameters` | 绘制调用参数正确 | +| 绘制 | `DrawIndexed_ValidParameters` | 索引绘制调用正确 | +| 清除 | `ClearRenderTargetView_ClearsColor` | 清除颜色正确 | +| 清除 | `ClearDepthStencilView_ClearsDepth` | 清除深度模板正确 | +| 复制 | `CopyBuffer_TransfersData` | Buffer 复制正确 | +| 复制 | `CopyTexture_TransfersData` | Texture 复制正确 | +| 查询 | `BeginQuery_StartsQuery` | 查询开始 | +| 查询 | `EndQuery_EndsQuery` | 查询结束 | +| 查询 | `ResolveQueryData_CopiesResults` | 查询数据解析 | + +**测试代码示例**: + +```cpp +TEST(D3D12CommandList, TransitionBarrier_ValidStates) { + D3D12Buffer buffer; + buffer.Initialize(GetDevice(), 1024, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_TYPE_UPLOAD); + + // 从通用读取状态转换到渲染目标状态 + GetCommandList()->TransitionBarrier( + buffer.GetResource(), + ResourceStates::GenericRead, + ResourceStates::RenderTarget + ); + + GetCommandList()->Close(); + + // 执行命令 + ID3D12CommandList* lists[] = { GetCommandList() }; + GetCommandQueue()->ExecuteCommandLists(1, lists); + WaitForGPU(); + + // 成功执行无崩溃 + SUCCEED(); +} + +TEST(D3D12CommandList, ClearRenderTargetView_VerifyColor) { + // 创建渲染目标 + D3D12Texture rt; + D3D12DescriptorHeap heap; + heap.Initialize(GetDevice(), DescriptorHeapType::RTV, 1); + + // 简化测试:创建 RTV + // ... + + float clearColor[] = { 0.25f, 0.5f, 0.75f, 1.0f }; + GetCommandList()->ClearRenderTargetView( + heap.GetCPUDescriptorHandleForHeapStart(), + clearColor, 0, nullptr + ); + + GetCommandList()->Close(); + ID3D12CommandList* lists[] = { GetCommandList() }; + GetCommandQueue()->ExecuteCommandLists(1, lists); + WaitForGPU(); + + SUCCEED(); +} +``` + +--- + +### 10.5 D3D12Buffer 测试 + +**文件**: `test_buffer.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_DefaultHeap` | 默认堆创建成功 | +| 初始化 | `Initialize_UploadHeap` | 上传堆创建成功 | +| 初始化 | `Initialize_ReadbackHeap` | 回读堆创建成功 | +| 初始化 | `InitializeFromExisting_WrapsResource` | 包装现有资源 | +| 初始化 | `InitializeWithData_CopiesData` | 带数据初始化复制数据 | +| 数据操作 | `Map_ReturnsValidPointer` | Map 返回有效指针 | +| 数据操作 | `Unmap_ReleasesPointer` | Unmap 释放指针 | +| 数据操作 | `UpdateData_ModifiesContent` | 更新数据正确 | +| 属性 | `GetGPUVirtualAddress_ReturnsValid` | GPU 虚拟地址有效 | +| 属性 | `GetDesc_ReturnsCorrectDesc` | 描述符正确 | +| 属性 | `GetSize_ReturnsCorrectSize` | 大小正确 | +| 状态 | `GetState_ReturnsCurrent` | 状态查询正确 | +| 状态 | `SetState_ChangesState` | 状态设置正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12Buffer, Initialize_UploadHeap_MapsSuccessfully) { + D3D12Buffer buffer; + bool result = buffer.Initialize(GetDevice(), 1024, + D3D12_RESOURCE_STATE_GENERIC_READ, + D3D12_HEAP_TYPE_UPLOAD); + + ASSERT_TRUE(result); + + // Map 操作 + void* data = buffer.Map(0, nullptr); + ASSERT_NE(data, nullptr); + + // 写入测试数据 + memset(data, 0xAB, 1024); + buffer.Unmap(0, nullptr); + + // 再次 Map 验证 + data = buffer.Map(0, nullptr); + ASSERT_NE(data, nullptr); + + // 验证数据 + uint8_t* byteData = static_cast(data); + for (int i = 0; i < 1024; ++i) { + EXPECT_EQ(byteData[i], 0xAB); + } + + buffer.Unmap(0, nullptr); +} + +TEST(D3D12Buffer, InitializeWithData_DataIntegrity) { + const size_t dataSize = 256; + std::vector testData(dataSize); + for (size_t i = 0; i < dataSize; ++i) { + testData[i] = static_cast(i & 0xFF); + } + + D3D12Buffer buffer; + bool result = buffer.InitializeWithData( + GetDevice(), GetCommandList(), + testData.data(), dataSize, + ResourceStates::VertexAndConstantBuffer + ); + + ASSERT_TRUE(result); + + WaitForGPU(); + + // 验证 GPU 地址有效 + EXPECT_NE(buffer.GetGPUVirtualAddress(), 0); +} +``` + +--- + +### 10.6 D3D12Texture 测试 + +**文件**: `test_texture.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_2DTexture` | 2D 纹理创建成功 | +| 初始化 | `Initialize_3DTexture` | 3D 纹理创建成功 | +| 初始化 | `Initialize_CubeTexture` | 立方体纹理创建成功 | +| 初始化 | `Initialize_WithMipLevels` | 多 Mip 级别创建 | +| 初始化 | `Initialize_DepthStencil` | 深度模板纹理创建 | +| 初始化 | `InitializeFromData_CopiesPixels` | 带像素数据初始化 | +| 属性 | `GetWidth_ReturnsCorrect` | 宽度正确 | +| 属性 | `GetHeight_ReturnsCorrect` | 高度正确 | +| 属性 | `GetDepth_ReturnsCorrect` | 深度正确 | +| 属性 | `GetMipLevels_ReturnsCorrect` | Mip 级别数正确 | +| 属性 | `GetFormat_ReturnsCorrect` | 格式正确 | +| 状态 | `GetState_ReturnsCurrent` | 状态查询正确 | +| 状态 | `SetState_ChangesState` | 状态设置正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12Texture, Initialize_2DTexture_CorrectDimensions) { + D3D12Texture texture; + + D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex2D( + DXGI_FORMAT_R8G8B8A8_UNORM, 512, 512 + ); + + bool result = texture.Initialize(GetDevice(), desc, D3D12_RESOURCE_STATE_COMMON); + + ASSERT_TRUE(result); + EXPECT_EQ(texture.GetWidth(), 512); + EXPECT_EQ(texture.GetHeight(), 512); + EXPECT_EQ(texture.GetDepth(), 1); + EXPECT_EQ(texture.GetMipLevels(), 1); +} + +TEST(D3D12Texture, InitializeDepthStencil_CorrectFormat) { + D3D12Texture depthStencil; + bool result = depthStencil.InitializeDepthStencil( + GetDevice(), 1280, 720, DXGI_FORMAT_D24_UNORM_S8_UINT + ); + + ASSERT_TRUE(result); + EXPECT_EQ(depthStencil.GetFormat(), Format::D24_UNorm_S8_UInt); +} +``` + +--- + +### 10.7 D3D12DescriptorHeap 测试 + +**文件**: `test_descriptor_heap.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_RTVHeap` | RTV 堆创建成功 | +| 初始化 | `Initialize_DSVHeap` | DSV 堆创建成功 | +| 初始化 | `Initialize_CBV_SRV_UAVHeap` | CBV/SRV/UAV 堆创建 | +| 初始化 | `Initialize_SamplerHeap` | 采样器堆创建 | +| 初始化 | `Initialize_ShaderVisible` | 着色器可见堆创建 | +| 句柄 | `GetCPUDescriptorHandle_ValidIndex` | CPU 句柄正确 | +| 句柄 | `GetGPUDescriptorHandle_ValidIndex` | GPU 句柄正确 | +| 句柄 | `GetCPUDescriptorHandleForHeapStart` | 起始句柄正确 | +| 属性 | `GetDescriptorCount_ReturnsCorrect` | 描述符数量正确 | +| 属性 | `GetDescriptorSize_ReturnsCorrect` | 描述符大小正确 | +| 属性 | `GetType_ReturnsCorrect` | 类型正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12DescriptorHeap, Initialize_SRVHeapWithShaderVisible) { + D3D12DescriptorHeap heap; + bool result = heap.Initialize( + GetDevice(), + DescriptorHeapType::CBV_SRV_UAV, + 16, + true // shader visible + ); + + ASSERT_TRUE(result); + EXPECT_EQ(heap.GetDescriptorCount(), 16); + EXPECT_EQ(heap.GetType(), DescriptorHeapType::CBV_SRV_UAV); + + // 验证 GPU 句柄可用 + auto gpuHandle = heap.GetGPUDescriptorHandle(0); + EXPECT_NE(gpuHandle.ptr, 0); +} + +TEST(D3D12DescriptorHeap, GetDescriptorSize_MatchesIncrement) { + D3D12DescriptorHeap heap; + heap.Initialize(GetDevice(), DescriptorHeapType::RTV, 4); + + UINT incrementSize = GetDevice()->GetDescriptorHandleIncrementSize( + D3D12_DESCRIPTOR_HEAP_TYPE_RTV + ); + + EXPECT_EQ(heap.GetDescriptorSize(), incrementSize); +} +``` + +--- + +### 10.8 D3D12Shader 测试 + +**文件**: `test_shader.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 编译 | `CompileFromFile_VertexShader` | VS 编译成功 | +| 编译 | `CompileFromFile_PixelShader` | PS 编译成功 | +| 编译 | `CompileFromFile_GeometryShader` | GS 编译成功 | +| 编译 | `CompileFromFile_ComputeShader` | CS 编译成功 | +| 编译 | `CompileFromFile_InvalidFile` | 无效文件返回失败 | +| 编译 | `CompileFromFile_InvalidEntry` | 无效入口点返回失败 | +| 编译 | `CompileFromFile_InvalidTarget` | 无效目标返回失败 | +| 字节码 | `GetD3D12Bytecode_ReturnsValid` | 字节码有效 | +| 字节码 | `GetBytecodeSize_ReturnsNonZero` | 字节码大小非零 | +| 属性 | `GetType_ReturnsCorrect` | 类型正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12Shader, CompileFromFile_VertexShader_Success) { + D3D12Shader shader; + bool result = shader.CompileFromFile( + L"Res/Shader/test_vs.hlsl", + "main", + "vs_5_1" + ); + + ASSERT_TRUE(result); + EXPECT_EQ(shader.GetType(), ShaderType::Vertex); + EXPECT_GT(shader.GetBytecodeSize(), 0); +} + +TEST(D3D12Shader, CompileFromFile_InvalidFile_ReturnsFalse) { + D3D12Shader shader; + bool result = shader.CompileFromFile( + L"NonExistent.hlsl", + "main", + "vs_5_1" + ); + + EXPECT_FALSE(result); +} +``` + +--- + +### 10.9 D3D12PipelineState 测试 + +**文件**: `test_pipeline_state.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_GraphicsPipeline` | 图形管线创建成功 | +| 初始化 | `Initialize_ComputePipeline` | 计算管线创建成功 | +| 工厂方法 | `CreateDesc_ValidParameters` | 描述符创建正确 | +| 工厂方法 | `CreateInputElement_ValidParams` | 输入元素创建正确 | +| 属性 | `GetPipelineState_ReturnsValid` | PSO 对象有效 | +| 属性 | `GetType_ReturnsCorrect` | 类型正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12PipelineState, Initialize_GraphicsPipeline_Success) { + // 创建根签名 + D3D12RootSignature rootSig; + D3D12_ROOT_PARAMETER params[1] = {}; + params[0] = D3D12RootSignature::CreateCBV(0); + D3D12_ROOT_SIGNATURE_DESC rsDesc = D3D12RootSignature::CreateDesc(params, 1); + rootSig.Initialize(GetDevice(), rsDesc); + + // 编译简单 Shader + D3D12Shader vs, ps; + vs.CompileFromFile(L"Res/Shader/test_vs.hlsl", "main", "vs_5_1"); + ps.CompileFromFile(L"Res/Shader/test_ps.hlsl", "main", "ps_5_1"); + + // 创建 PSO + D3D12PipelineState pso; + auto desc = D3D12PipelineState::CreateDesc( + rootSig.GetRootSignature(), + vs.GetD3D12Bytecode(), + ps.GetD3D12Bytecode(), + {}, // GS + 0, nullptr // input elements + ); + + bool result = pso.Initialize(GetDevice(), desc); + ASSERT_TRUE(result); + ASSERT_NE(pso.GetPipelineState(), nullptr); +} +``` + +--- + +### 10.10 D3D12RootSignature 测试 + +**文件**: `test_root_signature.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_ValidDesc` | 有效描述符创建成功 | +| 初始化 | `Initialize_WithCBV` | 带 CBV 参数创建 | +| 初始化 | `Initialize_WithSRV` | 带 SRV 参数创建 | +| 初始化 | `Initialize_WithDescriptorTable` | 带描述符表创建 | +| 初始化 | `Initialize_WithStaticSampler` | 带静态采样器创建 | +| 工厂方法 | `CreateCBV_ReturnsValid` | CBV 创建正确 | +| 工厂方法 | `CreateSRV_ReturnsValid` | SRV 创建正确 | +| 工厂方法 | `CreateUAV_ReturnsValid` | UAV 创建正确 | +| 工厂方法 | `Create32BitConstants_ReturnsValid` | 常量创建正确 | +| 工厂方法 | `CreateDescriptorTable_ReturnsValid` | 描述符表创建正确 | +| 工厂方法 | `CreateSamplerDesc_ReturnsValid` | 采样器描述创建正确 | +| 属性 | `GetRootSignature_ReturnsValid` | 根签名对象有效 | +| 属性 | `GetParameterCount_ReturnsCorrect` | 参数数量正确 | + +**测试代码示例**: + +```cpp +TEST(D3D12RootSignature, Initialize_WithDescriptorTable) { + D3D12_DESCRIPTOR_RANGE ranges[1]; + ranges[0] = D3D12RootSignature::CreateDescriptorRange( + D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1 + ); + + D3D12_ROOT_PARAMETER params[1]; + params[0] = D3D12RootSignature::CreateDescriptorTable(1, ranges); + + D3D12_ROOT_SIGNATURE_DESC desc = D3D12RootSignature::CreateDesc(params, 1); + + D3D12RootSignature rootSig; + bool result = rootSig.Initialize(GetDevice(), desc); + + ASSERT_TRUE(result); + ASSERT_NE(rootSig.GetRootSignature(), nullptr); + EXPECT_EQ(rootSig.GetParameterCount(), 1); +} + +TEST(D3D12RootSignature, CreateSamplerDesc_AllParameters) { + auto desc = D3D12RootSignature::CreateSamplerDesc( + FilterMode::Linear, + TextureAddressMode::Clamp, + 16.0f + ); + + EXPECT_EQ(desc.Filter, D3D12_FILTER_MIN_MAG_MIP_LINEAR); + EXPECT_EQ(desc.AddressU, D3D12_TEXTURE_ADDRESS_MODE_CLAMP); + EXPECT_EQ(desc.MaxLOD, 16.0f); +} +``` + +--- + +### 10.11 视图测试 (RTV/DSV/SRV/UAV/CBV) + +**文件**: `test_views.cpp` + +**可测试 API 点**: + +| 组件 | 测试用例 | 验证内容 | +|------|----------|----------| +| RTV | `Initialize_2DTexture` | 2D 纹理 RTV 创建 | +| RTV | `CreateDesc_ValidFormat` | RTV 描述符创建 | +| DSV | `Initialize_DepthTexture` | 深度纹理 DSV 创建 | +| DSV | `CreateDesc_ValidFormat` | DSV 描述符创建 | +| SRV | `Initialize_Texture` | 纹理 SRV 创建 | +| SRV | `CreateDesc_WithMipLevels` | 带 Mip 级别 SRV | +| UAV | `Initialize_Buffer` | Buffer UAV 创建 | +| UAV | `Initialize_Texture` | Texture UAV 创建 | +| CBV | `Initialize_Buffer` | Buffer CBV 创建 | +| CBV | `Initialize_AutoDesc` | 自动描述符 CBV | + +**测试代码示例**: + +```cpp +TEST(D3D12RenderTargetView, Initialize_2DTexture_Success) { + D3D12Texture texture; + D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex2D( + DXGI_FORMAT_R8G8B8A8_UNORM, 256, 256 + ); + texture.Initialize(GetDevice(), desc); + + D3D12DescriptorHeap heap; + heap.Initialize(GetDevice(), DescriptorHeapType::RTV, 1); + + D3D12RenderTargetView rtv; + rtv.Initialize( + GetDevice(), + texture.GetResource(), + nullptr + ); + + EXPECT_NE(rtv.GetCPUDescriptorHandle().ptr, 0); +} + +TEST(D3D12DepthStencilView, Initialize_DepthTexture_Success) { + D3D12Texture depthTexture; + depthTexture.InitializeDepthStencil( + GetDevice(), 1280, 720, DXGI_FORMAT_D24_UNORM_S8_UINT + ); + + D3D12DescriptorHeap heap; + heap.Initialize(GetDevice(), DescriptorHeapType::DSV, 1); + + D3D12DepthStencilView dsv; + auto desc = D3D12DepthStencilView::CreateDesc(Format::D24_UNorm_S8_UInt); + dsv.Initialize( + GetDevice(), + depthTexture.GetResource(), + &desc + ); + + EXPECT_NE(dsv.GetCPUDescriptorHandle().ptr, 0); +} +``` + +--- + +### 10.12 D3D12Fence 测试 + +**文件**: `test_fence.cpp` + +**可测试 API 点**: + +| 测试类别 | 测试用例 | 验证内容 | +|----------|----------|----------| +| 初始化 | `Initialize_DefaultValue` | 默认初始值创建 | +| 初始化 | `Initialize_CustomValue` | 自定义初始值创建 | +| 同步 | `Signal_SetsValue` | Signal 设置值 | +| 同步 | `Wait_BlocksUntilSignaled` | Wait 阻塞等待 | +| 同步 | `GetCompletedValue_ReturnsCurrent` | 完成值查询 | +| 事件 | `GetEventHandle_ReturnsValid` | 事件句柄有效 | + +**测试代码示例**: + +```cpp +TEST(D3D12Fence, Signal_UpdatesCompletedValue) { + D3D12Fence fence; + fence.Initialize(GetDevice(), 0); + + GetCommandQueue()->Signal(fence.GetFence(), 5); + + fence.Wait(5); + + EXPECT_EQ(fence.GetCompletedValue(), 5); +} +``` + +--- + +### 10.13 类型转换测试 + +**文件**: `test_types.cpp` + +**可测试 API 点**: + +| 组件 | 测试用例 | 验证内容 | +|------|----------|----------| +| D3D12Enum | `ToD3D12_FillMode_All` | 所有填充模式转换 | +| D3D12Enum | `ToD3D12_CullMode_All` | 所有剔除模式转换 | +| D3D12Enum | `ToD3D12_ComparisonFunc_All` | 所有比较函数转换 | +| D3D12Enum | `ToD3D12_BlendOp_All` | 所有混合操作转换 | +| D3D12Enum | `ToD3D12_Format_Common` | 常用格式转换 | +| D3D12Enum | `ToD3D12_ResourceStates_All` | 所有资源状态转换 | +| D3D12Types | `ToD3D12_Viewport_Correct` | Viewport 转换正确 | +| D3D12Types | `ToD3D12_TextureDesc_Correct` | 纹理描述符转换正确 | +| D3D12Types | `ToD3D12_BufferDesc_Correct` | Buffer 描述符转换正确 | +| D3D12Common | `CheckFormatSupport_CommonFormats` | 常用格式支持检查 | +| D3D12Common | `IsRenderTargetFormatSupported_Common` | 渲染目标格式支持 | + +**测试代码示例**: + +```cpp +TEST(D3D12Enum, ToD3D12_FillMode_All) { + EXPECT_EQ(ToD3D12(FillMode::Wireframe), D3D12_FILL_MODE_WIREFRAME); + EXPECT_EQ(ToD3D12(FillMode::Solid), D3D12_FILL_MODE_SOLID); +} + +TEST(D3D12Enum, ToD3D12_ResourceStates_All) { + EXPECT_EQ(ToD3D12(ResourceStates::Common), D3D12_RESOURCE_STATE_COMMON); + EXPECT_EQ(ToD3D12(ResourceStates::RenderTarget), D3D12_RESOURCE_STATE_RENDER_TARGET); + EXPECT_EQ(ToD3D12(ResourceStates::DepthWrite), D3D12_RESOURCE_STATE_DEPTH_WRITE); + EXPECT_EQ(ToD3D12(ResourceStates::VertexAndConstantBuffer), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + EXPECT_EQ(ToD3D12(ResourceStates::IndexBuffer), D3D12_RESOURCE_STATE_INDEX_BUFFER); +} +``` + +--- + +## 11. 测试实现优先级 + +根据组件的依赖关系和重要性,建议按以下顺序实现测试: + +### Phase 1: 核心基础设施 (高优先级) + +1. **D3D12Device** - 所有其他组件依赖 +2. **D3D12CommandQueue** - 命令执行基础 +3. **D3D12CommandAllocator** - 命令分配基础 +4. **D3D12Fence** - 同步基础 + +### Phase 2: 资源管理 (中优先级) + +5. **D3D12Buffer** - 最常用的资源 +6. **D3D12Texture** - 纹理资源 +7. **D3D12DescriptorHeap** - 描述符管理 + +### Phase 3: 渲染管线 (中优先级) + +8. **D3D12Shader** - 着色器编译 +9. **D3D12RootSignature** - 根签名 +10. **D3D12PipelineState** - 管线状态 + +### Phase 4: 视图和命令 (低优先级) + +11. **RTV/DSV/SRV/UAV/CBV** - 各种视图 +12. **D3D12CommandList** - 命令录制 + +### Phase 5: 高级功能 (最低优先级) + +13. **D3D12SwapChain** - 需要窗口 +14. **D3D12Screenshot** - 截图功能 +15. **类型转换** - 辅助函数测试 + +--- + +## 12. 测试数据文件 + +测试所需资源文件应放在 `tests/D3D12/Res/` 目录: + +``` +tests/D3D12/Res/ +├── Shaders/ +│ ├── test_vs.hlsl # 测试用顶点着色器 +│ ├── test_ps.hlsl # 测试用像素着色器 +│ ├── test_gs.hlsl # 测试用几何着色器 +│ ├── test_cs.hlsl # 测试用计算着色器 +│ └── test_pattern.hlsl # 图案化测试着色器 +├── Textures/ +│ ├── test_256x256.png # 测试用 2D 纹理 +│ └── test_cube.dds # 测试用立方体纹理 +└── Golden/ + ├── clear_color_gt.ppm # 清除颜色基准图像 + ├── pattern_checker_gt.ppm # 棋盘格基准图像 + └── gradient_gt.ppm # 渐变基准图像 +``` + +--- + +## 13. 后续改进 + +- [ ] 实现 Phase 1 核心基础设施测试 +- [ ] 实现 Phase 2 资源管理测试 +- [ ] 实现 Phase 3 渲染管线测试 +- [ ] 实现 Phase 4 视图和命令测试 +- [ ] 实现 Phase 5 高级功能测试 - [ ] 添加资源泄漏检测工具 - [ ] 完善渲染结果测试图案 - [ ] 添加性能基准测试 diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12CommandAllocator.h b/engine/include/XCEngine/RHI/D3D12/D3D12CommandAllocator.h index c5dc4d17..8d2ea976 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12CommandAllocator.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12CommandAllocator.h @@ -3,7 +3,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h b/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h index 16850c3f..3d1bd51f 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h @@ -5,8 +5,8 @@ #include #include -#include "../Enums.h" -#include "../Types.h" +#include "../RHIEnums.h" +#include "../RHITypes.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12CommandQueue.h b/engine/include/XCEngine/RHI/D3D12/D3D12CommandQueue.h index a7e49d3b..aa78abad 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12CommandQueue.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12CommandQueue.h @@ -3,7 +3,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12DepthStencilView.h b/engine/include/XCEngine/RHI/D3D12/D3D12DepthStencilView.h index 8f08b2e8..7146398c 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12DepthStencilView.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12DepthStencilView.h @@ -3,7 +3,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h b/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h index fb7454d3..61058478 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h @@ -3,8 +3,8 @@ #include #include -#include "../Enums.h" -#include "../Types.h" +#include "../RHIEnums.h" +#include "../RHITypes.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h index 7afe497c..6b0d5b64 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h @@ -6,8 +6,8 @@ #include #include -#include "../Enums.h" -#include "../Types.h" +#include "../RHIEnums.h" +#include "../RHITypes.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Enum.h b/engine/include/XCEngine/RHI/D3D12/D3D12Enum.h index 0484507a..0328d27a 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Enum.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Enum.h @@ -2,7 +2,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" namespace XCEngine { namespace RHI { diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12PipelineState.h b/engine/include/XCEngine/RHI/D3D12/D3D12PipelineState.h index f33f6317..882a0718 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12PipelineState.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12PipelineState.h @@ -4,7 +4,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12RenderTargetView.h b/engine/include/XCEngine/RHI/D3D12/D3D12RenderTargetView.h index efff9450..b9ce40fc 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12RenderTargetView.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12RenderTargetView.h @@ -3,7 +3,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12RootSignature.h b/engine/include/XCEngine/RHI/D3D12/D3D12RootSignature.h index 0e314143..0dec1be3 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12RootSignature.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12RootSignature.h @@ -4,7 +4,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h b/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h index 989b5d71..26a5be4f 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h @@ -6,7 +6,7 @@ #include #include "D3D12Enum.h" -#include "../Types.h" +#include "../RHITypes.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12ShaderResourceView.h b/engine/include/XCEngine/RHI/D3D12/D3D12ShaderResourceView.h index beeeb5ed..53d04161 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12ShaderResourceView.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12ShaderResourceView.h @@ -3,7 +3,7 @@ #include #include -#include "../Enums.h" +#include "../RHIEnums.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Types.h b/engine/include/XCEngine/RHI/D3D12/D3D12Types.h index 571b7d3a..f80c3960 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Types.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Types.h @@ -2,7 +2,7 @@ #include -#include "../Types.h" +#include "../RHITypes.h" namespace XCEngine { namespace RHI { diff --git a/engine/include/XCEngine/RHI/Enums.h b/engine/include/XCEngine/RHI/RHIEnums.h similarity index 100% rename from engine/include/XCEngine/RHI/Enums.h rename to engine/include/XCEngine/RHI/RHIEnums.h diff --git a/engine/include/XCEngine/RHI/Types.h b/engine/include/XCEngine/RHI/RHITypes.h similarity index 100% rename from engine/include/XCEngine/RHI/Types.h rename to engine/include/XCEngine/RHI/RHITypes.h diff --git a/tests/D3D12/main.cpp b/tests/D3D12/main.cpp index 78db2667..32fef8f5 100644 --- a/tests/D3D12/main.cpp +++ b/tests/D3D12/main.cpp @@ -12,9 +12,9 @@ #include #include #include "stbi/stb_image.h" -#include "XCEngine/RHI/Enums.h" -#include "XCEngine/RHI/Types.h" -#include "XCEngine/RHI/Enums.h" +#include "XCEngine/RHI/RHIEnums.h" +#include "XCEngine/RHI/RHITypes.h" +#include "XCEngine/RHI/RHIEnums.h" #include "XCEngine/RHI/D3D12/D3D12Enum.h" #include "XCEngine/RHI/D3D12/D3D12Device.h" #include "XCEngine/RHI/D3D12/D3D12CommandQueue.h"