Files
XCEngine/docs/issues/RHI_PipelineState_Shader_Missing.md

174 lines
5.0 KiB
Markdown
Raw Normal View History

# 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 模块**最严重的架构级缺陷**,应该优先修复。