chore: sync workspace state

This commit is contained in:
2026-03-29 01:36:53 +08:00
parent eb5de3e3d4
commit e5cb79f3ce
4935 changed files with 35593 additions and 360696 deletions

View File

@@ -0,0 +1,364 @@
# C#脚本系统 Editor 前置缺口
## 1. 目的
本文档只记录 **C# 脚本系统接入 editor 时需要补齐的 editor 侧缺口**
这些内容 **不是脚本模块第一阶段的实现范围**
第一阶段仍以:
- 运行时闭环
- 单元测试闭环
- 最小场景级验证
为主。
本文档的作用是防止后续把 editor 集成需求误混到第一阶段里。
---
## 2. 当前策略
当前策略明确如下:
- 脚本系统第一阶段先不依赖 editor
- editor 只作为后续集成目标
- editor 相关工作拆分为独立 issue
因此,下面所有条目均属于:
- 后续阶段工作
- 或 editor / runtime 边界层工作
---
## 3. Issue 列表
## E-001 Play / Simulate 工作流尚未落地
### 现状
editor 当前已经定义了相关事件,但完整的 Play / Simulate 切换链路仍未形成统一工作流。
### 影响
没有这条链路,脚本系统无法在 editor 中以接近 Unity 的方式运行:
- 无法从编辑态切换到运行态
- 无法创建运行时场景副本
- 无法触发脚本运行时启动与停止
### 需要补齐
- `EditorMode` 状态机
- `Edit / Play / Simulate` 三态切换
- 菜单栏或工具栏中的 Play / Stop / Pause 控件
- 对应的事件派发和恢复流程
### 优先级
高,但属于 editor 集成阶段,不属于脚本第一阶段
---
## E-002 editor 场景与 runtime 场景切换控制未封装
### 现状
当前 scene 管理具备快照能力,但 editor 还没有一套完整的“运行时场景副本控制器”。
### 影响
没有这一层,脚本一旦接入 editor会直接面临以下风险
- Play 过程污染编辑场景
- Stop 后无法恢复编辑态
- 运行时对象状态和 editor 面板状态错乱
### 需要补齐
- editor 场景与 runtime 场景的明确所有权
- Play 前复制
- Stop 后恢复
- 运行时期间禁用部分编辑操作
- 选中对象和层级面板的状态同步策略
### 优先级
---
## E-003 Inspector 缺少 `ScriptComponent` 作者化 UI
### 现状
当前 editor Inspector 还没有脚本组件专用 UI。
### 影响
即使底层脚本系统完成,用户也无法在 editor 中完成以下基础操作:
- 添加脚本组件
- 删除脚本组件
- 选择脚本类
- 查看脚本类名
- 调整脚本组件顺序
### 需要补齐
- Add Component 菜单中的 `ScriptComponent`
- 已挂载脚本组件列表
- 脚本类选择器
- 脚本丢失 / 类不存在 / 程序集未加载的错误态显示
### 优先级
---
## E-004 Inspector 缺少脚本字段编辑能力
### 现状
当前 editor 没有基于脚本字段元数据的动态 Inspector。
### 影响
无法实现 Unity 风格脚本工作流中最关键的一环:
- 在 Inspector 中编辑脚本字段
### 需要补齐
- 字段元数据缓存到 editor 层
- 基础类型字段绘制
- `Vector2/3/4` 字段绘制
- `bool` / `string` / 数值类型编辑
- 字段值回写 `ScriptComponent` 的字段缓存
### 优先级
---
## E-005 C# 项目与程序集管理缺失
### 现状
`Project` 面板目前已经有 `Assets/Scripts` 目录概念,但没有正式的 C# 项目管理机制。
### 影响
用户无法在 editor 中稳定地管理脚本编译输入和输出:
- 没有 `GameScripts.csproj`
- 没有 `ScriptCore` 引用管理
- 没有程序集输出路径约定
### 需要补齐
- 项目初始化时创建脚本工程模板
- 脚本程序集输出目录规范
- `ScriptCore` 引用自动配置
- 脚本工程文件缺失时的恢复策略
### 优先级
中到高
---
## E-006 editor 内缺少脚本编译触发入口
### 现状
当前 editor 没有“编译脚本”入口,也没有编译状态反馈。
### 影响
后续即使 Inspector 可选择脚本,用户也无法在 editor 中完成闭环:
- 修改脚本
- 编译程序集
- 重新加载类列表
### 需要补齐
- 手动编译按钮
- 后续可扩展到自动编译或文件监听
- 编译状态显示
- 成功/失败结果通知
### 优先级
中到高
---
## E-007 Console 面板缺少脚本编译错误与运行时异常接入
### 现状
当前 Console 还没有专门的脚本编译/加载/执行错误通路。
### 影响
脚本系统接入 editor 后,最基本的错误反馈都会缺失:
- 编译错误
- 程序集加载失败
- 类发现失败
- 运行时异常
- 栈信息显示
### 需要补齐
- 编译器 stdout/stderr 采集
- 程序集加载错误显示
- 托管异常栈转发到 Console
- 错误级别区分
- 后续可扩展到点击跳转文件/行号
### 优先级
---
## E-008 脚本类数据库与类缓存刷新机制缺失
### 现状
editor 还没有“当前项目有哪些可挂载脚本类”的缓存层。
### 影响
没有这一层Inspector 无法稳定实现:
- 类下拉列表
- 类是否可挂载的判断
- 类丢失提示
- 程序集重载后的刷新
### 需要补齐
- 脚本程序集扫描结果缓存
- 全限定类名列表
- 类状态标记
- reload 后缓存刷新
### 优先级
---
## E-009 对象引用字段的 editor 交互控件缺失
### 现状
后续脚本字段一旦支持 `GameObject` / 组件引用editor 目前没有相应控件。
### 影响
对象引用字段虽然不属于脚本第一阶段必需项,但属于后续可用性的关键能力。
### 需要补齐
- 场景对象选择器
- 层级面板拖拽赋值
- 失效引用显示
- 类型校验
### 优先级
---
## E-010 脚本程序集重载的 editor UX 缺失
### 现状
editor 当前没有定义“脚本重载时如何影响当前状态”的用户体验规则。
### 影响
后续一旦接入脚本编译与重载,会出现一系列状态问题:
- 当前选中对象是否刷新
- Inspector 是否保留编辑状态
- Play 中是否允许重载
- 重载失败如何回退
### 需要补齐
- Edit 模式重载策略
- Play 模式重载策略
- 失败回退策略
- 用户提示文案与状态反馈
### 优先级
---
## 4. 与 editor 集成直接相关的推荐顺序
建议的 editor 集成顺序如下:
1. `E-001` Play / Simulate 工作流
2. `E-002` runtime scene 切换控制
3. `E-003` `ScriptComponent` 作者化 UI
4. `E-004` 脚本字段 Inspector
5. `E-007` Console 错误接入
6. `E-005` C# 项目与程序集管理
7. `E-006` 脚本编译入口
8. `E-008` 类数据库刷新
9. `E-009` 对象引用字段控件
10. `E-010` 程序集重载 UX
这个顺序的核心原则是:
- 先让脚本能在 editor 中“跑起来”
- 再让脚本能在 editor 中“被作者化”
- 最后再补自动化体验与重载体验
---
## 5. 关联但不归 editor 的前置项
以下事项不是 editor issue但会直接影响后续 editor 集成质量:
- `GameObject UUID` 持久化
- 运行时生命周期规范化
- `Start` 一次性语义
- `SetActive` 驱动 `OnEnable/OnDisable`
- 场景递归更新
- `ScriptComponent` 字段缓存与序列化
这些工作应当在脚本第一阶段或 editor 集成前置阶段优先完成。
---
## 6. 结论
脚本系统第一阶段不应被 editor 当前进度绑定。
正确的推进方式是:
- 先做运行时与单测闭环
- 再按本文档逐项补 editor 集成能力
这样可以避免脚本模块在早期同时背负:
- 运行时实现风险
- editor 工作流风险
- UI 设计风险
- 重载体验风险
从而把复杂度拆开,逐步落地。

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,940 @@
# XCEngine Editor 设计分析与改进计划
## 1. 项目概述
### 1.1 当前状态
XCEngine Editor 是一个基于 ImGui 的 Unity 风格编辑器 UI目前具备以下基础功能
- **渲染基础**: DirectX 12 + ImGui 对接
- **面板框架**: Docking 布局系统
- **UI 主题**: Unity 风格深色主题
### 1.2 对比参考
参考项目 Fermion Boson Editor 是一个功能完整的游戏引擎编辑器,具有:
- 完整的 3D Viewport
- 场景层级系统
- 组件检查器
- 资源浏览器
- 材质编辑器
- Play/Edit/Simulate 模式切换
---
## 2. 整体架构对比
### 2.1 架构图
**Fermion 架构**:
```
Fermion::Application
└── LayerStack
├── ImGuiLayer (overlay)
└── BosonLayer (editor layer)
├── ViewportPanel (3D viewport + gizmos)
├── SceneHierarchyPanel (entity tree)
│ └── InspectorPanel (embedded, component editor)
├── ContentBrowserPanel (asset browser)
├── MaterialEditorPanel (node-based material)
├── SettingsPanel (editor settings)
├── OverlayRenderPanel (physics debug)
└── MenuBarPanel (menu bar)
```
**XCEngine 架构**:
```
UI::Application
└── Panels (独立 Panel 类)
├── MenuBar
├── HierarchyPanel
├── InspectorPanel
├── SceneViewPanel (占位符)
├── GameViewPanel (占位符)
├── ProjectPanel
└── ConsolePanel
```
### 2.2 关键差异
| 方面 | Fermion | XCEngine |
|------|---------|----------|
| Layer 系统 | Application → LayerStack → BosonLayer | Application 直接管理 Panels |
| Panel 集成 | SceneHierarchy 内嵌 InspectorPanel | 各 Panel 独立 |
| Scene 管理 | BosonLayer 持有 Scene/SceneRenderer | SceneManager 单例 |
| 渲染集成 | BosonLayer → SceneRenderer → Framebuffer | 无对接 |
| 事件系统 | Layer::onEvent 统一分发 | 各 Panel 独立处理 |
---
## 3. 各面板详细分析
### 3.1 SceneHierarchyPanel / HierarchyPanel
#### 功能对比
| 功能 | Fermion | XCEngine | 状态 |
|------|---------|----------|------|
| 树节点渲染 | ✅ `TreeNodeEx` + UUID | ✅ `TreeNodeEx` + EntityID | 完成 |
| 选中高亮 | ✅ | ✅ | 完成 |
| 展开/折叠 | ✅ 自动记忆状态 | ✅ `isOpen` 状态 | 完成 |
| 重命名 | ✅ 双击触发 | ⚠️ 有 bug | 需修复 |
| 拖拽重排 | ✅ 完整 + 循环检测 | ⚠️ 基本实现 | 需完善 |
| 右键菜单 | ✅ Create Child, Detach, Delete | ✅ Create, Rename, Delete, Copy/Paste, Duplicate | 需补充 |
| 空区域点击 | ✅ 取消选中 | ✅ 取消选中 | 完成 |
| 嵌入 Inspector | ✅ Panel 内嵌 InspectorPanel | ❌ 分离 | 架构差异 |
#### XCEngine 问题详解
**问题 1: 重命名逻辑 bug**
`HierarchyPanel.cpp` lines 106-113:
```cpp
if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) {
if (strlen(m_renameBuffer) > 0) {
sceneManager.RenameEntity(id, m_renameBuffer);
}
m_renaming = false;
m_renamingEntity = INVALID_ENTITY_ID;
}
```
问题:点击 InputText 外部时,`IsItemActive()` 已经变为 false此时 `IsMouseClicked(0)` 也已经错过。
**问题 2: 缺少 "Create Child" 选项**
右键菜单只有:
- Create → Empty Object, Camera, Light, Cube, Sphere, Plane
- Rename, Delete
- Copy, Paste, Duplicate
缺少 "Create Child" 选项来在选中物体下创建子物体。
**问题 3: 没有 "Detach from Parent" 选项**
无法将子物体脱离父物体,直接变为根层级。
---
### 3.2 InspectorPanel
#### 功能对比
| 功能 | Fermion (1173 行) | XCEngine (94 行) | 状态 |
|------|-------------------|------------------|------|
| 组件显示 | ✅ 模板系统 | ⚠️ 只实现 2 种组件 (Engine 有完整组件库) | 需完善 |
| 动态增删组件 | ✅ 分类菜单 | ❌ 无 | 需实现 |
| 删除组件 | ✅ 右键 Remove | ❌ 无 | 需实现 |
| Transform 编辑 | ✅ `drawVec3Control` | ⚠️ `DragFloat3` 简陋 | 需改进 |
| Mesh 编辑 | ✅ Drag-drop + popup | ⚠️ 只有 InputText | 需改进 |
| 材质预览 | ✅ 缩略图渲染 | ❌ 无 | 需实现 |
| Camera 编辑 | ✅ 完整 | ❌ 无 | 需实现 |
| Light 编辑 | ✅ D/P/S Light | ❌ 无 | 需实现 |
| Physics 编辑 | ✅ 完整 | ❌ 无 | 需实现 |
| Script 编辑 | ✅ 字段编辑 | ❌ 无 | 需实现 |
| Entity Picking | ✅ 关节连接 | ❌ 无 | 需实现 |
#### XCEngine 实现现状
`InspectorPanel.cpp` lines 44-92:
```cpp
void InspectorPanel::RenderComponent(Component* component) {
if (auto* transform = dynamic_cast<TransformComponent*>(component)) {
ImGui::DragFloat3("##Position", transform->position, 0.1f);
ImGui::DragFloat3("##Rotation", transform->rotation, 1.0f);
ImGui::DragFloat3("##Scale", transform->scale, 0.1f);
}
else if (auto* meshRenderer = dynamic_cast<MeshRendererComponent*>(component)) {
// 只有 InputText没有预览没有拖拽
}
}
```
**主要问题**:
1. Editor Inspector 面板只实现了 Transform 和 MeshRenderer 显示编辑,但 Engine 核心已有完整组件系统
2. 没有 Add Component 菜单
3. 没有 Remove Component 功能
4. 没有 CollapsingHeader 折叠
5. 布局简陋,没有缩进和对齐
---
### 3.3 ProjectPanel / ContentBrowserPanel
#### 功能对比
| 功能 | Fermion | XCEngine | 状态 |
|------|---------|----------|------|
| 布局 | ✅ 两列 (树 + 网格) | ⚠️ 只有网格 | 需补充 |
| 文件夹树 | ✅ 左侧导航树 | ❌ 无 | 需实现 |
| 缩略图 | ✅ 加载 Texture | ⚠️ 彩色方块 | 需改进 |
| 材质预览 | ✅ 缩略图渲染 | ❌ 无 | 需实现 |
| 拖拽移动 | ✅ 完整实现 | ⚠️ stubbed | 需修复 |
| 双击打开 | ✅ 打开文件夹 | ✅ 实现 | 完成 |
| 面包屑导航 | ✅ 路径按钮 | ✅ 实现 | 完成 |
| 搜索过滤 | ✅ 实现 | ✅ 实现 | 完成 |
#### XCEngine 问题详解
**问题: HandleDrop() 返回 false**
`ProjectPanel.cpp` line 294:
```cpp
bool ProjectPanel::HandleDrop(const AssetItemPtr& targetFolder) {
return false; // STUBBED OUT - 拖拽移动功能不工作
}
```
虽然 `RenderAssetItem()` 中有拖拽目标代码,但实际上 `HandleDrop()` 从未被调用,拖拽移动功能完全失效。
---
### 3.4 MenuBar
#### 功能对比
| 功能 | Fermion (271 行) | XCEngine (55 行) | 状态 |
|------|------------------|-------------------|------|
| 实现方式 | ✅ 自定义窗口边框 | ✅ `BeginMainMenuBar` | 完成 |
| 菜单项 | ✅ 实际回调 | ❌ **全部 stubbed** | 需实现 |
| 项目操作 | ✅ new/open/save | ❌ 无 | 需实现 |
| 创建菜单 | ✅ Material/Texture | ❌ 无 | 需实现 |
| 窗口控制 | ✅ 有 (已注释) | ❌ 无 | 可选 |
#### XCEngine 问题详解
**所有菜单项都是空的**:
```cpp
// MenuBar.cpp
if (ImGui::MenuItem("New Scene", "Ctrl+N")) {} // 空
if (ImGui::MenuItem("Open Scene", "Ctrl+O")) {} // 空
if (ImGui::MenuItem("Save Scene", "Ctrl+S")) {} // 空
// ... 所有项都是空的
```
---
### 3.5 ConsolePanel
#### 功能对比
| 功能 | Fermion (84 行) | XCEngine (70 行) | 状态 |
|------|------------------|-------------------|------|
| 日志显示 | ✅ 彩色 + 前缀 | ✅ 彩色 + 前缀 | 完成 |
| 命令输入 | ✅ 底部输入框 | ❌ 无 | 需补充 |
| 命令处理 | ✅ clear/help | ❌ 无 | 需实现 |
| 自动滚动 | ✅ 新日志时滚动 | ⚠️ flag 设置但逻辑不完整 | 需改进 |
#### XCEngine 优点
- 测试按钮注入日志功能完善
- 日志级别颜色区分正确
- 基本显示功能正常
---
### 3.6 SceneViewPanel / ViewportPanel
#### 功能对比
| 功能 | Fermion (356 行) | XCEngine (54 行) | 状态 |
|------|------------------|-------------------|------|
| 3D 渲染 | ✅ Framebuffer | ❌ **只有网格** | 需重构 |
| 相机 | ✅ EditorCamera | ❌ 无 | 需实现 |
| 鼠标拾取 | ✅ readPixel | ❌ 无 | 需实现 |
| Gizmo | ✅ ImGuizmo | ❌ 无 | 需实现 |
| 工具栏 | ✅ Q/W/E/R | ❌ 无 | 需实现 |
| Play 控制 | ✅ Play/Stop/Pause/Step | ❌ 无 | 需实现 |
| 状态切换 | ✅ Edit/Play/Simulate | ❌ 无 | 需实现 |
#### XCEngine 实现现状
```cpp
// SceneViewPanel.cpp
void SceneViewPanel::RenderGrid() {
// 只画了 50px 网格背景
for (float x = 0; x < canvasSize.x; x += gridSize) {
drawList->AddLine(...);
}
// 没有任何 3D 渲染
}
```
**问题**: 完全没有任何 3D 渲染能力,只是占位符。
---
### 3.7 GameViewPanel
| 功能 | Fermion | XCEngine | 状态 |
|------|---------|----------|------|
| 游戏视图 | ✅ Framebuffer 渲染 | ❌ **纯占位符** | 需重构 |
| 状态栏 | ✅ Play/Simulate 指示 | ❌ 无 | 需实现 |
---
## 4. XCEngine 缺失的面板
XCEngine Editor 只有 7 个面板,而 Fermion 有 10 个。以下是缺失的面板:
### 4.1 SettingsPanel - 编辑器设置
**Fermion 功能**:
- Renderer Info: 相机设置、设备信息、帧时间统计
- Environment Settings: Skybox、阴影、IBL、HDR 加载、环境光强度、法线强度
- Debug Settings: 渲染模式 (Forward/Deferred Hybrid)、GBuffer 调试、深度视图、物理调试开关、无限网格、轮廓设置
- Project Settings: 项目信息、默认字体配置
**XCEngine 状态**: 无此面板
**实现建议**: 可以作为 InspectorPanel 的扩展,或者单独的设置浮窗
---
### 4.2 OverlayRenderPanel - 调试可视化
**Fermion 功能**:
```cpp
class OverlayRenderPanel {
void render(const Context &ctx) const;
void renderPhysicsColliders(); // 物理碰撞体可视化
void renderPhysics2DColliders(); // 2D 碰撞体
void renderPhysics3DColliders(); // 3D 碰撞体
void renderJoints(); // 关节连接可视化
void renderSelectedEntityOutline(); // 选中物体轮廓
};
```
**功能说明**:
- 在 Viewport 上叠加渲染物理调试信息
- 2D 碰撞体: Box、Circle、BoxSensor、CircleSensor
- 3D 碰撞体: Box、Sphere、Capsule、Mesh (三角形线框)
- 关节: RevoluteJoint (锚点圆)、DistanceJoint (锚点圆 + 线段)
- 选中物体白色轮廓
**XCEngine 状态**: 无此面板,但可以在 SceneViewPanel 完善后添加
---
### 4.3 MaterialEditorPanel - 材质编辑器
**Fermion 功能**:
- 基于 `ax::NodeEditor` (imnodes) 的节点式材质编辑器
- PBR Output 节点 (ID=1) 固定在右侧
- Texture 节点可动态创建
- 引脚连接系统 (Pin ID 约定: `nodeID*100 + pinIndex`)
- 材质预览渲染 (`MaterialPreviewRenderer`)
- 材质编译 (`compileMaterial()`)
**节点系统**:
```cpp
// PBR Output 节点输入引脚
enum PBRInputPin {
Albedo = 1, // 引脚 ID = 101
Normal = 2, // 引脚 ID = 102
Metallic = 3, // 引脚 ID = 103
Roughness = 4,// 引脚 ID = 104
AO = 5 // 引脚 ID = 105
};
// Texture 节点输出引脚
// 引脚 ID = nodeID * 100 + 1
```
**UI 布局**:
```
┌─────────────────────────────────────────────────────┐
│ [Texture Node] ──────→ [Albedo] │
│ [Texture Node] ──────→ [Normal] │
│ [Texture Node] ──────→ [PBR Output] → [Material] │
│ → [Metallic] │
│ → [Roughness] │
│ → [AO] │
└─────────────────────────────────────────────────────┘
```
**XCEngine 状态**: 无此面板,需要独立开发
**实现难度**: 高,需要 imnodes 库集成和材质编译系统
---
### 4.4 TextureConfigPanel - 纹理配置
**Fermion 功能**:
```cpp
class TextureConfigPanel {
void loadTexture(const std::filesystem::path &ftexPath);
void loadTextures(const vector<path> &ftexPaths);
void saveTexture(TextureConfigData &data);
void saveAllTextures();
struct TextureConfigData {
std::filesystem::path FtexPath;
std::string Name;
TextureAssetSpecification Spec;
bool Modified = false;
};
bool m_BatchMode = false; // 批量配置模式
TextureAssetSpecification m_BatchSpec;
};
```
**功能**:
- 批量纹理加载
- 纹理规格编辑 (格式、过滤器、Mipmaps 等)
- 保存/导出功能
**XCEngine 状态**: 无此面板ProjectPanel 只做文件浏览
---
### 4.5 AssetManagerPanel - 资源注册表
**Fermion 功能**:
```cpp
class AssetManagerPanel {
void onImGuiRender();
// 显示所有注册的资源
// 可搜索、可过滤
// Asset 类型过滤
// Load/Unload 按钮
// 显示: asset path, type, handle ID, loading status
};
```
**功能**:
- 查看所有已注册资产
- 按类型过滤 (Texture, Mesh, Material, etc.)
- 搜索功能
- 手动加载/卸载资产
- 显示资源路径、类型、句柄 ID、加载状态
**XCEngine 状态**: 无此面板ProjectPanel 只做文件系统浏览
---
## 5. 核心系统差异分析
### 5.1 Application 架构对比
**Fermion Application**:
```cpp
class Application {
std::unique_ptr<IWindow> m_window;
std::unique_ptr<ImGuiLayer> m_imGuiLayer;
std::unique_ptr<LayerStack> m_layerStack;
void pushLayer(std::unique_ptr<Layer> layer); // 在 ImGui 之前更新
void pushOverlay(std::unique_ptr<Layer> overlay); // 在 ImGui 之后更新
};
```
**XCEngine Application**:
```cpp
class Application {
HWND m_hwnd;
ID3D12Device* m_device;
// 直接管理所有 Panels
std::unique_ptr<MenuBar> m_menuBar;
std::unique_ptr<HierarchyPanel> m_hierarchyPanel;
// ...
};
```
**关键差异**:
1. Fermion 使用 Layer/Overlay 模式,事件按倒序传播
2. XCEngine 直接管理 Panels缺乏层次化设计
3. Fermion 有 ImGuiLayer 专门处理 ImGui 事件阻塞
4. XCEngine 需要手动在 Panel 内部处理焦点判断
---
### 5.2 SceneManager vs Scene/EntityManager
**XCEngine SceneManager**:
```cpp
class SceneManager {
std::unordered_map<EntityID, GameObject> m_entities;
std::vector<EntityID> m_rootEntities;
EntityID CreateEntity(name, parent);
void DeleteEntity(id);
void MoveEntity(id, newParent);
EntityID CopyEntity(id);
EntityID PasteEntity(parent);
};
```
**Fermion Scene + EntityManager**:
```cpp
class Scene {
std::unique_ptr<EntityManager> m_entityManager;
std::unique_ptr<Physics2DWorld> m_physicsWorld2D;
std::unique_ptr<Physics3DWorld> m_physicsWorld3D;
};
class EntityManager {
entt::registry m_registry; // EnTT ECS
std::unordered_map<UUID, entt::entity> m_entityMap;
};
```
**XCEngine 实际情况**:
1. ✅ 有 Scene 类和 SceneManager (见 engine/include/XCEngine/Scene/)
2. ❌ 没有物理世界集成
3. ✅ 有 Component/GameObject 系统,但非 EnTT ECS (使用 dynamic_cast)
4. ✅ EntityID 是 uint64_t 递增整数,不是 UUID
5. ❌ Editor 没有场景状态 (Edit/Play/Simulate) 切换机制
---
### 5.3 BosonUI 自定义控件
Fermion 定义了 `ui` 命名空间的自定义控件XCEngine 没有:
**Fermion ui 控件**:
```cpp
namespace ui {
// 向量编辑器 (带 XYZ 标签和 reset 按钮)
void drawVec3Control(const char* label, glm::vec3& values,
float resetValue = 0.0f, float columnWidth = 120.0f);
// 浮点数编辑器
bool drawFloatControl(const char* label, float& value,
float columnWidth = 120.0f, float speed = 0.1f);
// 复选框
void drawCheckboxControl(const char* label, bool& value, float width = 120.0f);
// 自定义 Popup 包装
bool BeginPopup(const char* name);
void EndPopup();
}
```
**XCEngine**: 直接使用原生 ImGui API没有封装
---
### 5.4 选择系统差异
**Fermion 选择 + Entity Picking**:
```cpp
// InspectorPanel 实体拾取用于关节连接
bool m_entityPickingActive = false;
Entity m_pickingTargetEntity;
// 当用户在 Viewport 点击时
void deliverPickedEntity(Entity pickedEntity) {
if (m_pickingTargetEntity.hasComponent<RevoluteJoint2DComponent>()) {
m_pickingTargetEntity.getComponent<RevoluteJoint2DComponent>()
.connectedBodyID = pickedEntity.getUUID();
}
}
```
**XCEngine SelectionManager**:
```cpp
class SelectionManager {
Event<EntityID> OnSelectionChanged;
EntityID GetSelectedEntity();
void SetSelectedEntity(EntityID entity);
};
```
**XCEngine 问题**: 没有 Entity Picking 机制,无法在编辑关节时拾取场景中的物体
---
### 5.5 资源系统对比
**Fermion 资源系统**:
```
AssetManager (抽象基类)
├── EditorAssetManager (编辑器资源管理)
│ └── importAsset() 导入资源
└── RuntimeAssetManager (运行时资源管理)
└── getAsset<T>() 获取资源
AssetRegistry (资源注册表)
AssetHandle (资源句柄)
```
**XCEngine 资源系统**:
```
ProjectManager (文件系统浏览)
└── GetCurrentItems() 返回 AssetItem 列表
AssetItem (只包含文件信息)
├── name
├── type
├── isFolder
└── fullPath
```
**XCEngine 问题**:
1. 没有真正的资源导入流程
2. 没有 AssetRegistry 资源注册表
3. 没有 AssetHandle 统一资源句柄
4. 没有资源缓存和加载/卸载管理
---
## 7. 核心问题总结
### 7.1 已完成功能
| 面板 | 完成度 | 说明 |
|------|--------|------|
| HierarchyPanel | 70% | 基本树视图、选中、重命名、复制、拖拽 |
| ProjectPanel | 60% | 文件浏览、网格显示、导航,但拖拽移动失效 |
| ConsolePanel | 60% | 日志显示,缺少命令输入 |
| MenuBar | 30% | 菜单结构存在,但所有项 stubbed |
| InspectorPanel | 20% | 只实现 Transform 和 MeshRenderer 编辑,但 Engine 核心有完整组件库 |
| SceneViewPanel | 5% | 纯占位符 |
| GameViewPanel | 5% | 纯占位符 |
### 7.2 高优先级问题
1. **MenuBar 所有菜单项 stubbed** - 无法进行任何 Scene/Project 操作
2. **Inspector 没有 Add/Remove Component** - 无法添加/删除组件
3. **SceneViewPanel 完全是占位符** - 无法预览场景
4. **Project 拖拽移动失效** - HandleDrop() 返回 false
5. **缺少 5 个重要面板** - SettingsPanel, OverlayRenderPanel, MaterialEditorPanel, TextureConfigPanel, AssetManagerPanel
### 7.3 RHI 限制
当前 RHI 模块状态:
- D3D12: PipelineState 返回 nullptr无法创建 3D 渲染 Pipeline
- OpenGL: Framebuffer、PipelineState、Shader 正常工作
**影响**: 在 RHI 重构完成前3D Viewport 无法实现。
---
## 8. 改进计划
### 8.1 第一阶段: 完善现有面板功能
**目标**: 不依赖 RHI完善 Editor UI 功能
#### 8.1.1 MenuBar 菜单功能对接
```
优先级: 高
预计工作量: 1-2 天
依赖: 无
```
**需要实现**:
- File 菜单: New Scene, Open Scene, Save Scene, Exit
- Edit 菜单: Undo, Redo (需要命令历史系统), Cut, Copy, Paste
- View 菜单: Reset Layout
- Help 菜单: About
**实现方案**:
```cpp
// MenuBar.cpp
if (ImGui::MenuItem("New Scene", "Ctrl+N")) {
m_onNewSceneCallback(); // 通过回调连接到 BosonLayer
}
```
#### 8.1.2 Inspector Add/Remove Component
```
优先级: 高
预计工作量: 2-3 天
依赖: 组件系统完善
```
**需要实现**:
1. 添加 "Add Component" 按钮
2. 分类组件菜单 (2D, 3D, Other)
3. 右键 "Remove Component" 选项
**实现方案**:
```cpp
// InspectorPanel.cpp
void InspectorPanel::drawComponent<T>(Entity entity, UIFunction uiFunction) {
// 右键菜单
if (ImGui::BeginPopupContextItem("ComponentSettings")) {
if (ImGui::MenuItem("Remove Component"))
entity.removeComponent<T>();
ImGui::EndPopup();
}
}
// Add Component 按钮
if (ImGui::Button("Add Component")) {
ImGui::OpenPopup("AddComponentMenu");
}
// 分类显示组件列表
```
#### 8.1.3 修复 Project 拖拽移动
```
优先级: 中
预计工作量: 0.5 天
依赖: 无
```
**问题**: `HandleDrop()` 返回 false从未被调用
**修复方案**: 在双击打开文件夹时,检查是否正在拖拽,如果是则执行移动操作。
---
### 8.2 第二阶段: Inspector 组件系统完善
**目标**: 实现完整的组件编辑功能
#### 8.2.1 Inspector 组件编辑支持
Engine 核心已有完整组件系统Editor Inspector 需要添加对这些组件的编辑支持:
| 组件 | Engine 状态 | Inspector 编辑复杂度 | 说明 |
|------|------------|---------------------|------|
| TransformComponent | ✅ | 低 | 需改进 UI (drawVec3Control) |
| MeshRendererComponent | ✅ | 中 | 需添加拖拽、预览 |
| CameraComponent | ✅ | 中 | 投影、FOV、近远裁剪 |
| DirectionalLightComponent | ✅ | 低 | 颜色、强度 |
| PointLightComponent | ✅ | 低 | 颜色、强度、范围 |
| SpotLightComponent | ✅ | 中 | 颜色、强度、范围、角度 |
| Rigidbody2DComponent | ✅ | 高 | 物理引擎对接 |
| Rigidbody3DComponent | ✅ | 高 | 物理引擎对接 |
| Collider2D/3D | ✅ | 高 | 碰撞体 |
| SpriteRendererComponent | ✅ | 中 | 2D 精灵 |
| CircleRendererComponent | ✅ | 低 | 圆形渲染 |
| TextComponent | ✅ | 中 | 文本渲染 |
| ScriptComponent | ✅ | 高 | 脚本字段编辑 |
#### 8.2.2 Transform UI 改进
**当前**:
```cpp
ImGui::DragFloat3("##Position", transform->position, 0.1f);
```
**改进方案** (参考 Fermion `ui::drawVec3Control`):
- 添加 XYZ 标签
- 添加 Per-axis reset 按钮
- 统一对齐和缩进
- 添加合适的刻度 (speed)
---
### 8.3 第三阶段: 场景序列化
**目标**: 实现 Scene Save/Load
```
优先级: 中
预计工作量: 2-3 天
依赖: Scene 序列化框架 (Engine Scene 类已有基础 Serialize/Deserialize)
```
**需要实现**:
- Scene 序列化到文件 (Engine 核心已有基础)
- Scene 反序列化
- 资源路径管理
- Editor/Runtime 场景分离
---
### 8.4 第四阶段: 3D Viewport (依赖 RHI)
**目标**: 实现完整的 3D Viewport
```
优先级: 高 (但依赖 RHI)
预计工作量: 2-4 周
依赖: RHI 重构完成
```
#### 8.4.1 OpenGL Backend 优先方案
由于 D3D12 PipelineState 当前 broken可以先用 OpenGL Backend 实现 Viewport
**优势**:
- OpenGL Framebuffer 正常工作
- OpenGL PipelineState 正常工作
- Shader uniform 设置正常工作
**需要工作**:
1. EditorCamera 实现 (Orbit/Pan/Zoom)
2. SceneRenderer 中间层
3. ViewportPanel Framebuffer 渲染
4. 鼠标拾取 (readPixel from entity ID attachment)
5. ImGuizmo 集成
#### 8.4.2 实现步骤
**Step 1: EditorCamera** (3-5 天)
```cpp
class EditorCamera {
// Orbit 模式
void orbit(float deltaX, float deltaY);
void pan(float deltaX, float deltaY);
void zoom(float delta);
// FPS 模式
void moveForward(float delta);
void moveRight(float delta);
};
```
**Step 2: SceneRenderer 中间层** (1 周)
```cpp
class ViewportRenderer {
std::shared_ptr<Framebuffer> m_framebuffer;
std::shared_ptr<Scene> m_scene;
void beginScene(const EditorCamera& camera);
void submitMesh(MeshComponent& mesh, glm::mat4 transform);
void endScene();
};
```
**Step 3: ViewportPanel 集成** (3-5 天)
```cpp
void ViewportPanel::onImGuiRender() {
// 渲染到 framebuffer
m_framebuffer->bind();
m_viewportRenderer->beginScene(m_editorCamera);
// ... 提交场景物体
m_viewportRenderer->endScene();
m_framebuffer->unbind();
// 显示到 ImGui
ImGui::Image(m_framebuffer->getColorTexture(), ...);
// 鼠标拾取
int entityID = m_framebuffer->readPixel(1, pixelX, pixelY);
}
```
**Step 4: ImGuizmo 集成** (2-3 天)
```cpp
ImGuizmo::SetOrthographic(isOrthographic);
ImGuizmo::SetRect(viewportBounds);
ImGuizmo::Manipulate(
cameraView, cameraProjection,
operation, LOCAL,
glm::value_ptr(worldTransform)
);
```
---
### 8.5 第五阶段: Play/Edit 模式
**目标**: 实现场景状态切换
```
优先级: 中
预计工作量: 1-2 周
依赖: 3D Viewport + 组件系统
```
**状态机**:
```cpp
enum class SceneState { Edit, Play, Simulate };
void BosonLayer::onScenePlay() {
m_runtimeScene = Scene::copy(m_editorScene);
m_activeScene = m_runtimeScene;
m_activeScene->onRuntimeStart();
}
void BosonLayer::onSceneStop() {
m_activeScene->onRuntimeStop();
m_activeScene = m_editorScene;
}
```
---
## 9. 技术债务
### 9.1 架构问题
1. **Editor 和 Engine 使用两套不同的 GameObject/Component 系统**
- **Editor** (`editor/src/Core/GameObject.h`): 简化版,使用 `float position[3]` 数组存储变换
- **Engine** (`engine/include/XCEngine/Components/`): 完整 ECS使用 `TransformComponent` 组件
- **后果**: Editor 无法直接使用 Engine 的组件系统,需要重新实现
- **建议**: Editor 应复用 Engine 的 Components::GameObject/Scene 系统
2. **Panel 独立设计 vs Layer 组合**
- Fermion: BosonLayer 组合所有面板,共享 Context
- XCEngine: 各 Panel 独立,通过 SceneManager 单例通信
3. **SceneManager 单例 vs Scene 指针传递**
- Editor 使用简化版 SceneManager与 Engine 的 Scene 类不兼容
- 建议: 考虑使用 Context 模式传递 Scene 引用
4. **缺少 BosonUI 自定义控件封装**
- Fermion 有 ui::drawVec3Control, ui::drawFloatControl 等
- XCEngine 直接使用原生 ImGui API代码重复
### 9.2 代码质量问题
1. **注释掉的代码** - 建议清理
2. **TODO/FIXME** - 建议跟踪
3. **Magic numbers** - 建议定义常量
---
## 10. 建议实施路线
### 短期 (1-2 周)
```
□ MenuBar 菜单功能对接
□ Inspector Add/Remove Component
□ 修复 Project 拖拽移动
□ Transform UI 改进
□ Console 命令输入
```
### 中期 (1-2 月RHI 完成后)
```
□ EditorCamera 实现
□ SceneRenderer 中间层
□ ViewportPanel 3D 渲染
□ 鼠标拾取
□ ImGuizmo 集成
□ Play/Edit/Simulate 模式
```
### 长期
```
□ 完整的 Inspector 组件编辑界面 (Engine 核心组件已有)
□ 场景序列化
□ 资源导入系统
□ 材质编辑器
□ 动画编辑器
□ OverlayRenderPanel (物理调试可视化)
□ TextureConfigPanel (纹理配置)
□ AssetManagerPanel (资源注册表)
□ SettingsPanel (编辑器设置)
□ Play/Edit/Simulate 模式切换
```
---
## 11. 参考资料
- Fermion Boson Editor 源码: `参考/Fermion/Boson/`
- XCEngine Editor 源码: `editor/`
- RHI 模块: `engine/include/XCEngine/RHI/`
---
*文档生成时间: 2026-03-24*
*最后更新: 2026-03-24 (更正 Component 系统描述,补充 Editor/Engine 架构问题)*

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,410 @@
# OpenGL 测试实施计划
## 1. 概述
本文档是 `docs/OpenGL后端测试设计.md` 的实施细化计划,基于设计文档中的 5 阶段实现优先级,结合 D3D12 测试经验54 个测试)制定。
### 1.1 目标
- 搭建完整的 OpenGL 后端测试框架
- 实现与 D3D12 对齐的 54+ 个测试用例
- 确保 CI 环境可用
- 支持无头渲染headless测试
### 1.2 测试组件总览
| # | 组件 | 测试数量 | 文件 | 优先级 |
|---|------|:--------:|------|:------:|
| 1 | OpenGLDevice | 6 | test_device.cpp | Phase 1 |
| 2 | OpenGLBuffer | 6 | test_buffer.cpp | Phase 1 |
| 3 | OpenGLFence | 5 | test_fence.cpp | Phase 1 |
| 4 | OpenGLTexture | 5 | test_texture.cpp | Phase 2 |
| 5 | OpenGLSampler | 4 | test_sampler.cpp | Phase 2 |
| 6 | OpenGLShader | 4 | test_shader.cpp | Phase 3 |
| 7 | OpenGLPipelineState | 3 | test_pipeline_state.cpp | Phase 3 |
| 8 | OpenGLVertexArray | 4 | test_vertex_array.cpp | Phase 3 |
| 9 | OpenGLCommandList | 8 | test_command_list.cpp | Phase 4 |
| 10 | OpenGLRenderTargetView | 4 | test_render_target_view.cpp | Phase 4 |
| 11 | OpenGLDepthStencilView | 4 | test_depth_stencil_view.cpp | Phase 4 |
| 12 | OpenGLSwapChain | 3 | test_swap_chain.cpp | Phase 5 |
| **总计** | | **56** | | |
---
## 2. 实施阶段
### Phase 1: 核心基础设施(约 1 天)
#### 2.1 创建目录结构
```
tests/RHI/OpenGL/
├── CMakeLists.txt
├── fixtures/
│ ├── OpenGLTestFixture.h
│ └── OpenGLTestFixture.cpp
└── Res/
├── Shader/
├── Texture/
└── Data/
```
#### 2.2 实现测试夹具
**OpenGLTestFixture** 是所有测试的基础:
| 功能 | 描述 |
|------|------|
| `SetUpTestSuite()` | 创建隐藏 GLFW 窗口和 GL 上下文 |
| `TearDownTestSuite()` | 销毁窗口,终止 GLFW |
| `SetUp()` | 确保上下文激活,清除 GL 错误 |
| `TearDown()` | 重置 GL 状态,检查泄漏 |
| `CheckGLError()` | 检查并报告 GL 错误 |
**GL 错误检查宏**
```cpp
#define GL_CLEAR_ERRORS() do { while (glGetError() != GL_NO_ERROR); } while(0)
#define GL_CHECK(call) do { call; ASSERT_TRUE(CheckGLError(__FILE__, __LINE__)); } while(0)
#define GL_EXPECT_SUCCESS(call) do { call; EXPECT_EQ(glGetError(), GL_NO_ERROR); } while(0)
```
#### 2.3 OpenGLDevice 测试6 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `CreateRenderWindow_ValidParams` | 窗口创建成功 |
| `CreateRenderWindow_DebugMode` | 调试模式创建 |
| `InitializeWithExistingWindow` | 现有窗口初始化 |
| `GetDeviceInfo_ReturnsValid` | 供应商/渲染器/版本信息 |
| `SwapBuffers_NoErrors` | 交换缓冲区无错误 |
| `PollEvents_ReturnsTrue` | 事件轮询正常 |
#### 2.4 OpenGLBuffer 测试6 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_VertexBuffer` | 顶点缓冲创建 |
| `Initialize_IndexBuffer` | 索引缓冲创建 |
| `Initialize_UniformBuffer` | Uniform 缓冲创建 |
| `Initialize_Dynamic` | 动态缓冲创建 |
| `Bind_Unbind` | 缓冲绑定/解绑 |
| `Map_Unmap` | 数据映射操作 |
#### 2.5 OpenGLFence 测试5 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_Unsignaled` | 未 signaled 状态创建 |
| `Initialize_Signaled` | signaled 状态创建 |
| `Signal_SetsValue` | Signal 设置值 |
| `Wait_Blocks` | Wait 阻塞等待 |
| `IsSignaled_ReturnsState` | signaled 状态查询 |
#### 2.6 验证步骤
```bash
# 构建
cmake --build build --config Debug
# 运行测试
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.Device*:OpenGLTestFixture.Buffer*:OpenGLTestFixture.Fence*
# 预期结果
[==========] 17 tests from OpenGLTestFixture
[ PASSED ] 17 tests
```
---
### Phase 2: 资源管理(约 1 天)
#### 2.7 OpenGLTexture 测试5 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_2DTexture` | 2D 纹理创建 |
| `Initialize_CubeMap` | 立方体纹理创建 |
| `Bind_Unbind` | 纹理绑定/解绑 |
| `GenerateMipmap` | Mipmap 生成 |
| `SetFiltering_SetWrapping` | 过滤/环绕参数 |
#### 2.8 OpenGLSampler 测试4 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_Default` | 默认采样器创建 |
| `Initialize_Custom` | 自定义采样器创建 |
| `Bind_Unbind` | 采样器绑定/解绑 |
| `GetID_ReturnsValid` | 采样器 ID 有效 |
#### 2.9 验证步骤
```bash
# 运行资源管理测试
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.Texture*:OpenGLTestFixture.Sampler*
# 预期结果
[==========] 9 tests from OpenGLTestFixture
[ PASSED ] 9 tests
```
---
### Phase 3: 渲染管线(约 1.5 天)
#### 2.10 OpenGLShader 测试4 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Compile_VertexFragment` | 顶点和片段着色器编译 |
| `Compile_WithGeometry` | 几何着色器编译 |
| `Compile_InvalidSource` | 无效源码编译失败 |
| `SetUniforms` | Uniform 设置 (int/float/vec3/mat4) |
#### 2.11 OpenGLPipelineState 测试3 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `SetDepthStencilState` | 深度/模板状态设置 |
| `SetBlendState` | 混合状态设置 |
| `SetViewport_SetScissor` | 视口/裁剪矩形 |
#### 2.12 OpenGLVertexArray 测试4 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_CreatesVAO` | VAO 创建 |
| `AddVertexBuffer` | 顶点缓冲添加 |
| `SetIndexBuffer` | 索引缓冲设置 |
| `Bind_Unbind` | VAO 绑定/解绑 |
#### 2.13 验证步骤
```bash
# 运行渲染管线测试
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.Shader*:OpenGLTestFixture.PipelineState*:OpenGLTestFixture.VertexArray*
# 预期结果
[==========] 11 tests from OpenGLTestFixture
[ PASSED ] 11 tests
```
---
### Phase 4: 命令与视图(约 1.5 天)
#### 2.14 OpenGLCommandList 测试8 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Clear_ColorBuffer` | 清除颜色缓冲 |
| `Clear_DepthStencil` | 清除深度/模板 |
| `SetVertexBuffer` | 设置顶点缓冲 |
| `SetIndexBuffer` | 设置索引缓冲 |
| `Draw_Triangles` | 绘制三角形 |
| `DrawIndexed_Indices` | 索引绘制 |
| `DrawInstanced` | 实例化绘制 |
| `Dispatch_ComputeShader` | 计算着色器分发 |
#### 2.15 OpenGLRenderTargetView 测试4 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_Texture2D` | 2D 纹理 RTV 创建 |
| `Initialize_Default` | 默认帧缓冲 RTV |
| `Bind_Unbind` | RTV 绑定/解绑 |
| `Clear_Color` | 清除颜色 |
#### 2.16 OpenGLDepthStencilView 测试4 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_Texture2D` | 2D 纹理 DSV 创建 |
| `Initialize_DepthOnly` | 仅深度 DSV |
| `Bind_Unbind` | DSV 绑定/解绑 |
| `ClearDepthStencil` | 清除深度/模板 |
#### 2.17 验证步骤
```bash
# 运行命令与视图测试
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.CommandList*:OpenGLTestFixture.RenderTargetView*:OpenGLTestFixture.DepthStencilView*
# 预期结果
[==========] 16 tests from OpenGLTestFixture
[ PASSED ] 16 tests
```
---
### Phase 5: 窗口管理(约 0.5 天)
#### 2.18 OpenGLSwapChain 测试3 个)
| 测试用例 | 验证内容 |
|----------|----------|
| `Initialize_Window` | 交换链初始化 |
| `Present_VSync` | 垂直同步显示 |
| `Resize_ChangesSize` | 调整大小 |
#### 2.19 验证步骤
```bash
# 运行窗口管理测试
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.SwapChain*
# 预期结果
[==========] 3 tests from OpenGLTestFixture
[ PASSED ] 3 tests
```
---
## 3. 完整验证
### 3.1 运行所有测试
```bash
# 完整测试
cmake --build build --config Debug
ctest --test-dir build -C Debug --output-on-failure
# 预期结果
[==========] 56 tests from 1 test suite.
[ PASSED ] 56 tests
```
### 3.2 测试分类统计
| 分类 | 数量 | 占比 |
|------|:----:|:----:|
| 初始化测试 | 18 | 32% |
| 绑定/解绑测试 | 10 | 18% |
| 数据操作测试 | 8 | 14% |
| 状态设置测试 | 10 | 18% |
| 绘制/执行测试 | 10 | 18% |
---
## 4. CI 配置
### 4.1 GitHub Actions
```yaml
# .github/workflows/opengl-tests.yml
name: OpenGL Tests
on: [push, pull_request]
jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Configure
run: cmake -B build -S . -G "Visual Studio 17 2022"
- name: Build
run: cmake --build build --config Debug
- name: Run Tests
run: ctest --test-dir build -C Debug --output-on-failure
```
### 4.2 Linux CI可选
Linux 下需要配置 Mesa 软件渲染:
```yaml
- name: Run Tests
env:
MESA_GL_VERSION_OVERRIDE: 4.6
MESA_GALLIUM_DRIVER: llvmpipe
run: ctest --test-dir build -C Debug --output-on-failure
```
---
## 5. 任务清单
### 阶段 1基础设施
- [ ] 1.1 创建 `tests/RHI/OpenGL/CMakeLists.txt`
- [ ] 1.2 创建 `tests/RHI/OpenGL/fixtures/OpenGLTestFixture.h`
- [ ] 1.3 创建 `tests/RHI/OpenGL/fixtures/OpenGLTestFixture.cpp`
- [ ] 1.4 实现 `test_device.cpp`6 个测试)
- [ ] 1.5 实现 `test_buffer.cpp`6 个测试)
- [ ] 1.6 实现 `test_fence.cpp`5 个测试)
- [ ] 1.7 构建验证17 个测试)
### 阶段 2资源管理
- [ ] 2.1 实现 `test_texture.cpp`5 个测试)
- [ ] 2.2 实现 `test_sampler.cpp`4 个测试)
- [ ] 2.3 构建验证9 个测试)
### 阶段 3渲染管线
- [ ] 3.1 实现 `test_shader.cpp`4 个测试)
- [ ] 3.2 实现 `test_pipeline_state.cpp`3 个测试)
- [ ] 3.3 实现 `test_vertex_array.cpp`4 个测试)
- [ ] 3.4 构建验证11 个测试)
### 阶段 4命令与视图
- [ ] 4.1 实现 `test_command_list.cpp`8 个测试)
- [ ] 4.2 实现 `test_render_target_view.cpp`4 个测试)
- [ ] 4.3 实现 `test_depth_stencil_view.cpp`4 个测试)
- [ ] 4.4 构建验证16 个测试)
### 阶段 5窗口管理
- [ ] 5.1 实现 `test_swap_chain.cpp`3 个测试)
- [ ] 5.2 完整测试验证56 个测试)
- [ ] 5.3 提交并推送
---
## 6. 关键注意事项
### 6.1 窗口依赖
- OpenGL 必须有 GLFW 窗口上下文
- 使用 `GLFW_VISIBLE = GLFW_FALSE` 创建隐藏窗口
- 每个测试前 `glfwMakeContextCurrent()`
### 6.2 GL 状态污染
- OpenGL 状态是全局的,必须隔离
- `TearDown()` 中重置所有 GL 状态
- 测试结束后 `glBindBuffer(..., 0)`
### 6.3 错误检查
- 使用 `GL_CHECK()` 宏验证每个 GL 调用
- 测试开始时 `GL_CLEAR_ERRORS()`
- 捕获 GL 错误并转换为测试失败
### 6.4 与 D3D12 对齐
- 保持相同的测试数量级54+
- 使用相同的 TEST_F 宏
- 遵循相同的命名约定
---
## 7. 后续工作
- [ ] 资源泄漏检测工具
- [ ] 性能基准测试
- [ ] 截图对比测试
- [ ] Linux CI 配置
- [ ] macOS 支持
---
**文档版本**1.0
**创建日期**2026年3月17日
**基于文档**`docs/OpenGL后端测试设计.md``tests/RHI/D3D12/`

