Files
XCEngine/docs/issues/RHI_PipelineState_Shader_Missing.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

174 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 模块**最严重的架构级缺陷**,应该优先修复。