# RHI 模块严重问题:PipelineState 与 Shader 关系设计混乱 ## 问题严重程度 **严重级别**: 🔴 架构级缺陷(Critical) ## 问题定位 根据核心设计理念: > - **求同存异**:优先提取 API 共性作为核心抽象 > - **核心约束原则**:面向 D3D12/Vulkan 设计,参考 Unity RHI 当前设计存在一个**根本性的架构缺陷**。 ## 问题详述 ### `RHIDevice::CreatePipelineState()` 接口设计错误 ```cpp // engine/include/XCEngine/RHI/RHIDevice.h:41 virtual RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) = 0; ``` ### `GraphicsPipelineDesc` 缺少 Shader 字段 ```cpp // engine/include/XCEngine/RHI/RHITypes.h:309-320 struct GraphicsPipelineDesc { InputLayoutDesc inputLayout; RasterizerDesc rasterizerState; BlendDesc blendState; DepthStencilStateDesc depthStencilState; uint32_t topologyType = 0; uint32_t renderTargetCount = 1; uint32_t renderTargetFormats[8] = { 0 }; uint32_t depthStencilFormat = 0; uint32_t sampleCount = 1; // ❌ 缺少 Shader 字段! }; ``` ## 导致的严重后果 ### 1. D3D12 PSO 创建后立即无效 ```cpp // engine/src/RHI/D3D12/D3D12Device.cpp:434-444 RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& desc) { auto* pso = new D3D12PipelineState(m_device.Get()); pso->SetInputLayout(desc.inputLayout); // ... 设置各种状态 return pso; // ❌ 此时 m_vsBytecode 和 m_psBytecode 都是空的! } ``` 当调用 `EnsureValid()` 时: ```cpp // engine/src/RHI/D3D12/D3D12PipelineState.cpp:143-146 bool D3D12PipelineState::CreateD3D12PSO() { if (!m_vsBytecode.pShaderBytecode || !m_psBytecode.pShaderBytecode) { return false; // ❌ 直接失败! } // ... } ``` ### 2. 后端行为不一致,违反"求同存异"原则 | 后端 | `CreatePipelineState()` 返回后 `IsValid()` | |------|------------------------------------------| | D3D12 | `false` (需要额外设置 shader) | | OpenGL | `true` (OpenGL 不需要预编译 PSO) | 这完全违反了核心设计原则。 ### 3. 运行时状态污染 Shader 通过 `SetShaderBytecodes()` 在运行时注入: ```cpp // 需要外部代码手动调用 pso->SetShaderBytecodes(vsBytecode, psBytecode); // ❌ 语义混乱 pso->EnsureValid(); // ❌ 现在才能创建真正的 D3D12 PSO ``` ## 设计根源分析 ### 参考 Unity RHI 的正确做法 Unity 的 `PipelineState` 是 **Shader + RenderState** 的不可变组合: - 创建时必须提供完整的 shader 和 state - 创建后不可修改 - `IsValid()` 的语义是确定的 ### 当前设计的错误假设 把 Shader 和 PipelineState 分离,试图让 PSO 成为"可配置的 render state 容器",但这与 D3D12/Vulkan 的 PSO 概念完全冲突——在这些 API 中,**PSO 是 shader + state 的编译后不可变对象**。 ## 影响范围 1. **无法正确实现 SRP**:上层渲染管线无法可靠地预编译 PSO 2. **资源管理混乱**:PSO 何时真正创建?何时可以释放?语义不明确 3. **测试困难**:后端行为不一致,单元测试无法统一编写 4. **扩展性差**:未来添加 Vulkan 后端会遇到同样的问题 ## 建议修复方案 ### 方案 A:在 `GraphicsPipelineDesc` 中添加 Shader 字段 ```cpp struct GraphicsPipelineDesc { // ... 现有字段 RHIShader* vertexShader = nullptr; RHIShader* pixelShader = nullptr; RHIShader* geometryShader = nullptr; RHIShader* hullShader = nullptr; RHIShader* domainShader = nullptr; }; ``` ### 方案 B:创建专用的 ShaderProgram 类型 ```cpp struct ShaderProgramDesc { RHIShader* vertexShader = nullptr; RHIShader* pixelShader = nullptr; // ... }; struct GraphicsPipelineDesc { ShaderProgramDesc shaders; // 包含所有 shader InputLayoutDesc inputLayout; RasterizerDesc rasterizerState; BlendDesc blendState; DepthStencilStateDesc depthStencilState; // ... }; ``` ### 方案 C:分离 PSO 创建接口 ```cpp // 独立的 Compute PSO 创建 RHIPipelineState* CreateComputePipelineState(RHIShader* computeShader); // Graphics PSO 创建时必须提供 shader RHIPipelineState* CreateGraphicsPipelineState( const GraphicsPipelineDesc& desc, RHIShader* vertexShader, RHIShader* pixelShader ); ``` ## 相关文件 - `engine/include/XCEngine/RHI/RHIDevice.h` - `engine/include/XCEngine/RHI/RHITypes.h` - `engine/include/XCEngine/RHI/RHIPipelineState.h` - `engine/src/RHI/D3D12/D3D12Device.cpp` - `engine/src/RHI/D3D12/D3D12PipelineState.cpp` - `engine/src/RHI/OpenGL/OpenGLDevice.cpp` ## 总结 **`GraphicsPipelineDesc` 缺少 Shader 字段** 导致: 1. 抽象层无法正确表达 D3D12/Vulkan 的 PSO 概念 2. 后端行为不一致,违反"求同存异" 3. PSO 生命周期管理语义混乱 这是整个 RHI 模块**最严重的架构级缺陷**,应该优先修复。