View File

@@ -0,0 +1,144 @@
# RHI 模块严重问题OpenGL 后端 RHI 状态不生效
## 问题严重程度
**严重级别**: 🔴 Critical Bug
## 问题定位
`OpenGLPipelineState` 维护了两套状态系统,但它们之间没有关联。
### 两套状态系统
**RHI 抽象层状态** (`OpenGLPipelineState.h:131-133`)
```cpp
RasterizerDesc m_rasterizerDesc;
BlendDesc m_blendDesc;
DepthStencilStateDesc m_depthStencilDesc;
```
**OpenGL 特定状态** (`OpenGLPipelineState.h:141-143`)
```cpp
OpenGLDepthStencilState m_glDepthStencilState;
OpenGLBlendState m_glBlendState;
OpenGLRasterizerState m_glRasterizerState;
```
## 问题详述
### RHI 接口设置的状态只存储不生效
```cpp
// 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() 使用的是另一套状态
```cpp
// 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 抽象层设置的状态完全不会生效!**
```cpp
// 上层代码
RasterizerDesc raster;
raster.cullMode = 2; // 设置剔除模式
pso->SetRasterizerState(raster); // 通过 RHI 接口设置
// 实际渲染时
pso->Bind(); // 调用 ApplyRasterizer()
// ❌ m_glRasterizerState.cullMode 仍然是默认值,不是设置的值!
```
## 对比 D3D12 后端
D3D12 后端正确地在 `CreateD3D12PSO()` 中使用了 RHI 状态:
```cpp
// 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` 重载:
```cpp
// RHI 接口 - 只存储
void SetRasterizerState(const RasterizerDesc& state);
// OpenGL 特定接口 - 会生效
void SetRasterizerState(const OpenGLRasterizerState& state);
```
RHI 接口的实现缺少状态转换逻辑。
## 修复方案
`SetRasterizerState(const RasterizerDesc& state)` 中添加转换逻辑:
```cpp
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;
// ... 其他字段
}
```
同样需要修复 `SetBlendState``SetDepthStencilState`
## 相关文件
- `engine/include/XCEngine/RHI/OpenGL/OpenGLPipelineState.h`
- `engine/src/RHI/OpenGL/OpenGLPipelineState.cpp`
## 影响范围
1. **所有通过 RHI 抽象层设置的状态都不会生效**
2. **OpenGL 集成测试能工作是因为使用了 OpenGL 特定 API**
3. **上层代码如果使用 RHI 接口,行为会与预期不符**

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
# Renderer模块 EditorViewport缺少RenderSurface接入层
## 1. 问题定义
当前 editor 已经有:
- `GameViewPanel`
- `SceneViewPanel`
但二者目前仍然是空面板,尚未形成真正的 viewport 渲染宿主。
这意味着 Renderer 即使在 runtime 侧建立起来editor 侧也还没有标准方式去承接:
- 离屏 color/depth 输出
- viewport resize
- 渲染结果贴到 ImGui 面板
---
## 2. 当前现状
当前 `GameViewPanel::Render()``SceneViewPanel::Render()` 仅创建面板窗口,本身没有:
- 离屏渲染目标
- 渲染尺寸管理
- RHI / Renderer 级渲染输出对象
- 纹理到 ImGui 的桥接
也就是说editor 当前只有“面板外壳”,还没有“渲染宿主层”。
---
## 3. 为什么这不应该反向污染 Renderer 设计
这个问题很容易走偏成下面这种错误路线:
- 先把 renderer 直接写进 editor 面板逻辑
- `SceneView` 一套渲染逻辑
- `GameView` 一套渲染逻辑
- runtime 又一套渲染逻辑
这会导致:
- 渲染逻辑重复
- editor 与 runtime 耦合
- 后续 C# SRP 难以统一接管
因此正确思路不是“先让面板自己画”,而是:
1. Renderer 模块先支持统一的 `RenderSurface`
2. editor viewport 只作为 `RenderSurface` 的宿主与展示层
---
## 4. 建议方案
### 4.1 先在 Renderer 模块建立 `RenderSurface`
`RenderSurface` 应统一描述:
- swapchain 输出
- 离屏 color / depth 目标
- viewport 尺寸
- resize 行为
### 4.2 editor 侧建立 viewport host 层
editor 侧后续应新增一层专门承接:
- 面板尺寸变化
- 请求 Renderer 重建或 resize `RenderSurface`
- 把结果纹理显示到 ImGui
而不是把渲染实现直接塞进面板类。
### 4.3 `SceneView` 与 `GameView` 应共享同一套 Renderer 输出机制
区别只在于:
- `GameView` 使用 runtime camera
- `SceneView` 使用 editor 自有 camera / gizmo / overlay
但底层渲染输出机制应一致。
---
## 5. 与未来 Unity 风格演进的关系
未来如果要做接近 Unity 的 editor 与 SRP 体系,这一层非常关键。
因为 Unity 的:
- Game 视图
- Scene 视图
- Camera 预览
本质上都不是复制多套渲染器,而是在同一渲染体系上挂不同宿主与附加绘制。
XCEngine 也应遵循同样思路。
---
## 6. 验收标准
完成后至少应满足:
1. Renderer 能输出到离屏 `RenderSurface`
2. `GameView` 能显示 renderer 的离屏结果
3. `SceneView` 能显示 renderer 的离屏结果
4. viewport resize 不需要复制新的渲染逻辑
5. runtime 与 editor 共用同一套渲染宿主接口
---
## 7. 优先级
中到高。
它不是 Renderer v0 的第一步实现内容,但必须在 renderer 基础链路稳定后尽快接上,否则 editor 渲染体系会被迫走临时方案。

