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 手感继续改善。
|
|
|
|
|
|
|
|
|
|
|
|
## 阶段 6:viewport 生命周期收口
|
|
|
|
|
|
|
|
|
|
|
|
### 目标
|
|
|
|
|
|
|
|
|
|
|
|
让 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` 这条链。
|
2026-04-13 19:57:25 +08:00
|
|
|
|
4. 已把 viewport render target 资源工厂从 `ProductViewportRenderTargets.h` 收成独立 manager,`ProductViewportHostService` 只保留请求/返回 frame 的业务外壳。
|
|
|
|
|
|
5. 已把 shader resource descriptor 分配职责从 `D3D12WindowRenderer` 抽到独立的 `D3D12ShaderResourceDescriptorAllocator`,减少窗口呈现器的非 swapchain 职责。
|
|
|
|
|
|
6. 下一步进入阶段 2 主体:继续拆 `NativeRenderer` 中的窗口互操作 / present 组合路径,把 D2D UI 光栅化与 D3D11On12 窗口合成进一步分离。
|