20 - AutoUI 分离架构设计文档
来源:前期在 DeepSeek 上的架构讨论成果,2026-07 整理入库。 关联:docs/design/08-ui-systems.md(AURA IR)、docs/plans/archive/364-a2r-cosmic-replication-readiness.md。 修订(2026-08-26,Design 23 / Plan 452):窗口管理归属(§6.1)与桌面 形态(§9.2)已由 docs/design/autoui/virtual-desktop.md 修订——窗口语义 (chrome/任务栏/焦点策略)归特权桌面 App、Win/Mac 改单 OS 窗口虚拟桌面、 RenderCommand 重定位为 AppWindow 接缝的渲染叶子后端。本文其余部分 (RenderCommand/RenderQueue/资源集中/弹性)仍然有效,作为 386 复活时的 协议设计底稿。
1. 项目背景与目标
AutoUI 是一个跨平台 UI 解决方案,包含声明式语言前端、独立中间表示层和可替换的渲染后端。其长期目标是驱动 AutoOS 操作系统桌面环境,实现百应用级别轻量运行和全局共享渲染资源。
当前基于 iced 的单体应用架构,每个应用需独立持有 wgpu 上下文、字体图集、管线缓存等资源,内存基线高达 100 MB,无法支撑数十个应用同时运行。分离架构的核心思想是:
- 应用不拥有 GPU 资源:每个应用进程极轻量(目标 1–5 MB),只包含逻辑和 UI 描述。
- 宿主集中渲染:系统级 Compositor 进程持有唯一 GPU 上下文,执行所有应用的绘制命令,复用全局字体、纹理、着色器等。
- 共享渲染:通过无锁共享内存传递轻量绘制指令,消除重复资源,将系统总内存控制在 1 GB 以内(100 个应用)。
2. 架构概览
系统由三大核心部分构成:AutoTree、RenderCommand 和 RenderQueue,以及运行它们的 宿主 Compositor 与 应用壳。
[应用进程] [宿主 Compositor 进程]
Auto 语言前端 ┌─────────────────┐
↓ │ 窗口/输入管理 │
AutoTree (VNode 树) │ 全局 wgpu/Vulkan │
↓ │ 字体图集/纹理池 │
RenderCommand 生成 ──── RenderQueue ──▶ 合成器/渲染器 │
(共享内存无锁队列) └─────────────────┘- 应用进程:解析
.auto源码,维护 AutoTree,按帧生成 RenderCommand 增量/全量数据,推送到 RenderQueue。 - 宿主进程:管理窗口树、Z-order、输入事件;从每个窗口的 RenderQueue 中按序取出命令,执行 GPU 绘制并合成最终桌面。
- RenderQueue:基于共享内存的单生产者单消费者无锁环形队列,实现极低延迟(纳秒级)的应用-宿主通信。
3. AutoTree 设计
AutoTree 是 AutoUI 在 Rust 环境中的唯一中间表达,取代原有的 AbstractComponents。它是声明式 Widget 虚拟树,并非绘制基元列表。
3.1 VNode 结构
每个节点代表一个 UI 组件(Button、Row、Text 等),存储其语义属性与来源信息。
pub struct VNode {
pub id: NodeId, // 稳定全局唯一标识
pub kind: VNodeKind, // 组件类型
pub props: HashMap<String, Value>, // 组件属性(文本、颜色、样式等)
pub layout: Option<Layout>, // 布局计算结果(Rect 等)
pub children: Vec<VNode>, // 子节点
pub source: SourceSpanSet, // 源码位置映射
}
pub enum VNodeKind {
Button,
Text,
Input,
Row,
Column,
Custom(String), // 用户自定义组件
// ...
}稳定标识(NodeId) 由编译器分配,基于源码声明位置和循环键值生成,确保跨帧持久。辅助的 VPath(如 App/navbar/col[1]/button[0])提供人类可读路径,用于 Inspector 面包屑。
3.2 动态结构处理
- 条件分支:记录条件表达式源码位置(
condition_span),VTree 仅包含当前激活的分支子树。 - 循环生成:每个实例节点携带
(模板NodeId, 迭代键)复合标识,数据变化时通过键值稳定定位。
3.3 AutoTree 与源码的映射(SourceMap)
SourceMap 建立 VNode → 源码多位置 的精确关联:
pub struct SourceSpanSet {
/// 在 view 块中的 widget 声明位置
pub view_span: Option<SourceSpan>,
/// 绑定的 model 变量声明与引用位置
pub model_refs: Vec<ModelRef>,
/// 事件绑定与处理位置
pub event_refs: Vec<EventRef>,
}由 Auto 编译器在生成 AutoTree 时填充,运行时只读。这为 Inspect 面板、源码跳转、反向修改提供了基础。
3.4 Diff 与 Patch
当 model 变化时,新的 AutoTree 与上一帧的旧树进行差异比较,产出 Patch 集合。Patch 是描述树变更的最小单元:
pub enum Patch {
UpdateProps { node_id: NodeId, props: HashMap<String, Value> },
AppendChild { parent_id: NodeId, child: VNode },
RemoveNode { node_id: NodeId },
Reorder { parent_id: NodeId, new_order: Vec<NodeId> },
// ...
}这些 Patch 再转换为 RenderCommand 序列发送给宿主。对于静态区域,宿主可缓存上一帧的绘制结果,仅重绘脏区。
4. RenderCommand 设计
RenderCommand 是宿主渲染器执行的平台无关的轻量绘制指令,由 AutoTree 增量转换而来。
4.1 命令分类
pub enum RenderCommand {
// 图形基元
DrawRect { rect: Rect, color: Color, radius: f32 },
DrawText { font_id: FontId, glyphs: Vec<GlyphInfo>, color: Color },
DrawImage { image_id: ImageId, src: Rect, dst: Rect },
// 状态管理
SetClip { rect: Rect },
PushLayer { opacity: f32, transform: Matrix },
PopLayer,
// 增量更新指令
UpdateTexture { node_id: NodeId, data: Vec<u8> },
InvalidateRect { rect: Rect },
CacheControl { node_id: NodeId, cache: bool },
// 自定义(保留扩展)
Custom { shader: ShaderId, params: Vec<u8> },
}命令设计为窗口内相对坐标,应用不感知屏幕绝对位置或 Z-order,由宿主在合成时统一处理窗口变换。
4.2 全量与增量帧
每个 RenderQueue 条目包含帧类型标记:
- Full:后跟完整 RenderCommand 列表,用于首帧、窗口大小改变或缓存失效。
- Incremental:仅含基于上一帧变化的命令,宿主根据自身缓存重绘指定区域。
应用在帧头写入 DirtyRect 列表,告知宿主窗口内哪些矩形区需重新合成,其余区域可复用上一帧纹理。
5. RenderQueue 设计
RenderQueue 是应用与宿主间的高性能通信通道,基于共享内存 + 无锁单生产者单消费者环形队列。
5.1 队列结构
每个应用分配两个队列(命令上行、事件下行),每个队列包含:
- 共享内存控制块:包含读写指针(原子变量)、缓冲区大小、帧同步信号(如
eventfd)。 - 数据环形缓冲:存储序列化的 RenderCommand 流或事件数据。
5.2 通信流程
- 应用端:
- 构造增量/全量 RenderCommand 列表。
- 写入共享缓冲区(零拷贝时直接构造在缓冲区内)。
- 原子更新写指针。
- 可选触发
eventfd通知宿主(或宿主定期轮询)。
- 宿主端:
- 在合成循环中遍历所有窗口(按 Z-order)。
- 对每个窗口,原子读取读指针到写指针之间的数据块。
- 解析命令并立即提交 GPU 执行。
- 处理后更新读指针,回写事件(如输入)到应用的事件队列。
5.3 性能特点
- 单次通信延迟 <5 μs(含内存写入和原子操作),对 16 ms 帧预算可忽略。
- 零锁竞争,无内核调用(除可选事件通知)。
- 应用只发送窗口局部命令,典型每帧 10–100 KB,共享内存带宽足够支持 100+ 应用。
6. 宿主 Compositor 设计
宿主是系统的唯一渲染服务进程,负责窗口管理、输入分发、GPU 资源管理和合成。
6.1 窗口管理
修订注记(Design 23 R1/R2):窗口树/Z 序/输入路由/合成仍归宿主,但 窗口语义(装饰、任务栏、焦点策略)归特权桌面 App(AutoUI 编写); "窗口"在 Win/Mac 上为单 OS 窗口内的虚拟窗口,不再假设每窗口一个 OS surface。
维护全局窗口树,存储每个窗口的:
- Z-order、位置、大小、可见性。
- 对应的 RenderQueue 引用。
- 离屏纹理缓存(用于增量合成和透明窗口)。
宿主按照 Z-order 从低到高依次执行每个窗口的 RenderQueue,绘制到其离屏纹理或直接到帧缓冲。支持透明混合和跨窗口效果(阴影、模糊等)。
6.2 全局资源管理
- 字体图集:宿主加载系统字体,光栅化常用字形到一张大纹理(如 2048×2048),所有应用共享
FontId。 - 图标/控件样式纹理:全局主题纹理,应用仅引用 ID。
- 着色器/管线缓存:宿主预编译常用管线,应用通过
ShaderId引用。
应用不持有任何 GPU 资源,仅发送命令。
6.3 渲染后端抽象
初期使用 wgpu 实现快速原型,后期通过 trait 替换为自研 Vulkan 渲染器,实现极致轻量(宿主 <30 MB)。抽象接口定义:
pub trait GpuBackend {
fn execute_commands(&mut self, commands: &[RenderCommand], target: &mut RenderTarget);
fn create_font_atlas(&mut self, font_data: &[u8]) -> FontId;
fn update_texture(&mut self, id: TextureId, data: &[u8]);
// ...
}6.4 输入与事件
宿主从窗口系统(winit/SDL3)捕获输入,根据焦点窗口路由事件至对应应用的事件队列。应用在空闲时读取事件并更新 AutoTree。
7. 应用端流程
每个应用编译为独立的原生二进制,链接 autoui-client 库。该库屏蔽渲染后端,应用仅操作 AutoTree。
7.1 应用生命周期
- 初始化:解析
.auto文件,构建初始 AutoTree,分配共享内存队列,连接宿主。 - 事件循环:接收宿主发送的事件(鼠标、键盘、自定义),调用
update函数修改 model,触发 AutoTree 增量构建。 - 生成 RenderCommand:将 AutoTree Diff 转换为全量或增量 RenderCommand,推入 RenderQueue。
- 帧同步:等待宿主完成信号(可异步),进入下一帧。
7.2 内存基线
- AutoTree 状态:几百 KB。
- 通信缓冲:共享内存约 256 KB。
- Rust 运行时 + 应用逻辑:~1–2 MB。
- 不链接任何图形库。
总内存占用:2–5 MB,未来通过 no_std 等优化可进一步降低。
8. 开发工具与调试
8.1 内嵌 DevTools
在单应用开发阶段,提供类似浏览器 F12 的面板,内嵌于应用中(基于 iced 实现,功能稳定后抽取为独立服务)。
核心功能:
- 元素选择与高亮:鼠标悬停显示 VNode 边界、ID、VPath。
- Inspector 面板:展示选中节点的属性(类型、样式、布局、数据绑定、事件)。通过 SourceMap 可查看和跳转源码位置。
- 实时编辑:修改简单属性(文本、颜色)立即反映到界面,并可反向写入源码(通过 SourceMap 定位替换)。
- 事件追踪:记录消息流和状态变化。
8.2 外部 AutoDesign 工具
当切换到共享宿主后,抽取 Inspector 逻辑为独立应用,通过宿主授权的调试通道获取任意应用的 AutoTree 快照和 SourceMap,实现全局调试与 AI 辅助设计。
9. 未来演进
9.1 渲染后端优化
- 宿主从 wgpu 迁移到自研 SDL3 + Vulkan 后端,内存基线降至 <30 MB。
- 实现跨平台 Vulkan 渲染器(Linux 原生,Windows 原生,macOS 通过 MoltenVK 兼容)。
- 提供 CPU 2D 后端(基于 tiny-skia)作为降级方案,单应用内存 <10 MB。
9.2 AutoOS 集成
修订注记(Design 23 R2/R7):桌面形态演进调整为——Win/Mac 虚拟桌面 先行(Plan 454/455),Linux 原生合成器为 Smithay 宿主(Plan 457), RenderCommand 作为 AppWindow 接缝后端由 Plan 386 复活承接。本节 "Compositor 直连 Wayland"的描述由 457 落地时细化。
- Compositor 直接基于 Wayland 协议和自研渲染器,替代 X11/Wayland 桌面环境。
- 应用通过
autoui-client作为系统标准开发方式。 - 系统级字体、主题、资源服务全部集中管理,应用零冗余。
- AutoDesign 成为系统原生设计/开发工具,支持 AI 局部修改 UI。
10. 总结
本架构通过 AutoTree 中间表示、RenderCommand 轻量指令、RenderQueue 无锁通信 和 共享宿主 Compositor,实现了 UI 逻辑与渲染的彻底分离。它兼具声明式开发的便利性与命令式渲染的性能优势,能够以极低的内存代价同时运行上百个应用,为 AutoOS 桌面环境提供了坚实的技术基座。
11. 仓库边界时序裁定(2026-09-13 留底)
本节与上文正交:§1–§10 讲 AutoUI 内部的应用/宿主进程分离,本节讲 AutoUI 代码与 auto-lang 仓的仓界问题。源自 2026-09-13 拆仓可行性 分析(背景:AutoOS 已于 2026-09-07/08 迁独立仓,AutoUI 是否跟进)。 关联登记:auto-os 侧 PLAN-578「examples/ui 与画廊归属两读」待裁定事项, 留到本议题重开时一并裁定。
11.1 裁定
AutoUI 拆独立仓一事推迟,不设日程;重开前置条件 = VM/Rust 桌面版 (VM/iced 轨道)稳定。 近期不动 UI↔语言核心的解耦工程。理由:当下 双端正处于高速共变期,此时解耦等于逆着开发流做手术;等共变频率自然 回落后再动,成本低一个量级。
11.2 依据(当次实测)
- 足迹:
crates/auto-lang/src/{ui,ui_gen,aura,a2ui}合计约 21.6 万行 (巨石 crate 内)+packages/5 个 npm 包 +examples/ui37 例 +stdlib/auto7 个 UI 域文件(运行时文件系统加载,不嵌入二进制,可整体搬走)。 - 三处硬耦合(拆库前必须解开):
- UI 语法在语言核心——
ast/ui.rs(1091 行)、parser.rs58 处 WidgetDecl; ui_gen/aura/a2ui无条件编译,被 lib.rs 公共 API(ui_build系列) 与 CLI(cmd_ui/cmd_vue)无门控调用;- VM
native_catalog.rs永久登记 UI native ID 段(auto.term/clipboard/ code_editor等),ui/dynamic.rs直接持有AutoVM实例。 (反向依赖本身健康:infer/、trans/对 UI 零引用;核心→UI 大多已被 feature gate + 降级桩驯服,无 UI 构建在 HEAD 是绿的。)
- UI 语法在语言核心——
- 共变频率(决定性):近 90 天改 UI 侧提交 1407、VM 侧 509、 同提交跨两侧 245(≈2.7 次/天)——拆仓后每次都是跨仓协调。
- 历史:2026-03 前
../auto-ui独立仓即因「单向深依赖 + path 依赖 churn + 转译器必须长进 ui_gen」并入本仓(Plan 045/096/175 有案底), 且今天耦合比当时更深而非更浅;AutoOS 迁移时桌面宿主运行时 19.3 万行 被定性为框架能力、刻意留架(auto-os Design 01 §2)。
11.3 submodule 形态裁定:不采用
- 依赖方向 auto-ui→auto-lang 与 submodule「消费者嵌入被依赖方」模型相悖: auto-ui 嵌 auto-lang = path churn 加强版(每次语言演进都要显式 bump 子模块 指针再修 breakage,2026-03 死法重现);auto-lang 嵌 auto-ui = 子模块内 crate 只能在挂载点里构建、独立检出即断链,独立仓的意义自我取消。
- submodule 只解决「相对路径检出」,不解决 cargo 依赖关系;而相对路径 检出已有更轻的成文解析序(
env → 兄弟检出 → 主检出,auto-os 全链验证)。 - 与本仓 worktree 工作流冲突(子模块
.git指向主仓.git/modules的 相对指针在 worktree 下易断,wt-guard/JUNCTION 红线环境零容忍)。 仓系唯一 submodule 先例是 auto-osapps/kanban(叶子 App,产品级), 不构成框架依赖先例。 - 若未来拆仓:按 auto-shell 模式(Plan 330 先例:git-filter-repo 保 历史 + 跨仓 path 依赖 + 解析序),不用 submodule。
11.4 重开时的路线(推迟但保留)
- Phase 0:修门禁回归(见 §11.5 第二条)。
- Phase 1(核心工程):仓内 crate 化——
ui/ui_gen/aura/a2ui拆为 workspace 成员crates/auto-ui,分层auto-lang(语言核心)→ auto-ui (框架)→ auto-man/CLI(编排);lib.rs 编排函数(ui_build 系列/ build_dynamic_component/run_file_dynamic_ui)上移;VM native 改注册制 (ID 常量留核心、实现由 auto-ui 启动注册);UI 语法留语言核心、经公共 API 消费。保留单仓原子提交。 - Phase 2(可并行,低风险):边缘资产迁出——
packages/(npm)、crates/autoui-skill/(纯数据)、docs/design/autoui/;examples/画廊 归属随 PLAN-578 两读裁定。 - Phase 3(条件触发,非日程驱动):repo 拆分。触发条件:auto-ui crate 化后核心 API 消费面收敛稳定 + 连续数月跨侧共变频率显著下降 (较 2.7 次/天降一个数量级)+ 出现第二消费者(第三方/另一语言前端)。
11.5 立即有效的护栏(不随推迟而豁免)
- 新增 UI native/FFI 必须挂 feature cfg + 降级桩(沿用
vm/native.rs既有桩模式);无 UI 构建(--no-default-features/cargo tv/ CI vm-files 档)保持绿色——这是未来任何拆分唯一能站住的地基, 欠账后要花大价钱重新考古。 - 当飞 Plan 619 工作树中
vm/ffi/term_engine.rs133/199-230/331 行的 未门控crate::ui::terminal引用(HEAD 版本无此引用)须在合入前 补门控,否则弄红全部无 UI 构建(登记:KNOWN-DEBT-AND-RISKS.md 「架构裁定留底」节 ARCH-AUTOUI-GUARD)。