View File

@@ -0,0 +1,146 @@
# Renderer模块 Material与Shader资产模型暂不满足SRP演进需求
## 1. 问题定义
当前资源层已经具备:
- `Material`
- `Shader`
- `Texture`
但现有模型仍然偏“最小资源容器”,尚不足以直接承接未来 Unity 风格 Renderer / SRP 的完整需求。
当前最典型的问题是:
- `Shader` 更像“单个 stage shader 资源”
- `Material` 更像“shader 引用 + 属性包”
- 资产层缺少 pass / tag / render state / render queue 语义
---
## 2. 当前现状
从现有实现看:
### `Shader`
当前 `Shader` 资源主要描述:
- shader type
- shader language
- source / compiled binary
- uniforms / attributes
这更接近“单个 shader stage 对象”,而不是面向渲染管线选择的 shader asset。
### `Material`
当前 `Material` 资源主要描述:
- 一个 `Shader` 引用
- 属性表
- 纹理绑定表
当前 `MaterialLoader` 也只解析最基础的 `"shader"` 字段。
---
## 3. 为什么这会影响未来 Renderer / SRP
在未来的 Unity 风格渲染体系中Renderer / SRP 至少需要下列能力:
- 根据 shader pass/tag 选择绘制路径
- 区分 opaque / transparent / shadow caster / depth only 等 pass
- 用 render queue 控制排序层级
- 用 render state 描述 cull / blend / ztest / zwrite
- 为后续 keyword / variant 留空间
如果材质 / shader 资产模型长期停留在当前结构,会导致:
- 内建 forward 渲染可以临时跑起来
- 但未来一旦上 SRP就必须大规模重构资源资产模型
这会影响:
- Renderer
- Material 资源格式
- Shader 导入格式
- editor 材质面板
- 未来 C# SRP 的 pass 选择逻辑
---
## 4. 建议方向
### 4.1 不要让 `Shader` 永远停留在“单 stage 资源”
后续建议演进到更面向渲染管线的概念,例如:
- `ShaderAsset`
- `ShaderPass`
- 每个 pass 包含 vertex / fragment 等 stage 组合
- 每个 pass 具备 tag 与 render state 描述
### 4.2 `Material` 应逐步获得 renderer 需要的元数据
后续建议补充:
- render queue
- pass 相关 tag / override
- render state override
- shader keyword / variant 预留位
### 4.3 第一阶段可以先不一次性做全
但即使第一阶段只做 `UnlitTexture` / `SimpleLit`,也建议:
- 不把格式彻底写死成只有 `"shader"` 这一个入口
- 为 future pass/tag 结构预留升级路径
换句话说:
- 当前阶段可以简化实现
- 但不能封死演进路线
---
## 5. 与 Unity 风格的关系
未来如果要在 C# 层做接近 Unity 的 SRPshader pass 选择是核心能力之一。
例如:
- `ShaderTagId`
- `DrawingSettings`
- `FilteringSettings`
- renderer list / pass filtering
这些能力都要求材质与 shader 资产层至少能表达“pass/tag/state”。
因此,这个问题虽然不一定是 Renderer v0 第一周就要全量解决,但必须在设计阶段明确记录。
---
## 6. 建议验收标准
进入下一阶段时,至少应达到以下其中一档:
### 档位 A最小可演进
- 明确存在“shader pass”概念
- 材质资产格式有升级空间
- 内建 pipeline 能按 pass 选择绘制
### 档位 B更接近 SRP
- 具备 `pass + tag + render state + queue`
- 为 future keyword / variant 留接口
---
## 7. 优先级
中到高。
它不一定阻塞 Renderer v0 的第一步落地,但如果完全忽略,未来做 C# SRP 时会出现明显返工。

