Files
XCEngine/.trae/documents/RHI模块审查报告.md
ssdfasd 008fb98dee refactor(editor): Complete architecture refactoring
- SceneManager: remove singleton, use dependency injection via EditorContext
- SelectionManager: already interface-based via ISelectionManager
- Panel: now receives IEditorContext for accessing managers
- HierarchyPanel: migrated to use IEditorContext instead of singletons
- Add ISceneManager interface and SceneManagerImpl
- EditorContextImpl: holds all editor subsystems

Architecture now follows dependency injection pattern:
Application -> EditorContext -> SceneManager/SelectionManager
EditorLayer -> Panels (receive context via SetContext)

All Manager singletons removed: EditorSceneManager::Get(), SelectionManager::Get()
2026-03-25 15:51:27 +08:00

467 lines
11 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 模块审查报告
## 审查范围
基于设计文档 `RHI模块总览.md` 中定义的设计理念,对当前 RHI 模块的设计和实现进行全面审查。
---
## 一、设计问题
### 1. 接口一致性问题
#### 1.1 RHIResource 基类接口过于简单
**当前实现** ([RHIResource.h](file:///d:/Xuanchi/Main/XCEngine/engine/include/XCEngine/RHI/RHIResource.h)):
```cpp
class RHIResource {
public:
virtual ~RHIResource() = default;
virtual void* GetNativeHandle() = 0;
virtual ResourceStates GetState() const = 0;
virtual void SetState(ResourceStates state) = 0;
};
```
**问题**:
- 缺少资源命名接口 (`SetName`/`GetName`)
- 缺少资源类型查询接口
- 缺少资源大小查询接口
**影响**: RHITexture 自行添加了 `SetName`/`GetName`/`GetWidth` 等方法,导致接口不统一。
**建议**: 扩展 RHIResource 基类接口:
```cpp
class RHIResource {
public:
virtual ~RHIResource() = default;
// 现有接口
virtual void* GetNativeHandle() = 0;
virtual ResourceStates GetState() const = 0;
virtual void SetState(ResourceStates state) = 0;
// 建议新增
virtual void SetName(const char* name) = 0;
virtual const char* GetName() const = 0;
virtual ResourceType GetResourceType() const = 0;
virtual uint64_t GetGpuVirtualAddress() const = 0; // 对于 Buffer
};
```
---
#### 1.2 资源生命周期管理不一致
**当前问题**:
- 所有资源使用 `Shutdown()` + `delete` 的手动管理方式
- 容易导致资源泄漏或重复释放
- 与引擎 Core 模块的智能指针体系 (`Ref`, `UniqueRef`) 不统一
**建议**:
1. 考虑使用引用计数管理 RHI 资源
2. 或者提供 RAII 包装器类
3. 至少应该提供统一的资源销毁接口(如 `RHIDevice::DestroyResource()`
---
### 2. 描述符系统设计问题
#### 2.1 描述符接口偏向 D3D12
**当前实现** ([RHIDescriptorPool.h](file:///d:/Xuanchi/Main/XCEngine/engine/include/XCEngine/RHI/RHIDescriptorPool.h)):
```cpp
struct DescriptorPoolDesc {
uint32_t maxDescriptorCount; // D3D12 风格
// ...
};
```
**问题**:
- OpenGL 没有原生的描述符池概念
- OpenGL 后端需要完全模拟,可能效率低下
- 缺少 DescriptorSetLayout 的概念
**建议**: 参考 Vulkan 的描述符系统设计:
```cpp
// 1. 先创建 DescriptorSetLayout
struct DescriptorSetLayoutDesc {
std::vector<DescriptorBinding> bindings;
};
class RHIDescriptorSetLayout { ... };
// 2. 从 Layout 创建 Pool
struct DescriptorPoolDesc {
std::vector<DescriptorPoolSize> poolSizes; // 按类型指定数量
uint32_t maxSets;
};
// 3. 从 Pool 分配 Set
class RHIDescriptorSet {
virtual void Update(uint32_t binding, RHIResource* resource) = 0;
};
```
---
#### 2.2 缺少描述符集绑定机制
**当前问题**:
- RHICommandList 直接绑定资源 (`SetVertexBuffer`, `SetTexture`)
- 缺少批量绑定描述符集的能力
**建议**: 添加描述符集绑定接口:
```cpp
virtual void BindDescriptorSet(
uint32_t setIndex,
RHIDescriptorSet* descriptorSet,
RHIPipelineLayout* layout
) = 0;
```
---
### 3. 命令列表设计问题
#### 3.1 命令列表生命周期管理
**当前问题**:
- 缺少命令列表池化管理
- 每帧可能需要重新创建命令列表
**建议**: 添加命令分配器概念:
```cpp
class RHICommandAllocator {
public:
virtual void Reset() = 0; // 重用命令列表内存
};
// Device 接口
virtual RHICommandAllocator* CreateCommandAllocator(
CommandListType type
) = 0;
```
---
#### 3.2 屏障接口不够清晰
**当前实现**:
```cpp
virtual void ResourceBarrier(
uint32_t numBarriers,
ResourceBarrierDesc* barriers
) = 0;
virtual void ExecuteBarriers() = 0; // 这个方法名容易误解
```
**问题**: `ExecuteBarriers` 方法名暗示有延迟执行,但实际行为不明确。
**建议**:
- 明确屏障是立即执行还是批量执行
- 考虑添加 `FlushBarriers()` 方法名替代 `ExecuteBarriers()`
---
### 4. 着色器系统问题
#### 4.1 编译接口职责混乱
**当前实现** ([RHIShader.h](file:///d:/Xuanchi/Main/XCEngine/engine/include/XCEngine/RHI/RHIShader.h)):
```cpp
class RHIShader {
public:
// RHIShader 自己有编译方法
virtual bool CompileFromFile(...) = 0;
virtual bool Compile(...) = 0;
};
// RHIDevice 也有编译方法
virtual RHIShader* CompileShader(const ShaderCompileDesc& desc) = 0;
```
**问题**: 编译职责分散,用户不知道该用哪个接口。
**建议**: 统一着色器创建流程:
```cpp
// 方案1: 只在 Device 中创建
class RHIDevice {
virtual RHIShader* CreateShader(const ShaderDesc& desc) = 0;
};
// 方案2: 使用 ShaderCompiler 工具类
class RHIShaderCompiler {
virtual RHIShader* CompileFromFile(...) = 0;
virtual RHIShader* CompileFromSource(...) = 0;
};
```
---
#### 4.2 缺少着色器反射接口
**当前问题**:
- 只有 `GetUniformInfos()` 方法
- 缺少完整的着色器反射(输入/输出语义、资源绑定等)
**建议**: 添加完整的着色器反射接口:
```cpp
struct ShaderReflection {
std::vector<VertexInputAttribute> vertexInputs;
std::vector<FragmentOutput> fragmentOutputs;
std::vector<ResourceBinding> resourceBindings;
std::vector<PushConstantRange> pushConstantRanges;
};
virtual ShaderReflection GetReflection() const = 0;
```
---
### 5. 管线状态对象问题
#### 5.1 缺少管线缓存
**当前问题**: 每次创建 PSO 都需要完整编译,没有缓存机制。
**建议**: 添加管线缓存接口:
```cpp
class RHIPipelineCache {
public:
virtual void Save(const char* filePath) = 0;
virtual void Load(const char* filePath) = 0;
virtual size_t GetDataSize() const = 0;
virtual void* GetData() const = 0;
};
// Device 接口
virtual RHIPipelineCache* CreatePipelineCache() = 0;
virtual RHIPipelineState* CreatePipelineState(
const PipelineStateDesc& desc,
RHIPipelineCache* cache = nullptr
) = 0;
```
---
### 6. 缺失的关键功能
#### 6.1 缺少资源别名 (Aliasing) 支持
**设计文档提到**: "求同存异"
**问题**: D3D12 和 Vulkan 都支持资源别名(多个资源共享同一块内存),但当前 RHI 没有暴露。
**建议**: 添加资源别名支持:
```cpp
struct ResourceAliasingDesc {
RHIResource* overlappingResources;
uint32_t resourceCount;
};
virtual void AliasingResources(
const ResourceAliasingDesc& desc
) = 0;
```
---
#### 6.2 缺少多队列支持
**当前问题**:
- RHICommandQueue 只支持单一类型
- 缺少多队列同步机制
**建议**: 添加跨队列同步支持:
```cpp
struct QueueSyncDesc {
RHICommandQueue* waitQueue;
RHIFence* fence;
uint64_t value;
};
virtual void QueueSubmit(
const QueueSubmitDesc& desc,
const QueueSyncDesc* waitSyncs = nullptr,
uint32_t waitSyncCount = 0,
const QueueSyncDesc* signalSyncs = nullptr,
uint32_t signalSyncCount = 0
) = 0;
```
---
#### 6.3 缺少 RenderGraph 支持
**设计文档提到**: "渲染管线层SRP/Render Graph"
**问题**: 当前 RHI 接口没有为 RenderGraph 提供必要的支持:
- 缺少资源传递机制
- 缺少自动屏障生成
- 缺少资源生命周期跟踪
**建议**: 添加 RenderGraph 友好的接口:
```cpp
struct ResourceTransition {
RHIResource* resource;
ResourceStates fromState;
ResourceStates toState;
uint32_t queueFamily; // 支持跨队列传递
};
virtual void TransitionResources(
const ResourceTransition* transitions,
uint32_t count
) = 0;
```
---
## 二、实现问题
### 1. OpenGL 后端状态管理
**问题**: OpenGL 是状态机模型,需要仔细管理状态。
**建议检查点**:
- [ ] 是否正确跟踪当前绑定的 VAO/VBO/纹理
- [ ] 是否正确跟踪当前激活的着色器程序
- [ ] 是否正确跟踪混合/深度/模板状态
- [ ] 是否有不必要的冗余状态切换
**建议**: 实现状态跟踪器:
```cpp
class OpenGLStateTracker {
public:
void BindTexture(uint32_t unit, uint32_t texture);
void BindVertexArray(uint32_t vao);
void UseProgram(uint32_t program);
// ... 避免重复绑定
};
```
---
### 2. 资源状态跟踪不一致
**问题**:
- D3D12 需要精确的资源状态跟踪
- OpenGL 没有显式的资源状态概念
- 当前实现在 OpenGL 后端如何处理状态?
**建议**:
- OpenGL 后端可以忽略资源状态(或仅用于调试)
- 或者实现软件状态跟踪用于验证
---
### 3. 内存管理缺失
**问题**:
- 缺少显式的 GPU 内存分配接口
- D3D12 有 Heap 概念OpenGL 没有
**建议**: 添加内存分配抽象:
```cpp
struct HeapDesc {
HeapType type; // Default, Upload, Readback
uint64_t size;
HeapFlags flags;
};
class RHIHeap {
public:
virtual void* Map() = 0;
virtual void Unmap() = 0;
};
// 资源创建时指定堆
struct BufferDesc {
// ...
RHIHeap* heap; // 可选
uint64_t heapOffset; // 可选
};
```
---
### 4. 错误处理机制
**当前问题**:
- 大部分方法返回 `void``bool`
- 缺少详细的错误信息
**建议**: 添加结果类型:
```cpp
template<typename T>
struct RHIResult {
T value;
RHIErrorCode error;
const char* errorMessage;
};
// 使用示例
RHIResult<RHITexture*> result = device->CreateTexture(desc);
if (result.error != RHIErrorCode::Success) {
LogError(result.errorMessage);
}
```
---
## 三、与设计理念的对比
### 设计理念 vs 实际实现
| 设计理念 | 设计文档要求 | 当前实现状态 | 问题 |
|---------|------------|------------|------|
| **求同存异** | 提取 API 共性 | ✅ 部分实现 | 描述符系统偏向 D3D12 |
| **分层抽象** | 清晰的层级结构 | ✅ 已实现 | 层级清晰 |
| **特性降级** | 能力检测和替代方案 | ⚠️ 部分实现 | RHICapabilities 存在但使用不明确 |
| **底层逃逸** | 允许访问原生 API | ✅ 已实现 | GetNativeHandle() 接口存在 |
---
## 四、优先级建议
### 高优先级(影响功能正确性)
1. **统一资源生命周期管理** - 防止内存泄漏
2. **完善错误处理机制** - 便于调试
3. **OpenGL 状态跟踪** - 避免渲染错误
### 中优先级(影响性能和可维护性)
4. **重构描述符系统** - 提高 OpenGL 效率
5. **统一着色器编译接口** - 提高易用性
6. **添加命令分配器** - 提高性能
### 低优先级(增强功能)
7. **添加管线缓存** - 加速启动
8. **添加资源别名支持** - 优化内存
9. **RenderGraph 支持** - 高级功能
---
## 五、总结
### 优点
1. ✅ 分层架构清晰,符合设计文档
2. ✅ 核心抽象接口基本完整
3. ✅ D3D12 后端实现较为完善
4. ✅ 测试覆盖较好
### 主要问题
1. ❌ 描述符系统设计偏向 D3D12OpenGL 后端效率可能受影响
2. ❌ 资源生命周期管理不一致,存在泄漏风险
3. ❌ 着色器编译接口职责混乱
4. ⚠️ 缺少部分高级功能(资源别名、多队列同步等)
### 建议
建议按照优先级逐步改进,首先解决高优先级问题,确保引擎的稳定性和正确性。