7.5 KiB
7.5 KiB
NewEditor System Audit
Date: 2026-04-22
1. Scope
本次审计目标不是继续“猜一个点然后修一个点”,而是重新检查 new_editor
当前还残留哪些:
- 旧代码或旧语义残留
- 冗余控制路径
- 临时性/补丁式结构
- 边界没有收口干净的模块职责
审计重点覆盖:
app/Platform/Win32app/Rendering/D3D12app/Rendering/Viewportapp/CompositionWindowManager
2. Confirmed Closed Items
这轮审计先确认了已经真正收掉的历史链路,避免把已经解决的问题重复列为风险:
new_editor中已无活跃的D2D / Direct2D / D3D11On12 / NativeRenderer / WindowInterop主窗口链路。D3D12UiRenderer已不再保留活跃的legacy/indexed双路径 UI geometry 提交。- 启动截图策略已经不再由旧的渲染层壳子控制,
Rendering/Native活 include 路径已清空。
这说明上一轮 D3D12 / 截图职责收口本身是有效的。
3. Primary Findings
3.1 High: frame execution still has multiple live owners
RenderFrame() 现在不是单点驱动,而是同时被多条路径直接调用:
- EditorWindow.cpp:612
- EditorWindow.cpp:654
- EditorWindowChromeController.cpp:431
- EditorWindowChromeController.cpp:912
- EditorWindowHostRuntime.cpp:237
- EditorWindowMessageDispatcher.cpp:62
- EditorWindowMessageDispatcher.cpp:402
- EditorWindowMessageDispatcher.cpp:411
- EditorWindowMessageDispatcher.cpp:419
- EditorWindowMessageDispatcher.cpp:439
根本问题不是“调用次数多”,而是“帧驱动权不唯一”:
- 主循环在主动渲染。
WM_PAINT在同步渲染。WM_SIZE / WM_DPICHANGED / WM_EXITSIZEMOVE在消息里同步渲染。EditorWindowChromeController在窗口过渡操作里直接同步渲染。
这会导致:
- 帧生成/Present 时机不再只有一个真实来源。
EditorWindowFrameTransferRequests的处理顺序在不同入口下不一致。- resize / maximize / drag-restore 时,Chrome 层直接拥有渲染副作用。
- 输入、布局、Present、窗口消息之间很难建立稳定时序。
这不是局部实现细节,而是当前 new_editor 最明显的未收口架构问题。
3.2 High: window destruction lifecycle still has multiple owners
窗口销毁收尾现在仍然散落在多处:
- EditorWindowHostRuntime.cpp:172
- EditorWindowHostRuntime.cpp:194
- EditorWindowHostRuntime.cpp:262
- EditorWindowMessageDispatcher.cpp:428
- EditorWindowMessageDispatcher.cpp:452
- EditorWindowWorkspaceCoordinator.cpp:221
- EditorWindowWorkspaceCoordinator.cpp:267
当前重复动作包括:
window.Shutdown()DestroyWindow(hwnd)window.MarkDestroyed()- 从
m_windows中 erase
根本问题是:native window death、runtime shutdown、workspace removal、host container erase 没有一个唯一所有者。
这会导致:
- 生命周期语义只能靠“现在碰巧没炸”维持,而不是靠明确边界维持。
- 工具窗口、弹出窗口、独立面板窗口的关闭行为仍然容易反复回归。
WorkspaceCoordinator直接复制 host runtime 的 destroy 逻辑,说明边界没有收口。
这条问题和之前的“关子窗口把主窗口带走”属于同一类根因:生命周期控制权分裂。
3.3 Medium: EditorShellRuntime is still a monolithic per-frame god-object
EditorShellRuntime.cpp:549
开始的 EditorShellRuntime::Update(...) 仍然在一个单元里同时承担:
- shell definition 构建
- workspace/session 同步
- dock host interaction 更新
- viewport request / frame 应用
- hosted panel input 分发
- hierarchy / project / color picker / inspector / console 更新
- status / command focus / trace 同步
同一个 update 内还存在多次会话同步与定义重建:
- EditorShellRuntime.cpp:580
- EditorShellRuntime.cpp:582
- EditorShellRuntime.cpp:605
- EditorShellRuntime.cpp:607
- EditorShellRuntime.cpp:629
- EditorShellRuntime.cpp:672
这不是“旧链路残留”,但它是当前最明显的未拆分核心耦合点。它会导致:
- 任意一个 panel / dock / viewport 变更都容易影响整帧更新流程。
- 输入问题、状态问题、布局问题、面板问题很难局部定位。
- 后续继续做性能/交互优化时,改动面会被这个 god-object 放大。
4. Non-Findings
以下命中已确认不是这轮要处理的“旧代码/临时方案”问题:
- 普通
fallback参数或默认值。 DirectWrite在D3D12UiTextSystem中的文本栅格化使用。- 视口 pass 中的
fallbackState,它表示材质渲染状态默认值,不是旧主窗口链路。
5. Audit Conclusion
截至本次审计,new_editor 不是“还有一堆 D2D 遗留没删干净”,那条主线已经基本收掉了。
当前剩余最关键的两个系统级问题是:
- 帧驱动权没有单点收口。
- 窗口销毁权没有单点收口。
如果后续继续做系统级收口,优先级应该是:
- 先把 frame scheduling / present / transfer request 统一到一个唯一驱动源。
- 再把 window close / destroy / shutdown / erase 统一到一个唯一生命周期所有者。
- 最后再拆
EditorShellRuntime这个 per-frame god-object。