View File

@@ -0,0 +1,129 @@
# Renderer模块 Scene层缺少MeshFilter与MeshRenderer抽象
## 1. 问题定义
当前工程已经具备:
- `GameObject`
- `Component`
- `Scene`
- `CameraComponent`
- `LightComponent`
但仍然缺少最关键的可渲染组件抽象:
- `MeshFilterComponent`
- `MeshRendererComponent`
这会导致 Renderer 模块无法以“正式场景组件”的方式承接渲染对象。
---
## 2. 当前现状
从当前代码看:
- `GameObject` 已经支持通用组件挂载
- `Scene` 的序列化 / 反序列化已经依赖 `ComponentFactoryRegistry`
- `ComponentFactoryRegistry` 当前只注册了 `Camera``Light``AudioSource``AudioListener`
也就是说,场景层已经具备“扩展组件”的框架,但还没有真正承接渲染对象的组件类型。
---
## 3. 为什么这是 Renderer 阶段必须先补的缺口
如果没有正式的可渲染组件Renderer 会被迫依赖以下临时做法:
- 在测试里手工拼 mesh/material/transform
- 在 Renderer 内部写死资源路径或对象查找逻辑
- 把“场景对象”和“渲染对象”分裂成两套平行系统
这会直接破坏后续目标:
- 不利于 editor Inspector 展示
- 不利于场景序列化
- 不利于未来 C# API 对齐 Unity
- 不利于未来引入 `SkinnedMeshRenderer``SpriteRenderer` 等扩展
---
## 4. 与 Unity 风格的关系
如果未来要模仿 Unity 做 C# SRP那么场景组件模型最好一开始就尽量贴近 Unity。
因此建议不是只加一个大而全的 `MeshRendererComponent`,而是直接采用:
- `MeshFilterComponent`:持有 mesh
- `MeshRendererComponent`:持有材质和渲染状态
这样更容易在未来映射到:
- C# `MeshFilter`
- C# `MeshRenderer`
- Inspector 上的分离展示
- 脚本对 mesh / material 的分别访问
---
## 5. 建议方案
### 5.1 新增组件
#### `MeshFilterComponent`
最小建议字段:
- `ResourceHandle<Mesh> m_mesh`
#### `MeshRendererComponent`
最小建议字段:
- 材质数组
- `enabled`
- `castShadows`
- `receiveShadows`
- `renderLayer`
### 5.2 注册到 `ComponentFactoryRegistry`
这样场景文件才能:
- 正确反序列化
- 在 editor 中按组件类型恢复
- 为未来脚本与 Inspector 留入口
### 5.3 Renderer 只从组件层抽取渲染对象
Renderer 不应自行维护另一套“逻辑对象 -> 渲染对象”的临时注册表作为长期方案。
正确方式应是:
- `Scene`
- `GameObject`
- `MeshFilterComponent`
- `MeshRendererComponent`
共同构成 Renderer 的输入源。
---
## 6. 验收标准
完成后至少应满足:
1. 场景可正式挂载 mesh 渲染对象
2. `Scene` 序列化 / 反序列化可恢复对应组件
3. Renderer 可以直接从场景中提取可渲染对象
4. editor 后续可以直接复用同一套组件数据
5. 后续 C# API 可以平滑映射到 Unity 风格组件模型
---
## 7. 优先级
高。
这是 Renderer 模块正式落地前必须解决的前置缺口。

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,335 @@
# 第三阶段计划OpenGL 后端实现
> **目标**:实现 OpenGL 后端,完成 RHI 跨平台图形抽象
> **阶段**:第三阶段
> **前置依赖**:第二阶段 RHI 抽象层与 D3D12 后端
---
## 3.1 阶段目标
在已有 RHI 抽象层和 D3D12 后端的基础上,实现 OpenGL 后端:
- 复用现有抽象接口
- 对接 OpenGL (GLFW + GLAD)
- 支持最小渲染系统验证
---
## 3.2 目录结构
```
engine/include/XCEngine/RHI/OpenGL/
├── OpenGLCommon.h # OpenGL 公共定义与辅助函数
├── OpenGLEnum.h # RHI 枚举 → OpenGL 枚举转换层
├── OpenGLDevice.h # 设备初始化
├── OpenGLDevice.cpp
├── OpenGLSwapChain.h # 交换链GLFW 窗口)
├── OpenGLSwapChain.cpp
├── OpenGLCommandList.h # 命令列表封装
├── OpenGLCommandList.cpp
├── OpenGLBuffer.h # VBO/IBO/UBO 管理
├── OpenGLBuffer.cpp
├── OpenGLTexture.h # 纹理管理
├── OpenGLTexture.cpp
├── OpenGLShader.h # GLSL 着色器
├── OpenGLShader.cpp
├── OpenGLPipelineState.h # VAO + Program + State
├── OpenGLPipelineState.cpp
├── OpenGLRenderTarget.h # FBO + RTV
├── OpenGLRenderTarget.cpp
├── OpenGLDepthStencil.h # 深度模板
├── OpenGLDepthStencil.cpp
├── OpenGLDescriptorHeap.h # Texture Unit 模拟
├── OpenGLDescriptorHeap.cpp
├── OpenGLFence.h # 同步
├── OpenGLFence.cpp
├── OpenGLQueryHeap.h # 查询堆
├── OpenGLQueryHeap.cpp
├── OpenGLRootSignature.h # 简化实现
├── OpenGLRootSignature.cpp
├── OpenGLSampler.h # 采样器
├── OpenGLSampler.cpp
├── OpenGLResourceView.h # 视图基类
├── OpenGLResourceView.cpp
└── OpenGLRenderTargetView.h # 渲染目标视图
├── OpenGLRenderTargetView.cpp
├── OpenGLDepthStencilView.h
├── OpenGLDepthStencilView.cpp
├── OpenGLShaderResourceView.h
├── OpenGLShaderResourceView.cpp
├── OpenGLUnorderedAccessView.h
├── OpenGLUnorderedAccessView.cpp
├── OpenGLConstantBufferView.h
└── OpenGLConstantBufferView.cpp
```
---
## 3.3 任务拆分
### 3.3.1 基础准备
**任务 3.1OpenGLEnum.h - 枚举转换层**
实现 RHI 枚举到 OpenGL 枚举的转换:
- `Format``GLenum`
- `PrimitiveTopology``GLenum`
- `BlendOp` / `BlendFactor``GLenum`
- `ComparisonFunc``GLenum`
- `ResourceStates``GLenum` (简化)
- `ShaderType``GLenum`
**任务 3.2OpenGLCommon.h - 公共定义**
- OpenGL 初始化辅助函数
- 格式支持检测
- 错误检查宏
- GLAD 加载器封装
---
### 3.3.2 核心组件实现
**任务 3.3OpenGLDevice - 设备实现**
实现 `OpenGLDevice` 类:
- GLFW 窗口创建
- GLAD 初始化
- OpenGL 上下文配置
- 设备信息查询
```cpp
class OpenGLDevice : public IRHIDevice {
public:
bool Initialize(void* windowHandle, bool enableDebug = false);
GLFWwindow* GetWindow() const { return m_window; }
// IRHIDevice 实现...
private:
GLFWwindow* m_window;
HGLRC m_glContext;
};
```
**任务 3.4OpenGLSwapChain - 交换链实现**
实现 `OpenGLSwapChain` 类:
- GLFW 窗口管理
- 双缓冲切换
- 帧缓冲 resize 处理
**任务 3.5OpenGLShader - 着色器实现**
实现 `OpenGLShader` 类:
- GLSL 源码加载
- `glShaderSource` + `glCompileShader`
- 编译错误获取
- 反射数据提取(可选)
**任务 3.6OpenGLBuffer - 缓冲区实现**
实现 `OpenGLBuffer` 类:
- VBO 创建与管理
- IBO 索引缓冲
- UBO uniform 缓冲
- Buffer mapping
**任务 3.7OpenGLTexture - 纹理实现**
实现 `OpenGLTexture` 类:
- 2D 纹理创建
- 纹理参数设置
- Mipmap 生成
- 纹理绑定
**任务 3.8OpenGLPipelineState - 管线状态实现**
实现 `OpenGLPipelineState` 类:
- VAO 管理
- Shader Program 链接
- 状态缓存blend, depth, rasterizer
- 输入布局映射
**任务 3.9OpenGLCommandList - 命令列表实现**
实现 `OpenGLCommandList` 类:
- 状态缓存与批量提交
- `glDrawArrays` / `glDrawElements` 封装
- 视口裁剪设置
- 渲染目标绑定
**任务 3.10OpenGLFence - 同步实现**
实现 `OpenGLFence` 类:
- `glFenceSync` 封装
- CPU 等待实现
**任务 3.11OpenGLDescriptorHeap - 描述符堆实现**
实现 `OpenGLDescriptorHeap` 类:
- Texture Unit 数组管理
- 简化版描述符绑定
---
### 3.3.3 视图实现
**任务 3.12OpenGLRenderTargetView - 渲染目标视图**
- Framebuffer 对象管理
- 颜色附件绑定
**任务 3.13OpenGLDepthStencilView - 深度模板视图**
- Depth/stencil buffer 管理
- FBO 深度附件
**任务 3.14OpenGLShaderResourceView - 着色器资源视图**
- 纹理视图绑定到 Texture Unit
**任务 3.15OpenGLUnorderedAccessView - 无序访问视图**
- SSBO 管理
**任务 3.16OpenGLConstantBufferView - 常量缓冲区视图**
- UBO 绑定
---
## 3.4 D3D12 与 OpenGL 关键差异
| D3D12 组件 | OpenGL 对应 | 差异说明 |
|------------|-------------|----------|
| `ID3D12Device` | `OpenGLDevice` | GLFW + GLAD 初始化 |
| `ID3D12CommandQueue` | 简化 | OpenGL 无需显式命令队列 |
| `ID3D12CommandList` | `OpenGLCommandList` | 封装立即模式渲染 |
| `ID3D12DescriptorHeap` | `OpenGLDescriptorHeap` | 使用 Texture Unit 模拟 |
| `ID3D12PipelineState` | `OpenGLPipelineState` | VAO + Program + State |
| `ID3D12RootSignature` | 简化 | 使用 uniform binding |
| `ID3D12Fence` | `OpenGLFence` | glFenceSync |
| `ID3D12SwapChain` | `OpenGLSwapChain` | GLFW 窗口管理 |
| `ID3D12Buffer` | `OpenGLBuffer` | VBO/IBO/UBO |
| `ID3D12Texture` | `OpenGLTexture` | GL 纹理对象 |
| `ID3D12Shader` | `OpenGLShader` | GLSL 编译 |
| `ID3D12QueryHeap` | `OpenGLQueryHeap` | GL 查询对象 |
---
## 3.5 实现顺序
```
阶段 3.1: 基础准备 (1天)
├── 3.1.1 OpenGLEnum.h (枚举转换)
└── 3.1.2 OpenGLCommon.h (公共定义)
阶段 3.2: 核心组件 (4天)
├── 3.2.1 OpenGLDevice
├── 3.2.2 OpenGLSwapChain
├── 3.2.3 OpenGLShader
├── 3.2.4 OpenGLBuffer
├── 3.2.5 OpenGLTexture
├── 3.2.6 OpenGLPipelineState
└── 3.2.7 OpenGLCommandList
阶段 3.3: 辅助组件 (2天)
├── 3.3.1 OpenGLFence
├── 3.3.2 OpenGLDescriptorHeap
├── 3.3.3 OpenGLQueryHeap
├── 3.3.4 OpenGLSampler
└── 3.3.5 OpenGLRootSignature
阶段 3.4: 视图实现 (1天)
├── 3.4.1 OpenGLRenderTargetView
├── 3.4.2 OpenGLDepthStencilView
├── 3.4.3 OpenGLShaderResourceView
├── 3.4.4 OpenGLUnorderedAccessView
└── 3.4.5 OpenGLConstantBufferView
阶段 3.5: 集成测试 (1天)
├── 窗口创建与渲染循环
├── 简单模型渲染测试
└── 与 mvs/OpenGL 功能对比验证
```
---
## 3.6 关键技术点
### 3.6.1 状态管理
OpenGL 是状态机模式:
-`OpenGLCommandList` 中缓存当前状态
- 绘制前检查状态变化,仅调用变化的 GL 函数
- 避免冗余状态设置
### 3.6.2 资源绑定
D3D12: Descriptor Heap + Root Signature
OpenGL: Texture Unit + Uniform Location
```cpp
// OpenGL 方式
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(location, slot);
```
### 3.6.3 着色器编译
```cpp
// GLSL 编译
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, nullptr);
glCompileShader(vertexShader);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
```
### 3.6.4 VAO 管理
```cpp
// Vertex Array Object
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
```
### 3.6.5 帧缓冲
```cpp
// Framebuffer Object
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthID, 0);
```
---
## 3.7 验收标准
1. **编译通过**:所有头文件和实现文件能够无错误编译
2. **接口完整**:所有 RHI 抽象接口都有 OpenGL 实现
3. **功能验证**
- 能够创建 GLFW 窗口并初始化 OpenGL 上下文
- 能够渲染简单的几何体
- 能够加载和显示纹理
- 能够呈现到屏幕
4. **功能对比**:与现有 mvs/OpenGL 功能一致
---
## 3.8 后续阶段依赖
- 第四阶段渲染管线RenderPipeline需要 RHI 多后端支持
- 材质系统需要统一的 Shader 接口
- 跨平台渲染验证需要 OpenGL 后端

