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

5.7 KiB
Raw Blame History

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 收成独立 managerProductViewportHostService 只保留请求/返回 frame 的业务外壳。
  5. 已把 shader resource descriptor 分配职责从 D3D12WindowRenderer 抽到独立的 D3D12ShaderResourceDescriptorAllocator,减少窗口呈现器的非 swapchain 职责。
  6. 下一步进入阶段 2 主体:继续拆 NativeRenderer 中的窗口互操作 / present 组合路径,把 D2D UI 光栅化与 D3D11On12 窗口合成进一步分离。