Files
XCEngine/docs/used/RHI_OpenGL_State_Not_Applied.md
2026-03-29 01:36:53 +08:00

3.9 KiB
Raw Blame History

RHI 模块严重问题OpenGL 后端 RHI 状态不生效

问题严重程度

严重级别: 🔴 Critical Bug

问题定位

OpenGLPipelineState 维护了两套状态系统,但它们之间没有关联。

两套状态系统

RHI 抽象层状态 (OpenGLPipelineState.h:131-133)

RasterizerDesc m_rasterizerDesc;
BlendDesc m_blendDesc;
DepthStencilStateDesc m_depthStencilDesc;

OpenGL 特定状态 (OpenGLPipelineState.h:141-143)

OpenGLDepthStencilState m_glDepthStencilState;
OpenGLBlendState m_glBlendState;
OpenGLRasterizerState m_glRasterizerState;

问题详述

RHI 接口设置的状态只存储不生效

// OpenGLPipelineState.cpp:19-21
void OpenGLPipelineState::SetRasterizerState(const RasterizerDesc& state) {
    m_rasterizerDesc = state;  // ❌ 只存储到 m_rasterizerDesc
}

void OpenGLPipelineState::SetBlendState(const BlendDesc& state) {
    m_blendDesc = state;  // ❌ 只存储到 m_blendDesc
}

void OpenGLPipelineState::SetDepthStencilState(const DepthStencilStateDesc& state) {
    m_depthStencilDesc = state;  // ❌ 只存储到 m_depthStencilDesc
}

Apply() 使用的是另一套状态

// OpenGLPipelineState.cpp:133-149
void OpenGLPipelineState::ApplyRasterizer() {
    if (m_glRasterizerState.cullFaceEnable) {  // ✅ 使用的是 m_glRasterizerState
        glEnable(GL_CULL_FACE);
        glCullFace(static_cast<GLenum>(m_glRasterizerState.cullFace));
        // ...
    }
}

void OpenGLPipelineState::ApplyBlend() {
    if (m_glBlendState.blendEnable) {  // ✅ 使用的是 m_glBlendState
        glEnable(GL_BLEND);
        // ...
    }
}

void OpenGLPipelineState::ApplyDepthStencil() {
    if (m_glDepthStencilState.depthTestEnable) {  // ✅ 使用的是 m_glDepthStencilState
        glEnable(GL_DEPTH_TEST);
        // ...
    }
}

导致的后果

通过 RHI 抽象层设置的状态完全不会生效!

// 上层代码
RasterizerDesc raster;
raster.cullMode = 2;  // 设置剔除模式
pso->SetRasterizerState(raster);  // 通过 RHI 接口设置

// 实际渲染时
pso->Bind();  // 调用 ApplyRasterizer()
// ❌ m_glRasterizerState.cullMode 仍然是默认值,不是设置的值!

对比 D3D12 后端

D3D12 后端正确地在 CreateD3D12PSO() 中使用了 RHI 状态:

// D3D12PipelineState.cpp:157-161
desc.RasterizerState.FillMode = static_cast<D3D12_FILL_MODE>(m_rasterizerDesc.fillMode);
desc.RasterizerState.CullMode = static_cast<D3D12_CULL_MODE>(m_rasterizerDesc.cullMode);
// ✅ 直接使用 m_rasterizerDesc

根本原因

OpenGL 后端有两个 SetRasterizerState 重载:

// RHI 接口 - 只存储
void SetRasterizerState(const RasterizerDesc& state);

// OpenGL 特定接口 - 会生效
void SetRasterizerState(const OpenGLRasterizerState& state);

RHI 接口的实现缺少状态转换逻辑。

修复方案

SetRasterizerState(const RasterizerDesc& state) 中添加转换逻辑:

void OpenGLPipelineState::SetRasterizerState(const RasterizerDesc& state) {
    m_rasterizerDesc = state;
    
    // 转换到 OpenGL 状态
    m_glRasterizerState.cullFaceEnable = (state.cullMode != 0);  // CullMode::None
    m_glRasterizerState.cullFace = static_cast<CullMode>(state.cullMode);
    m_glRasterizerState.frontFace = static_cast<FrontFace>(state.frontFace);
    m_glRasterizerState.polygonMode = static_cast<FillMode>(state.fillMode);
    m_glRasterizerState.depthClipEnable = state.depthClipEnable;
    // ... 其他字段
}

同样需要修复 SetBlendStateSetDepthStencilState

相关文件

  • engine/include/XCEngine/RHI/OpenGL/OpenGLPipelineState.h
  • engine/src/RHI/OpenGL/OpenGLPipelineState.cpp

影响范围

  1. 所有通过 RHI 抽象层设置的状态都不会生效
  2. OpenGL 集成测试能工作是因为使用了 OpenGL 特定 API
  3. 上层代码如果使用 RHI 接口,行为会与预期不符