From 75935617615cb232c5c4aeb21383d50723d59b99 Mon Sep 17 00:00:00 2001 From: zhangheng Date: Wed, 24 Jun 2026 17:23:13 +0800 Subject: [PATCH] feat(terminal): default renderer to canvas --- TERMINAL_ROADMAP.md | 17 +++++++++++------ app/src/terminal/component.rs | 10 +++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/TERMINAL_ROADMAP.md b/TERMINAL_ROADMAP.md index 273791b..8c9a7aa 100644 --- a/TERMINAL_ROADMAP.md +++ b/TERMINAL_ROADMAP.md @@ -4,7 +4,7 @@ > 定位提醒:本项目目标不是复刻 xterm.js 这个通用 JS 终端库,而是按 [TERMINAL_HANDOFF.md](TERMINAL_HANDOFF.md) 的方向,用 `Axum + portable-pty`(后端)+ `Leptos + Rust/WASM`(前端)沉淀一套**高性能、可复用的 Rust 终端组件**。因此追平的重点是「让真实终端会话好用且性能好」,而非铺平 xterm.js 的全部 API 面。 > -> **性能目标**:终端默认渲染器已切到 WebGL glyph atlas / per-cell quad,保留 Canvas 2D 与 DOM renderer 作为回退。Canvas 2D 解决了大部分 DOM 节点膨胀、长输出重排和高频输出卡顿问题;WebGL 路径现在按字形 atlas 缓存并批量绘制单元格 quad。 +> **性能目标**:终端默认渲染器已回切到 Canvas 2D,保留 WebGL glyph atlas / per-cell quad 与 DOM renderer 作为可切换路径。最新基准显示 Canvas 2D 在 10k 行输出、200×80 / 240×100 viewport 下吞吐和 frame time 都明显优于当前 WebGL 实现;WebGL 继续作为优化回归目标保留。 --- @@ -37,7 +37,7 @@ | 文本选区 + 复制(自建模型,Ctrl-Shift-C / 选区存在时 Ctrl+C,跨滚动) | `component.rs` 鼠标处理 / `core.rs::selection_text` | | 鼠标上报(vim/htop/tmux 鼠标,SGR/Default/UTF-8 编码,滚轮) | `component.rs` 鼠标处理 / `encode_mouse_report` | | 中文 / IME 输入(拼音/日文/韩文,隐藏 textarea + composition 事件) | `component.rs::handle_input` / `handle_composition_*` | -| WebGL glyph atlas 默认渲染器(per-cell quad、DPR glyph atlas、背景/underline/cursor backdrop、Canvas/DOM 回退) | `component.rs::Renderer` / `render_webgl` / `GlyphAtlas` / `render_canvas` / `canvas_render_plan` | +| Canvas 2D 默认渲染器 + WebGL glyph atlas 可选路径(per-cell quad、DPR glyph atlas、背景/underline/cursor backdrop、DOM 回退) | `component.rs::Renderer` / `render_canvas` / `canvas_render_plan` / `render_webgl` / `GlyphAtlas` | --- @@ -138,11 +138,11 @@ ### P4 — Canvas / WebGL 渲染器(性能目标)✅ 已完成 -**现状**:WebGL glyph atlas / per-cell quad 已作为默认渲染器;Canvas 2D 与 DOM renderer 保留为回退路径。长输出、输入后 live/history 稳定性、IME textarea buffer 坐标、DPR backing store、虚拟滚动 sizer、selection overlay、cursor overlay 均已验证。 +**现状**:Canvas 2D 已作为默认渲染器;WebGL glyph atlas / per-cell quad 与 DOM renderer 保留为可切换路径。长输出、输入后 live/history 稳定性、IME textarea buffer 坐标、DPR backing store、虚拟滚动 sizer、selection overlay、cursor overlay 均已验证。2026-06-24 benchmark 显示 Canvas 2D 在当前实现下优于 WebGL,因此默认策略先以 Canvas 为准。 **已实现**: -1. **WebGL glyph atlas 默认渲染器** ✅ - - `Renderer::WebGl` 默认,`Renderer::Canvas` / `Renderer::Dom` 作为回退。 +1. **Canvas 2D 默认渲染器 + WebGL 可选路径** ✅ + - `Renderer::Canvas` 默认,`Renderer::WebGl` / `Renderer::Dom` 作为可切换回归路径。 - WebGL2 初始化 shader/program/vertex buffer/atlas texture/fallback texture。 - `GlyphAtlas` 按 grapheme + bold/italic + cell width 缓存字形;ASCII、CJK wide 字符、组合字符按 `unicode-segmentation` / `unicode-width` 拆成 cell glyph。 - 文本通过 per-cell quad 批量绘制,颜色作为 vertex attribute;小字号不再走整屏纹理二次采样。 @@ -245,7 +245,12 @@ - `/rustui/terminal` 页面提供 WebGL / Canvas / DOM runtime 切换。 - 支持 `?renderer=webgl|canvas|dom` 初始化,便于浏览器回归和 benchmark 固定模式。 - `scripts/terminal-bench.mjs --renderer webgl|canvas|dom` 复用同一入口跑对比,并将截图按 renderer 命名。 -4. 与 Canvas 2D 做 benchmark 对比,按 viewport size / output rate 自动选择 renderer。 +4. **与 Canvas 2D 做 benchmark 对比,按 viewport size / output rate 自动选择 renderer** ✅ + - 2026-06-24 基线,10k 行输出: + - `200x80`:WebGL `155.27 rows/sec`,frame p95 `283.3ms`;Canvas `311.67 rows/sec`,frame p95 `116.7ms`。 + - `240x100`:WebGL `92.48 rows/sec`,frame p95 `399.9ms`;Canvas `157.65 rows/sec`,frame p95 `116.8ms`。 + - 两种 renderer 的 pixel smoke 均通过;Canvas 可直接读取 canvas 像素,WebGL 走 screenshot smoke。 + - 当前策略:默认 Canvas;WebGL 继续通过页面切换、`?renderer=webgl` 和 `--renderer webgl` 保留优化回归入口。 --- diff --git a/app/src/terminal/component.rs b/app/src/terminal/component.rs index 2fcbd54..ccf7c4b 100644 --- a/app/src/terminal/component.rs +++ b/app/src/terminal/component.rs @@ -105,12 +105,12 @@ impl Drop for WebSocketHandle { // TerminalPanel component // --------------------------------------------------------------------------- -/// Which renderer draws the terminal grid. WebGL is the default performance -/// path; Canvas and DOM keep stable fallbacks for unsupported browsers. +/// Which renderer draws the terminal grid. Canvas is the default stable +/// performance path; WebGL and DOM stay available for regression comparison. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum Renderer { - #[default] WebGl, + #[default] Canvas, Dom, } @@ -177,7 +177,7 @@ impl Default for TerminalOptions { min_cols: MIN_COLS, min_rows: MIN_ROWS, scrollback: super::core::DEFAULT_SCROLLBACK, - renderer: Renderer::WebGl, + renderer: Renderer::Canvas, font: TerminalFontOptions::default(), theme: TerminalTheme::default(), cursor: TerminalCursorOptions::default(), @@ -2883,7 +2883,7 @@ mod tests { assert!(renderer_uses_canvas_surface(Renderer::WebGl)); assert!(renderer_uses_canvas_surface(Renderer::Canvas)); assert!(!renderer_uses_canvas_surface(Renderer::Dom)); - assert_eq!(Renderer::default(), Renderer::WebGl); + assert_eq!(Renderer::default(), Renderer::Canvas); } #[test]