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

5.0 KiB
Raw Blame History

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 的 PipelineStateShader + RenderState 的不可变组合:

  • 创建时必须提供完整的 shader 和 state
  • 创建后不可修改
  • IsValid() 的语义是确定的

当前设计的错误假设

把 Shader 和 PipelineState 分离,试图让 PSO 成为"可配置的 render state 容器",但这与 D3D12/Vulkan 的 PSO 概念完全冲突——在这些 API 中,PSO 是 shader + state 的编译后不可变对象

影响范围

  1. 无法正确实现 SRP:上层渲染管线无法可靠地预编译 PSO
  2. 资源管理混乱PSO 何时真正创建?何时可以释放?语义不明确
  3. 测试困难:后端行为不一致,单元测试无法统一编写
  4. 扩展性差:未来添加 Vulkan 后端会遇到同样的问题

建议修复方案

方案 AGraphicsPipelineDesc 中添加 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.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 模块最严重的架构级缺陷,应该优先修复。