View File

@@ -0,0 +1,829 @@
# 第二阶段计划RHI 渲染硬件抽象层
> **目标**构建跨平台的渲染硬件抽象层支持多后端D3D12、Vulkan等
> **阶段**:第二阶段
> **前置依赖**:第一阶段核心基础层(数学库、内存管理、线程系统)
---
## 2.1 阶段目标
实现完整的RHI抽象层提供
- 统一的图形API抽象接口
- D3D12后端完整实现
- 资源管理(纹理、缓冲区)
- 命令流提交机制
- 同步与同步原语
---
## 2.2 目录结构
```
engine/include/XCEngine/RHI/ # 渲染硬件抽象层公开API
├── Enums.h # 枚举定义(独立编号,跨平台)
├── Types.h # 通用类型定义
├── RHISystem.h # RHI 系统入口
├── RHIDevice.h # 抽象设备接口
├── Resource.h # 资源基类接口
├── ResourceView.h # 资源视图基类接口
├── RenderTargetView.h # 渲染目标视图接口
├── DepthStencilView.h # 深度模板视图接口
├── ShaderResourceView.h # 着色器资源视图接口
├── UnorderedAccessView.h # 无序访问视图接口
├── ConstantBufferView.h # 常量缓冲区视图接口
├── CommandQueue.h # 命令队列
├── CommandList.h # 命令列表
├── CommandAllocator.h # 命令分配器
├── Fence.h # 同步围栏
├── DescriptorHeap.h # 描述符堆
├── QueryHeap.h # 查询堆
├── RootSignature.h # 根签名
├── PipelineState.h # 管线状态
├── Sampler.h # 采样器
├── SwapChain.h # 交换链
├── Texture.h # 纹理资源
├── Buffer.h # 缓冲区资源
├── Shader.h # 着色器
└── D3D12/ # D3D12 后端实现
├── D3D12Enum.h # 枚举转换层RHI→D3D12
├── D3D12Device.h
├── D3D12Device.cpp
├── D3D12CommandList.h
├── D3D12CommandList.cpp
├── D3D12CommandQueue.h
├── D3D12CommandQueue.cpp
├── D3D12CommandAllocator.h
├── D3D12CommandAllocator.cpp
├── D3D12Fence.h
├── D3D12Fence.cpp
├── D3D12DescriptorHeap.h
├── D3D12DescriptorHeap.cpp
├── D3D12QueryHeap.h
├── D3D12QueryHeap.cpp
├── D3D12RootSignature.h
├── D3D12RootSignature.cpp
├── D3D12PipelineState.h
├── D3D12PipelineState.cpp
├── D3D12Sampler.h
├── D3D12Sampler.cpp
├── D3D12SwapChain.h
├── D3D12SwapChain.cpp
├── D3D12Texture.h
├── D3D12Texture.cpp
├── D3D12Buffer.h
├── D3D12Buffer.cpp
├── D3D12Shader.h
├── D3D12Shader.cpp
├── D3D12RenderTargetView.h
├── D3D12RenderTargetView.cpp
├── D3D12DepthStencilView.h
├── D3D12DepthStencilView.cpp
├── D3D12ShaderResourceView.h
├── D3D12ShaderResourceView.cpp
├── D3D12UnorderedAccessView.h
├── D3D12UnorderedAccessView.cpp
├── D3D12ConstantBufferView.h
├── D3D12ConstantBufferView.cpp
└── D3D12Common.h # 公共定义
```
---
## 2.3 任务拆分
### 2.3.1 基础枚举与类型定义
**任务 2.1Enums.h - 枚举定义**
定义所有渲染相关的枚举类型:
- `Format` - 像素格式
- `ResourceStates` - 资源状态
- `ShaderType` - 着色器类型
- `PrimitiveTopology` - 图元拓扑
- `CullMode` / `FillMode` - 剔除/填充模式
- `BlendOp` / `BlendFactor` - 混合操作/因子
- `ComparisonFunc` - 比较函数
- `StencilOp` - 模板操作
- `TextureType` - 纹理类型
- `BufferType` - 缓冲区类型
- `QueryType` - 查询类型
- `DescriptorType` - 描述符类型
- `PipelineType` - 管线类型
- `CommandQueueType` - 命令队列类型
- `LoadAction` / `StoreAction` - 渲染目标加载/存储操作
- `PresentFlags` - 呈现标志
- `IndirectDrawArguments` - 间接绘制参数
- `IndirectDispatchArguments` - 间接调度参数
**任务 2.1.2:类型定义 - Types.h**
定义通用结构体不依赖特定图形API
- `Viewport` - 视口
- `Rect` - 矩形区域
- `Color` - 颜色
- `ClearValue` - 清空值
- `ShaderCompileDesc` - 着色器编译描述
- `ShaderCompileResult` - 着色器编译结果
- `ShaderCompileMacro` - 着色器宏定义
- `InputElementDesc` - 输入元素描述
- `InputLayoutDesc` - 输入布局描述
- `VertexBufferBinding` - 顶点缓冲区绑定
- `TextureCopyLocation` - 纹理复制位置
- `DescriptorHandle` - 描述符句柄(通用类型)
- `GPUDescriptorHandle` - GPU描述符句柄
- `CPUDescriptorHandle` - CPU描述符句柄
- `ResourceBarrierDesc` - 资源屏障描述
- `SubresourceRange` - 子资源范围
- `TextureDesc` - 纹理描述
- `BufferDesc` - 缓冲区描述
- `RenderTargetDesc` - 渲染目标描述
- `DepthStencilDesc` - 深度模板描述
- `DescriptorHeapDesc` - 描述符堆描述
- `CommandQueueDesc` - 命令队列描述
- `CommandListDesc` - 命令列表描述
- `CommandAllocatorDesc` - 命令分配器描述
- `FenceDesc` - 围栏描述
- `QueryHeapDesc` - 查询堆描述
- `RootSignatureDesc` - 根签名描述
- `SamplerDesc` - 采样器描述
- `PipelineStateDesc` - 管线状态描述
- `SwapChainDesc` - 交换链描述
- `BlendStateDesc` - 混合状态描述
- `DepthStencilStateDesc` - 深度模板状态描述
- `RasterizerStateDesc` - 光栅化状态描述
- `ShaderBytecode` - 着色器字节码
- `ShaderBindingInfo` - 着色器绑定信息
- `RenderTargetViewDesc` - 渲染目标视图描述
- `DepthStencilViewDesc` - 深度模板视图描述
- `ShaderResourceViewDesc` - 着色器资源视图描述
- `UnorderedAccessViewDesc` - 无序访问视图描述
- `ConstantBufferViewDesc` - 常量缓冲区视图描述
- `FormatSupport` - 格式支持信息
### 2.3.2 核心接口定义
**任务 2.2RHISystem.h - RHI系统入口**
```cpp
struct RHISystemConfig {
void* nativeWindowHandle = nullptr; // HWND on Windows
uint32_t width = 1280;
uint32_t height = 720;
bool fullscreen = false;
uint32_t backBufferCount = 2;
bool enableDebugLayer = false;
bool enableGBV = false;
};
class RHISystem {
public:
static RHISystem& Get();
bool Initialize(const RHISystemConfig& config);
void Shutdown();
IRHIDevice* GetDevice();
ISwapChain* GetSwapChain();
void BeginFrame();
void EndFrame();
// 窗口管理
void Resize(uint32_t width, uint32_t height);
void SetFullscreen(bool fullscreen);
bool IsFullscreen() const;
private:
std::unique_ptr<IRHIDevice> m_device;
std::unique_ptr<ISwapChain> m_swapChain;
};
```
**任务 2.3RHIDevice.h - 抽象设备接口**
```cpp
struct DeviceInfo {
String deviceName;
String driverVersion;
uint64_t dedicatedVideoMemory;
uint64_t dedicatedSystemMemory;
uint64_t sharedSystemMemory;
uint32_t vendorId;
uint32_t deviceId;
bool supportsRaytracing;
bool supportsMeshShaders;
bool supportsSamplerFeedback;
};
class IRHIDevice {
public:
virtual ~IRHIDevice() = default;
// 资源创建
virtual ICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) = 0;
virtual ICommandList* CreateCommandList(const CommandListDesc& desc) = 0;
virtual ICommandAllocator* CreateCommandAllocator(const CommandAllocatorDesc& desc) = 0;
virtual IFence* CreateFence(const FenceDesc& desc) = 0;
virtual IDescriptorHeap* CreateDescriptorHeap(const DescriptorHeapDesc& desc) = 0;
virtual IQueryHeap* CreateQueryHeap(const QueryHeapDesc& desc) = 0;
virtual IRootSignature* CreateRootSignature(const RootSignatureDesc& desc) = 0;
virtual IPipelineState* CreatePipelineState(const PipelineStateDesc& desc) = 0;
virtual ISampler* CreateSampler(const SamplerDesc& desc) = 0;
virtual ITexture* CreateTexture(const TextureDesc& desc) = 0;
virtual IBuffer* CreateBuffer(const BufferDesc& desc) = 0;
virtual ISwapChain* CreateSwapChain(const SwapChainDesc& desc) = 0;
// 视图创建
virtual IRenderTargetView* CreateRenderTargetView(IResource* resource, const RenderTargetViewDesc& desc) = 0;
virtual IDepthStencilView* CreateDepthStencilView(IResource* resource, const DepthStencilViewDesc& desc) = 0;
virtual IShaderResourceView* CreateShaderResourceView(IResource* resource, const ShaderResourceViewDesc& desc) = 0;
virtual IUnorderedAccessView* CreateUnorderedAccessView(IResource* resource, const UnorderedAccessViewDesc& desc) = 0;
virtual IConstantBufferView* CreateConstantBufferView(IResource* resource, const ConstantBufferViewDesc& desc) = 0;
// 着色器编译
virtual IShader* CompileShader(const ShaderCompileDesc& desc) = 0;
// 查询
virtual void GetDeviceInfo(DeviceInfo& info) const = 0;
virtual FormatSupport GetFormatSupport(Format format) const = 0;
};
```
**任务 2.4CommandQueue.h - 命令队列接口**
```cpp
class ICommandQueue {
public:
virtual ~ICommandQueue() = default;
virtual void ExecuteCommandLists(uint32_t count, ICommandList** lists) = 0;
virtual void Signal(IFence* fence, uint64_t value) = 0;
virtual void Wait(IFence* fence, uint64_t value) = 0;
virtual uint64_t GetCompletedValue() = 0;
virtual void WaitForIdle() = 0;
virtual CommandQueueType GetType() const = 0;
virtual uint64_t GetTimestampFrequency() const = 0;
};
```
**任务 2.5CommandList.h - 命令列表接口**
```cpp
class ICommandList {
public:
virtual ~ICommandList() = default;
// 状态转换
virtual void TransitionBarrier(uint32_t count, const ResourceBarrierDesc* barriers) = 0;
virtual void UAVBarrier(IResource* resource = nullptr) = 0;
virtual void AliasBarrier(IResource* before, IResource* after) = 0;
// 渲染状态
virtual void SetPipelineState(IPipelineState* pso) = 0;
virtual void SetRootSignature(IRootSignature* signature) = 0;
virtual void SetViewport(const Viewport& viewport) = 0;
virtual void SetViewports(uint32_t count, const Viewport* viewports) = 0;
virtual void SetScissorRect(const Rect& rect) = 0;
virtual void SetScissorRects(uint32_t count, const Rect* rects) = 0;
virtual void SetPrimitiveTopology(PrimitiveTopology topology) = 0;
virtual void SetRenderTargets(uint32_t count, IResource** renderTargets, IResource* depthStencil) = 0;
// 绑定
virtual void SetVertexBuffer(uint32_t slot, IBuffer* buffer, uint32_t offset, uint32_t stride) = 0;
virtual void SetVertexBuffers(uint32_t startSlot, uint32_t count, const VertexBufferBinding* bindings) = 0;
virtual void SetIndexBuffer(IBuffer* buffer, uint32_t offset, Format indexFormat) = 0;
virtual void SetConstantBuffer(uint32_t rootParameterIndex, IBuffer* buffer, uint32_t offset, uint32_t size) = 0;
virtual void SetShaderResource(uint32_t rootParameterIndex, IResource* resource) = 0;
virtual void SetUnorderedAccess(uint32_t rootParameterIndex, IResource* resource) = 0;
virtual void SetDescriptorHeap(IDescriptorHeap* heap) = 0;
virtual void SetGraphicsDescriptorTable(uint32_t rootParameterIndex, GPUDescriptorHandle baseHandle) = 0;
virtual void SetComputeDescriptorTable(uint32_t rootParameterIndex, GPUDescriptorHandle baseHandle) = 0;
// 渲染状态设置
virtual void SetStencilRef(uint8_t stencilRef) = 0;
virtual void SetBlendFactor(const float blendFactor[4]) = 0;
virtual void SetDepthBias(float depthBias, float slopeScaledDepthBias, float depthBiasClamp) = 0;
// 绘制
virtual void Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) = 0;
virtual void DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) = 0;
virtual void DrawInstancedIndirect(IBuffer* argBuffer, uint32_t alignedByteOffset) = 0;
virtual void DrawIndexedInstancedIndirect(IBuffer* argBuffer, uint32_t alignedByteOffset) = 0;
// 清空
virtual void ClearRenderTargetView(IResource* renderTarget, const float color[4]) = 0;
virtual void ClearDepthStencilView(IResource* depthStencil, uint32_t clearFlags, float depth, uint8_t stencil) = 0;
virtual void ClearUnorderedAccessView(IResource* unorderedAccess, const float values[4]) = 0;
// 复制
virtual void CopyResource(IResource* dst, IResource* src) = 0;
virtual void CopyBuffer(IBuffer* dst, uint64_t dstOffset, IBuffer* src, uint64_t srcOffset, uint64_t size) = 0;
virtual void CopyTexture(ITexture* dst, const TextureCopyLocation& dstLocation, ITexture* src, const TextureCopyLocation& srcLocation) = 0;
// 查询
virtual void BeginQuery(IQueryHeap* queryHeap, QueryType type, uint32_t index) = 0;
virtual void EndQuery(IQueryHeap* queryHeap, QueryType type, uint32_t index) = 0;
virtual void ResolveQuery(IQueryHeap* queryHeap, QueryType type, uint32_t startIndex, uint32_t count, IBuffer* resultBuffer, uint64_t resultOffset) = 0;
// 提交
virtual void Close() = 0;
virtual void Reset(ICommandAllocator* allocator) = 0;
// 计算着色器
virtual void Dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) = 0;
virtual void DispatchIndirect(IBuffer* argBuffer, uint32_t alignedByteOffset) = 0;
// Bundle (用于命令复用)
virtual void ExecuteBundle(ICommandList* bundle) = 0;
};
```
**任务 2.6:其他核心接口**
- `Resource.h` - 资源基类接口(所有资源的共同基类)
- `ResourceView.h` - 资源视图基类接口
- `RenderTargetView.h` - 渲染目标视图接口
- `DepthStencilView.h` - 深度模板视图接口
- `ShaderResourceView.h` - 着色器资源视图接口
- `UnorderedAccessView.h` - 无序访问视图接口
- `ConstantBufferView.h` - 常量缓冲区视图接口
- `CommandAllocator.h` - 命令分配器接口
```cpp
class ICommandAllocator {
public:
virtual ~ICommandAllocator() = default;
virtual void Reset() = 0;
virtual bool IsReady() const = 0;
};
```
- `Fence.h` - 同步围栏接口
```cpp
class IFence {
public:
virtual ~IFence() = default;
virtual void Signal(uint64_t value) = 0;
virtual void Wait(uint64_t value) = 0;
virtual uint64_t GetCompletedValue() = 0;
virtual void* GetEventHandle() = 0;
};
```
- `DescriptorHeap.h` - 描述符堆接口
```cpp
class IDescriptorHeap {
public:
virtual ~IDescriptorHeap() = default;
virtual CPUDescriptorHandle GetCPUDescriptorHandle(uint32_t index) = 0;
virtual GPUDescriptorHandle GetGPUDescriptorHandle(uint32_t index) = 0;
virtual uint32_t GetDescriptorCount() const = 0;
virtual DescriptorType GetType() const = 0;
};
```
- `QueryHeap.h` - 查询堆接口
```cpp
class IQueryHeap {
public:
virtual ~IQueryHeap() = default;
virtual void* GetNativeHandle() const = 0;
virtual QueryType GetType() const = 0;
virtual uint32_t GetCount() const = 0;
};
```
- `RootSignature.h` - 根签名接口
```cpp
class IRootSignature {
public:
virtual ~IRootSignature() = default;
virtual void* GetNativeHandle() const = 0;
virtual uint32_t GetParameterCount() const = 0;
};
```
- `PipelineState.h` - 管线状态接口
```cpp
class IPipelineState {
public:
virtual ~IPipelineState() = default;
virtual void* GetNativeHandle() const = 0;
virtual PipelineType GetType() const = 0;
};
```
- `Sampler.h` - 采样器接口
```cpp
class ISampler {
public:
virtual ~ISampler() = default;
virtual void* GetNativeHandle() const = 0;
};
```
- `SwapChain.h` - 交换链接口
```cpp
class ISwapChain {
public:
virtual ~ISwapChain() = default;
virtual uint32_t GetCurrentBackBufferIndex() = 0;
virtual IResource* GetBackBuffer(uint32_t index) = 0;
virtual void Present(uint32_t syncInterval, PresentFlags flags) = 0;
virtual void Resize(uint32_t width, uint32_t height) = 0;
virtual void SetFullscreen(bool fullscreen) = 0;
virtual bool IsFullscreen() const = 0;
virtual void* GetNativeHandle() const = 0;
};
```
- `Texture.h` - 纹理资源接口
```cpp
class ITexture : public IResource {
public:
virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0;
virtual uint32_t GetDepth() const = 0;
virtual uint32_t GetMipLevels() const = 0;
virtual uint32_t GetArraySize() const = 0;
virtual Format GetFormat() const = 0;
virtual TextureType GetTextureType() const = 0;
virtual IShaderResourceView* GetOrCreateSRV() = 0;
virtual IRenderTargetView* GetOrCreateRTV(uint32_t mipSlice = 0, uint32_t arraySlice = 0) = 0;
virtual IDepthStencilView* GetOrCreateDSV(uint32_t mipSlice = 0, uint32_t arraySlice = 0) = 0;
virtual IUnorderedAccessView* GetOrCreateUAV(uint32_t mipSlice = 0, uint32_t arraySlice = 0) = 0;
};
```
- `Buffer.h` - 缓冲区资源接口
```cpp
class IBuffer : public IResource {
public:
virtual uint64_t GetSize() const = 0;
virtual uint32_t GetStride() const = 0;
virtual BufferType GetBufferType() const = 0;
virtual IConstantBufferView* GetOrCreateCBV() = 0;
virtual IShaderResourceView* GetOrCreateSRV() = 0;
virtual IUnorderedAccessView* GetOrCreateUAV() = 0;
};
```
- `Shader.h` - 着色器接口
```cpp
class IShader {
public:
virtual ~IShader() = default;
virtual const void* GetBytecode() const = 0;
virtual size_t GetBytecodeSize() const = 0;
virtual ShaderType GetType() const = 0;
virtual const InputLayoutDesc& GetInputLayout() const = 0;
virtual const ShaderBindingInfo& GetBindingInfo() const = 0;
};
```
- `RenderTarget.h` - 渲染目标接口
```cpp
class IRenderTarget {
public:
virtual ~IRenderTarget() = default;
virtual ITexture* GetTexture() = 0;
virtual IRenderTargetView* GetRTV() = 0;
virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0;
virtual Format GetFormat() const = 0;
};
```
- `DepthStencil.h` - 深度模板接口
```cpp
class IDepthStencil {
public:
virtual ~IDepthStencil() = default;
virtual ITexture* GetTexture() = 0;
virtual IDepthStencilView* GetDSV() = 0;
virtual IShaderResourceView* GetSRV() = 0;
virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0;
virtual Format GetFormat() const = 0;
};
```
**任务 2.7Resource.h - 资源基类接口**
```cpp
class IResource {
public:
virtual ~IResource() = default;
virtual void* GetNativeHandle() const = 0;
virtual ResourceStates GetState() const = 0;
virtual void SetState(ResourceStates state) = 0;
virtual uint64_t GetGPUAddress() const = 0;
virtual size_t GetSize() const = 0;
virtual const String& GetName() const = 0;
virtual void SetName(const String& name) = 0;
};
```
**任务 2.8ResourceView.h - 资源视图基类接口**
```cpp
class IResourceView {
public:
virtual ~IResourceView() = default;
virtual void* GetNativeHandle() const = 0;
virtual IResource* GetResource() const = 0;
};
```
---
### 2.3.3 D3D12 后端实现
**任务 2.9D3D12Common.h - 公共定义**
D3D12相关的公共定义和辅助函数
- 格式转换映射
- 描述符大小计算
- 资源状态转换
- 辅助工具函数
**任务 2.10D3D12Device - 设备实现**
实现 `D3D12Device` 类:
- ID3D12Device 封装
- IDXGIFactory 创建与管理
- 所有资源创建接口实现
- 适配器信息查询
- 功能级别支持检测
- 内存信息查询
- 设备移除与恢复处理
**任务 2.11D3D12CommandQueue - 命令队列实现**
实现 `D3D12CommandQueue` 类:
- ID3D12CommandQueue 封装
- 命令列表执行
- 围栏同步
- 时间戳频率查询
**任务 2.12D3D12CommandList - 命令列表实现**
实现 `D3D12CommandList` 类:
- ID3D12GraphicsCommandList 封装
- 所有渲染命令实现
- 状态追踪与验证
- 资源追踪
**任务 2.13D3D12CommandAllocator - 命令分配器实现**
实现 `D3D12CommandAllocator` 类:
- ID3D12CommandAllocator 封装
- 重置管理
**任务 2.14D3D12Fence - 围栏实现**
实现 `D3D12Fence` 类:
- ID3D12Fence 封装
- CPU/GPU同步
- 事件句柄管理
**任务 2.15D3D12DescriptorHeap - 描述符堆实现**
实现 `D3D12DescriptorHeap` 类:
- ID3D12DescriptorHeap 封装
- CPU/GPU描述符句柄管理
- 描述符分配/释放
- 堆增量大小计算
**任务 2.16D3D12RootSignature - 根签名实现**
实现 `D3D12RootSignature` 类:
- ID3D12RootSignature 封装
- 根参数配置
- 描述符表布局
- 静态采样器
**任务 2.17D3D12PipelineState - 管线状态实现**
实现 `D3D12PipelineState` 类:
- ID3D12PipelineState 封装
- 图形管线描述构建
- 计算管线描述构建
- 混合状态
- 深度模板状态
- 输入布局
- 顶点/像素着色器绑定
**任务 2.18D3D12Sampler - 采样器实现**
实现 `D3D12Sampler` 类:
- D3D12_SAMPLER_DESC 封装
- 静态采样器支持
**任务 2.19D3D12QueryHeap - 查询堆实现**
实现 `D3D12QueryHeap` 类:
- ID3D12QueryHeap 封装
- 时间戳查询
- 遮挡查询
- 流水线统计
**任务 2.20D3D12SwapChain - 交换链实现**
实现 `D3D12SwapChain` 类:
- IDXGISwapChain3 封装
- 帧缓冲管理
- 呈现模式配置
- 完整屏幕支持
**任务 2.21D3D12Texture - 纹理实现**
实现 `D3D12Texture` 类:
- ID3D12Resource 封装
- 纹理描述
- 子资源管理
- 视图创建SRV, RTV, DSV, UAV
- 状态管理
**任务 2.22D3D12Buffer - 缓冲区实现**
实现 `D3D12Buffer` 类:
- ID3D12Resource 封装
- 缓冲区描述
- 视图创建SRV, CBV, UAV
- 上传堆管理
- 默认堆管理
**任务 2.23D3D12Shader - 着色器实现**
实现 `D3D12Shader` 类:
- 着色器字节码管理
- 反射数据提取
- 输入布局构建
**任务 2.24D3D12RenderTargetView - 渲染目标视图实现**
实现 `D3D12RenderTargetView` 类:
- ID3D12RenderTargetView 封装
- 描述符创建与管理
**任务 2.25D3D12DepthStencilView - 深度模板视图实现**
实现 `D3D12DepthStencilView` 类:
- ID3D12DepthStencilView 封装
- 描述符创建与管理
**任务 2.26D3D12ShaderResourceView - 着色器资源视图实现**
实现 `D3D12ShaderResourceView` 类:
- ID3D12ShaderResourceView 封装
- 描述符创建与管理
**任务 2.27D3D12UnorderedAccessView - 无序访问视图实现**
实现 `D3D12UnorderedAccessView` 类:
- ID3D12UnorderedAccessView 封装
- 描述符创建与管理
**任务 2.28D3D12ConstantBufferView - 常量缓冲区视图实现**
实现 `D3D12ConstantBufferView` 类:
- ID3D12ConstantBufferView 封装
- 描述符创建与管理
---
## 2.4 实现顺序
```
阶段 2.1: 基础枚举与类型 (1天)
├── 2.1.1 Enums.h [已完成]
│ └── RHI枚举定义独立编号
├── 2.1.2 Types.h (通用类型定义)
└── 2.1.3 D3D12Enum.h [已完成]
└── 枚举转换层RHI→D3D12
阶段 2.2: 核心接口定义 (3天)
├── 2.2.1 RHISystem.h
├── 2.2.2 RHIDevice.h
├── 2.2.3 Resource.h (资源基类)
├── 2.2.4 ResourceView.h (视图基类)
├── 2.2.5 CommandQueue.h
├── 2.2.6 CommandList.h
└── 2.2.7 其他接口文件
阶段 2.3: D3D12 后端实现 (7天)
├── 2.3.1 D3D12Common.h
├── 2.3.2 D3D12Device
├── 2.3.3 D3D12Resource / D3D12Texture / D3D12Buffer
├── 2.3.4 D3D12CommandQueue
├── 2.3.5 D3D12CommandList
├── 2.3.6 D3D12CommandAllocator
├── 2.3.7 D3D12Fence
├── 2.3.8 D3D12DescriptorHeap
├── 2.3.9 D3D12RootSignature
├── 2.3.10 D3D12PipelineState
├── 2.3.11 D3D12Sampler
├── 2.3.12 D3D12QueryHeap
├── 2.3.13 D3D12SwapChain
├── 2.3.14 D3D12Shader
├── 2.3.15 D3D12RenderTargetView
├── 2.3.16 D3D12DepthStencilView
├── 2.3.17 D3D12ShaderResourceView
├── 2.3.18 D3D12UnorderedAccessView
└── 2.3.19 D3D12ConstantBufferView
阶段 2.4: 集成测试 (1天)
├── 窗口创建与交换链关联
├── 渲染循环基本框架
└── 简单的清屏测试
```
---
## 2.5 验收标准
1. **编译通过**:所有头文件和实现文件能够无错误编译
2. **接口完整**所有定义的接口都有D3D12实现
3. **功能验证**
- 能够创建窗口并初始化D3D12设备
- 能够创建命令队列和命令列表
- 能够执行基本的渲染命令(清屏)
- 能够处理窗口消息和呈现
4. **代码质量**
- 遵循编码规范
- 必要的注释和文档
- 错误处理完善
---
## 2.6 关键技术点
### 2.6.1 资源状态管理
D3D12要求严格的状态管理
- 资源必须处于正确的状态才能使用
- 状态转换通过 `TransitionBarrier`
- 常用状态:`D3D12_RESOURCE_STATE_GENERIC_READ`, `D3D12_RESOURCE_STATE_RENDER_TARGET`, `D3D12_RESOURCE_STATE_DEPTH_WRITE`
### 2.6.2 描述符管理
- 描述符堆类型CBV/SRV/UAV, Sampler, RTV, DSV
- GPU可见描述符堆用于渲染
- CPU可见描述符堆用于描述符拷贝
- 描述符递增大小计算
### 2.6.3 根签名设计
- 根参数类型:根常量、根描述符、根描述符表
- 描述符表:描述符数组
- 静态采样器:不可变的采样器配置
### 2.6.4 管线状态对象
- 图形管线:混合、深度、模板、光栅化、输入布局、顶点/像素/几何/ Hull/Domain着色器
- 计算管线根签名、CS着色器
### 2.6.5 视图接口设计
- 每种视图类型(RTV/DSV/SRV/UAV/CBV)都有独立接口
- 视图持有对底层资源的引用
- 视图描述符确定资源的解释方式
### 2.6.6 着色器编译
- 使用D3DCompiler API或dxc编译HLSL
- 支持着色器反射获取输入布局和资源绑定信息
- 支持着色器宏定义和include处理
### 2.6.7 跨平台抽象设计原则
- 所有接口使用抽象类型不暴露D3D12特定类型
- GPUDescriptorHandle/CPUDescriptorHandle 作为通用句柄类型
- 资源状态使用统一的ResourceStates枚举
- 创建描述符结构体独立于特定API
- RHI枚举使用独立编号通过转换层转换为特定API枚举
### 2.6.8 枚举转换层
RHI枚举使用独立编号与任何图形API无关通过转换层转换为特定API
```cpp
// RHI枚举独立编号
enum class FillMode { Wireframe, Solid };
// D3D12转换层
inline D3D12_FILL_MODE ToD3D12(FillMode mode) {
switch (mode) {
case FillMode::Wireframe: return D3D12_FILL_MODE_WIREFRAME;
case FillMode::Solid: return D3D12_FILL_MODE_SOLID;
}
}
```
---
## 2.7 后续阶段依赖
- 第三阶段渲染管线RenderPipeline需要RHI作为基础
- 材质系统需要RHI的Shader和PipelineState
- 场景渲染需要CommandList提交绘制命令