Files
XCEngine/docs/plan/NewEditor_宿主重构计划_2026-04-13.md

181 lines
5.7 KiB
Markdown
Raw Normal View History

2026-04-13 19:37:10 +08:00
# NewEditor 宿主重构计划
## 目标
`new_editor` 当前的窗口宿主从“功能可运行的过渡方案”收敛成可长期演进的 Editor 宿主架构,核心目标如下:
1. 主显示链最终统一到纯 D3D12。
2. 窗口线程只负责消息和状态,不承担 GPU 重活。
3. live resize 必须真实更新,但不能再走同步阻塞窗口线程的路径。
4. Editor shell 和 Scene/Game viewport 统一纳入宿主合成层。
5. 当前 `D3D11On12 + D2D` 只允许作为过渡路径,不能继续加深耦合。
## 当前问题
### 1. 宿主职责混在 `Application`
当前 `Application` 同时承担:
- Win32 消息调度
- 宿主运行时状态
- resize / dpi / deferred render 调度
- editor 状态更新
- present 前后的宿主控制
这会导致宿主问题难以单独定位和演进。
### 2. 主显示链过厚
当前主路径仍然依赖:
- D3D12 viewport 渲染
- swapchain backbuffer
- D3D11On12 wrapped resource
- D2D 绘制 shell
- present
这条链在 live resize、frame pacing、backbuffer 生命周期上都偏重。
### 3. resize 热路径仍然偏保守
虽然已经把 `WM_SIZE` 从直接同步 resize 调整为 deferred render 触发,但 resize 热路径里仍存在:
- backbuffer interop target 重建
- swapchain resize
- 资源生命周期收束
这还不是最终架构。
## 重构阶段
## 阶段 1宿主分层
### 目标
先把结构理顺,停止继续把宿主逻辑堆进 `Application`
### 任务
1. 拆出宿主运行时状态对象。
2. 拆出窗口消息调度与 deferred render 调度。
3.`Application` 只保留 editor 业务更新与高层协作职责。
4. 为后续 HostRenderer / HostCompositor 留清晰边界。
### 完成标准
1. resize / dpi / deferred render / interactive resize 状态不再散落在 `Application` 成员里。
2. `Application` 的宿主状态字段明显减少。
3. 现有功能与布局不回退。
## 阶段 2建立 HostRenderer / HostCompositor 边界
### 目标
把宿主渲染拆成明确两层:
1. `HostRenderer`
责任device / queue / swapchain / backbuffer / fence / present
2. `HostCompositor`
责任:把 shell draw data、viewport texture、icon/text 统一合成到 backbuffer
### 任务
1. 停止让 `NativeRenderer` 既像窗口绘制器又像过渡 compositor。
2. 把“主窗口显示”和“UI 绘制命令解释”职责显式拆开。
3. 为纯 D3D12 compositor 做接口准备。
### 完成标准
1. `HostRenderer` 不依赖 D2D 语义。
2. `HostCompositor` 成为唯一的宿主 UI 合成入口。
3. 现有 `NativeRenderer` 明确退化为过渡层或 fallback。
## 阶段 3主显示链切换到纯 D3D12
### 目标
去掉 `D3D11On12 + D2D` 在主显示链中的核心地位。
### 任务
1. shell 矩形、线条、图像、文字统一进入 D3D12 UI compositor。
2. Scene/Game viewport 作为普通 SRV 输入参与同一条 compositor pass。
3. backbuffer 只通过 D3D12 呈现。
### 完成标准
1. 主窗口显示不再依赖 D2D。
2. resize 时不再重建 D3D11On12 backbuffer interop target。
3. `new_editor` 主显示链可在没有 D3D11On12 的条件下工作。
## 阶段 4重写 resize 状态机
### 目标
做到真实 live resize但不阻塞窗口线程。
### 任务
1. `WM_SIZE` 只更新最新目标尺寸。
2. render tick 只消费最新尺寸,不处理过期尺寸。
3. resize 不允许在消息处理里做 GPU 等待。
4. resize / present / viewport surface 生命周期统一到宿主状态机。
### 完成标准
1. 拖动窗口边界时不黑屏。
2. 不出现黑白垃圾区。
3. 窗口拖动体感明显优于当前实现。
## 阶段 5去掉 resize 路径里的全队列等待
### 目标
去掉当前最重的同步点。
### 任务
1. 改成 per-backbuffer / per-frame 生命周期管理。
2. 只等待必须退休的资源代际。
3. 禁止 resize 路径里的整队列 idle 等待。
### 完成标准
1. resize 期间 CPU/GPU 同步明显减少。
2. live resize 手感继续改善。
## 阶段 6viewport 生命周期收口
### 目标
让 Scene/Game viewport 与外层宿主真正解耦。
### 任务
1. viewport render target 长期存活,不跟着宿主链大拆大建。
2. 宿主 compositor 只采样 viewport 结果,不干预其内部资源生命周期。
3. Scene/Game 在 interactive resize 期间保持稳定。
### 完成标准
1. viewport 不再因宿主 resize 逻辑出现黑屏或闪烁。
2. 宿主和 viewport 各自职责明确。
## 执行顺序
1. 先完成阶段 1。
2. 然后搭好阶段 2 的 HostRenderer / HostCompositor 边界。
3. 再推进阶段 3切主显示链到纯 D3D12。
4. 最后做阶段 4、5、6 的性能与生命周期收口。
## 当前落点
当前阶段 1 已完成,阶段 2 已开始收口:
1. 已新增 `HostRuntimeState`,把宿主 DPI / interactive resize / pending resize / deferred render 状态从 `Application` 中抽离。
2. 已新增 `WindowMessageDispatcher`,把 `WndProc` 中的宿主消息调度与 deferred render 调度拆到 `Host` 层。
3. 已把 `D3D12WindowRenderLoop` 从悬空 helper 升级为主窗口帧编排入口,开始统一 `BeginFrame / viewport render / UI present / fallback / resize interop` 这条链。
4. 已把 viewport render target 资源工厂从 `ProductViewportRenderTargets.h` 收成独立 manager`ProductViewportHostService` 只保留请求/返回 frame 的业务外壳。
5. 已把 shader resource descriptor 分配职责从 `D3D12WindowRenderer` 抽到独立的 `D3D12ShaderResourceDescriptorAllocator`,减少窗口呈现器的非 swapchain 职责。
6. 下一步进入阶段 2 主体:继续拆 `NativeRenderer` 中的窗口互操作 / present 组合路径,把 D2D UI 光栅化与 D3D11On12 窗口合成进一步分离。