- 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.
5.0 KiB
5.0 KiB
RHI 模块严重问题:PipelineState 与 Shader 关系设计混乱
问题严重程度
严重级别: 🔴 架构级缺陷(Critical)
问题定位
根据核心设计理念:
- 求同存异:优先提取 API 共性作为核心抽象
- 核心约束原则:面向 D3D12/Vulkan 设计,参考 Unity RHI
当前设计存在一个根本性的架构缺陷。
问题详述
RHIDevice::CreatePipelineState() 接口设计错误
// engine/include/XCEngine/RHI/RHIDevice.h:41
virtual RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) = 0;
GraphicsPipelineDesc 缺少 Shader 字段
// 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 创建后立即无效
// 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() 时:
// 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() 在运行时注入:
// 需要外部代码手动调用
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 的编译后不可变对象。
影响范围
- 无法正确实现 SRP:上层渲染管线无法可靠地预编译 PSO
- 资源管理混乱:PSO 何时真正创建?何时可以释放?语义不明确
- 测试困难:后端行为不一致,单元测试无法统一编写
- 扩展性差:未来添加 Vulkan 后端会遇到同样的问题
建议修复方案
方案 A:在 GraphicsPipelineDesc 中添加 Shader 字段
struct GraphicsPipelineDesc {
// ... 现有字段
RHIShader* vertexShader = nullptr;
RHIShader* pixelShader = nullptr;
RHIShader* geometryShader = nullptr;
RHIShader* hullShader = nullptr;
RHIShader* domainShader = nullptr;
};
方案 B:创建专用的 ShaderProgram 类型
struct ShaderProgramDesc {
RHIShader* vertexShader = nullptr;
RHIShader* pixelShader = nullptr;
// ...
};
struct GraphicsPipelineDesc {
ShaderProgramDesc shaders; // 包含所有 shader
InputLayoutDesc inputLayout;
RasterizerDesc rasterizerState;
BlendDesc blendState;
DepthStencilStateDesc depthStencilState;
// ...
};
方案 C:分离 PSO 创建接口
// 独立的 Compute PSO 创建
RHIPipelineState* CreateComputePipelineState(RHIShader* computeShader);
// Graphics PSO 创建时必须提供 shader
RHIPipelineState* CreateGraphicsPipelineState(
const GraphicsPipelineDesc& desc,
RHIShader* vertexShader,
RHIShader* pixelShader
);
相关文件
engine/include/XCEngine/RHI/RHIDevice.hengine/include/XCEngine/RHI/RHITypes.hengine/include/XCEngine/RHI/RHIPipelineState.hengine/src/RHI/D3D12/D3D12Device.cppengine/src/RHI/D3D12/D3D12PipelineState.cppengine/src/RHI/OpenGL/OpenGLDevice.cpp
总结
GraphicsPipelineDesc 缺少 Shader 字段 导致:
- 抽象层无法正确表达 D3D12/Vulkan 的 PSO 概念
- 后端行为不一致,违反"求同存异"
- PSO 生命周期管理语义混乱
这是整个 RHI 模块最严重的架构级缺陷,应该优先修复。