Rendering Modes zh CN - D0n9X1n/SonicTerm GitHub Wiki
渲染模式
SonicTerm 总会先创建 wgpu 适配器和设备,再决定使用正常 GPU 策略还是软件渲染降级。 Windows 上,降级还会把最终绘制切换为 CPU BGRA 帧,并通过 GDI 呈现。macOS 与 Linux 上的降级仍使用 wgpu 呈现,但采用更低开销的帧节奏和表面策略。
文字塑形、光栅化和图集所有权见渲染与字体。配置键见 配置,主机端保留内存见内存。
适配器分类与选择
首个渲染器请求兼容表面的高性能适配器,force_fallback_adapter = false;wgpu 仍可能
返回 CPU 适配器。进程内所有后续窗口(新建窗口、预热池窗口和 tear-out 窗口)都通过
GpuSharedContext 复用其适配器/设备/队列,因此进程只持有一个设备。主窗口关闭而另一个
窗口仍打开时,主窗口只会隐藏并保留其渲染器,所以该设备保持存活。各窗口各自拥有表面和
绘制状态。任何呈现器都不能绕过 wgpu 启动失败。
软件分类是只依赖 wgpu::AdapterInfo 的纯函数。device_type == Cpu 时返回 true;
否则把适配器名称转成小写,并检查是否包含:
microsoft basic render driver
llvmpipe
swiftshader
software adapter
分类同时决定 wgpu 分配策略和渲染策略。软件适配器请求
MemoryHints::MemoryUsage,硬件适配器请求 MemoryHints::Performance。
[appearance].software_render_mode 决定是否降级:
| 取值 | 结果 |
|---|---|
auto |
跟随适配器分类 |
force |
在任何适配器上启用降级 |
off |
在任何适配器上关闭降级 |
该设置可实时重载。每次都从显示器自身帧周期重新计算,因此从降级切换到 off 会恢复
显示器节奏,不会保留旧上限。Windows 上,force 还会把所有透明背景材质覆盖为
opaque,因为 GDI 呈现器无法合成 Mica、Acrylic 或 Tabbed 透明效果。平台启动时,
auto 不会改变配置的 backdrop。
flowchart TD
adapter["wgpu 适配器"] --> cpu{"设备类型是 Cpu?"}
cpu -- 是 --> detected["检测为软件"]
cpu -- 否 --> name{"名称匹配已知软件光栅器?"}
name -- 是 --> detected
name -- 否 --> hardware["检测为硬件"]
detected --> setting{"software_render_mode"}
hardware --> setting
setting -- auto --> follow["跟随检测"]
setting -- force --> degrade["启用降级"]
setting -- off --> normal["关闭降级"]
follow --> platform{"最终标志"}
degrade --> platform
normal --> platform
platform -- "Windows + 启用" --> gdi["CPU BGRA + GDI 呈现"]
platform -- "macOS/Linux + 启用" --> wgpuSlow["wgpu + 降级策略"]
platform -- 关闭 --> wgpuFast["正常 wgpu 策略"]
正常 GPU 策略
硬件路径跟随显示器周期。无法取得刷新率或刷新率为零时,保留 60 Hz 默认值。表面呈现
优先选择后端支持的 Mailbox,否则使用 Fifo。不透明 backdrop 使用
CompositeAlphaMode::Opaque,透明 backdrop 使用
CompositeAlphaMode::PreMultiplied。期望最大帧延迟为 2。
在 macOS 上,wgpu 的 Metal 后端只提供 Fifo 和 Immediate,因此 macOS 始终以 Fifo 呈现。
在那里,流式输出被推迟的窗口在显示链接(display link)的 tick 上准入,而不是在上次渲染一个
周期之后(见按窗口归属的帧调度)。
SonicTerm 绘制到保留式离屏帧纹理。帧键覆盖可见窗格修订号、几何、选区、标签页、
浮层、悬停、内联媒体、字体/样式状态以及其它影响画面的输入。滚动条有效透明度在每个带身份的
窗格记录中量化保存;Never、没有回滚历史的窗格,以及不高于共享发射阈值
的透明度都映射为零。每一帧都规划为三种模式之一。Noop 不重建也不提交任何内容:帧键完全相同、唯一的变化是
窗格修订号且其脏行全部滚出视图,或者帧键变化但损伤为空且没有脏实时行。其他帧都是 Partial
或 Full。硬件帧在损伤区域小于整个表面且没有任何因素要求整帧重绘时规划为 Partial:不是首帧、
没有整表面类别的变化、前后都没有活动覆盖层,并且每个干净的可见行都有有效的墨迹记录。Partial
帧组装每个脏行位置、墨迹扩边条带与损伤区域相交的每一行,以及有效墨迹记录与损伤区域、绘制出的
光标单元格或最近一次呈现的重着色范围相交的每一行(见渲染与字体)。
其他帧都是 Full。降级路径从不规划 Partial。
私有生产 FramePlan 同时拥有该帧键、最终模式、损伤区域、窗格完整/内容裁剪、已解析视口行和
预期修订号。它接收不含网格或 GPU 对象的元数据;单元格塑形和图集修改仍由 GpuRenderer
负责。同一规划器驱动确定性测试和两个呈现器。窗格内边距可能使图像内容裁剪为空,即使现有
单元格布局仍保留一格的最小尺寸。
任何未成功呈现的表面获取路径都会清除缓存帧键。Outdated 和 Suboptimal 会重新配置
表面,Lost 会重新创建并配置表面,之后的帧只有在设备仍接受工作时才会从中获取纹理;
Validation 结果会停止设备(见下文“已停止的 GPU 设备”)。重新配置前必须先释放
SurfaceTexture。因此下一帧不会把空白或已替换的交换链误认为已经绘制。
普通渲染器的字形图集在缩放 1(不超过 1.5)时起始为 1024×1024,超过 1.5 时为
2048×2048;字形放不下时按翻倍增长到最大 2048×2048。预热备用渲染器起始为 256×256。
GPU 路径上的字形纹理与 CPU 图集尺寸相同,因此缩放 1 的窗口起始时两者各占 4 MiB 而非
16 MiB,节省 12 MiB CPU 内存和 12 MiB GPU 内存。缩放 2 从最大尺寸起始,不节省内存。
这两个起始尺寸都是 sonicterm-text 中 start_size_inputs 的尺寸规则在 S9 与 S12
工作集的 CI 测量上选出的:缩放 1 的最大工作集放得进 1024,缩放 2 的最大工作集需要 2048。
Windows LCD 次像素策略
LCD 生效条件与混合公式见渲染与字体。
软件渲染降级
降级会把显示器周期替换为精确的 25,000 µs,约 40 fps。这是直接覆盖,不是
max(monitor_period, 25 ms):即使显示器只有 30 Hz,也会解析为 25 ms。输入法组字期间
周期变为 83,333 µs,约 12 fps;组字结束立即恢复 25,000 µs。硬件路径不使用输入法上限。
| 路径 | 帧周期 |
|---|---|
| 硬件 | 显示器周期 |
| 降级软件 | 25,000 µs(约 40 fps) |
| 降级软件且输入法组字中 | 83,333 µs(约 12 fps) |
降级路径会把所有重绘(包括输入引起的重绘)合并到最终周期,因为每帧都需要昂贵的 CPU
工作。滚动条在活动后立即跳到可见,并在 600 ms 空闲边界跳到隐藏。加速窗口保留 150 ms
淡入和 300 ms 淡出。两条路径上,已稳定的滚动条在空闲截止时间(last_active + 600 ms)
之前都不请求任何帧;该截止时间归其窗口所有,只触发一次,新的活动会重新设置它。在加速路径上,
它开始 300 ms 淡出。边缘悬停和拖动滑块会保持滚动条可见,不设置截止时间。目标改变后的第一步
淡变最多为一个 60 Hz 帧,因此即使唤醒延迟,淡变也会经过多帧。wgpu 表面使用
Fifo、不透明合成和期望最大帧延迟 1。
隐藏预热渲染器池默认保留一个。配置为 0 表示关闭。硬件最多接受目标值 5;降级时
任何非零目标都会限制为 1。
按窗口归属的帧调度
窗口输入和输出原因不共用应用级脏标记。硬件上的纯输入只能为其存活的来源窗口绕过帧节奏; 同时有可见输出时仍合并到帧边界。每个窗口在创建/采用、移动、缩放、改变尺寸、获得焦点和解除遮挡时 更新显示器周期;刷新率不可用或为 0 时保留上一个周期。 精确的 25,000 µs 降级周期和 83,333 µs 输入法周期仍从全局降级策略解析,不维护每窗口策略副本。
每个窗口有两个节奏时钟。last_render 是尝试时钟:每次渲染器调用都会推进它。stream_clock
在硬件路径上为流式输出定节奏。它随每次尝试推进,只有一种例外:硬件路径上针对新输入代际的尝试
没有呈现(Skipped)而结算,且没有待处理的表面超时或争用下限。因此还没等到回显的按键帧不会把
回显推迟一个周期;回显仍是流式工作,从上一次非豁免尝试开始计节奏。表面超时重试从 last_render
等待,降级的软件路径的每次尝试都从 last_render 计节奏,已呈现、缓存重绘、重试、失败和停止的尝试
会同时推进两个时钟。设置的 Frame 期限与准入使用相同的时钟选择。窗口计数器 stream_clock_exempt
统计保留 stream_clock 的尝试。
按窗口归属的唤醒项目只服务到期窗口;维护既不唤醒无关窗口,也不吞掉同时到期的重绘。已有
原生帧请求在途时,只排除重复的 Frame 期限:通知和滚动条空闲到期期限仍保持启用,到期
只清理一次,并把重绘合并到已有请求。滚动条到期只在确实改变了滚动条时才请求帧;在期限被收集
之后出现的活动、悬停或拖动会使它不产生任何效果。
在 macOS 14 及更高版本上,窗口注册时会安装每窗口的 NSView.displayLink,创建时处于暂停状态,
首选速率为窗口的显示器周期,并随每次改变周期的刷新而更新。流式规则胜出的硬件推迟在窗口有链接时
存储节奏模式 Link;表面超时或争用推迟,以及降级软件路径上或没有链接的窗口中的流式推迟,存储
Timer,沿用上述规则。Sync 推迟不存储模式,并保留已存储的模式;在准入重新评估保持之前,它暂停链接。存储的模式保持到该帧准入;链接失效会清除存储的 Link,但从不清除存储的
Timer。链接只在有待准入的 Link 时运行:等待合并在收集期限之后启动它,在没有需要链接节奏的工作
或窗口不能调度帧时暂停它。每次启动都会递增窗口的链接代际,只有属于运行中代际且有待准入 Link
时才接受 tick;被接受的 tick 授权一帧。原生遮挡和后端遮挡、设备停止、停放、隐藏以及软件降级开启
都会在写入处使链接节奏失效,递增代际并丢弃未使用的 tick。没有 tick 到来时,Frame 期限是节奏时钟
之后两个周期的回退上限。输入快速路径、表面超时重试、争用下限、25,000 µs 和 83,333 µs 周期,以及
更早的 macOS、Windows 和 Linux 都不变:它们不安装链接,按计时器计节奏。
按显示链接计节奏的帧仍可能等待 drawable。准入和同步的 present 调用在同一次 RedrawRequested
处理中执行,因此上一次 present 调用返回之前不会准入新帧;但 present 调用返回并不释放其 drawable。
wgpu-hal 的 Metal 表面把 maximumDrawableCount 设为帧延迟加一(硬件路径上为 3),关闭
allowsNextDrawableTimeout,并忽略获取超时;因此三帧都未完成时,下一次获取会在 nextDrawable
中等待。显示链接节奏不能消除这种等待,计时器路径也有同样的暴露。没有计数器测量它;Instruments 的
Metal System Trace 可以显示它。
输出事件按窗格服务。VT 工作线程为每个窗格最多保留一个未处理的 PaneOutput。事件循环在当前
持有该窗格的窗口中确认它,运行该窗口的命令维护,只有该窗口活动标签页(或其放大窗格)有未显示的
输出时才请求 Output 帧。若只有某个标签页的命令标记或其帧键中的命令状态变化,则改为请求
Chrome 帧;否则不请求任何帧,因此后台标签页的输出不花费帧:输出保留在窗格的网格和输出代际中,
切换到该标签页会标脏所有窗格并绘制最新内容。测试框架和测试发送的 RequestRedraw 仍无条件请求
Output 帧。
StructuralInvalid 消费该次尝试捕获的原因并停放窗口。停放窗口不贡献帧、重试、节奏、光标、 滚动条、通知或徽章期限。只有 Topology、Input、Visibility 或 DeviceRecovered 原因可以解除 停放;工作线程 Output 仍运行命令维护,但不会解除停放。关闭中缺失布局时静默跳过。设备停止 报告先于停放检查和帧收集执行;一次性报告不需要解析器/媒体锁。清除设备停止抑制还要求已安装 渲染器可用、未标记销毁、且代次不同;单独的恢复原因不能作为证明。该调度适配器不重建设备; 下文的共享恢复协调器先安装替换设备,再由按窗口归属的适配器准入帧。
同步输出(DEC 2026)新增 Sync 推迟规则,位于表面超时和锁争用规则之后、流式规则之前。
窗格在以下条件同时成立时保持其窗口:它属于活动标签页的可见集合,其已发布的更新仍在进行,
150 ms 期限未到,且它发布过的每次重置都已到达一次成功的帧。无论由哪个窗格引起,窗口从一段
保持的首次 Sync 推迟起最多保持 150 ms;Presented、Cached 或 Settled 结果结束这一段,
失败结果保留它。被保持的窗口在最早的保持期限或上限时唤醒,其显示链接既不运行也不接受 tick。
首帧、待处理的 Visibility 或 DeviceRecovered、表面尺寸改变,以及被重新配置或重建的表面
(Outdated、Suboptimal、SurfaceLost)会让帧越过保持;后两者只由已呈现的帧清除。
清除保留帧键(例如焦点变化)不会。两个重绘适配器都在应用回执之前、在收集到的解析器锁下重新
检查保持,并放弃被保持的帧而不结算,因此时钟、重试下限、回执和原因都不变。
遮挡与表面可用性
macOS 和 X11 的原生 Occluded 事件按窗口处理,先于主窗口和子窗口的帧收集。被遮挡窗口
保留待处理输入/输出身份和网格脏状态,但不贡献帧、光标、滚动条或通知期限,也不收集
解析器/媒体状态。PTY 输出和命令维护继续运行。应用隐藏的主窗口和未采用的预热窗口仍是
独立状态。设备拒绝边界(包括仅 smoke 使用的证据和一次性错误报告)最先执行;抑制不改写
任何节奏时钟或争用重试下限。恢复可见的转换会清除渲染器保留帧键,标记一次 Visibility 原因,
并在设备可用时最多请求一次帧。重复可见事件不增加工作;可见性不能复活已停止的设备。
遮挡 30 秒的窗口会被裁剪(内存);在 GPU 呈现器上其帧纹理降为 1×1。下一次 GPU 呈现会先按表面尺寸重建它,然后设备门控才准入该帧的上传工作;重建被拒绝时,在任何尺寸检查之前返回 渲染不可用,并保留脏状态等待之后的帧。改变尺寸、降级切换或恢复提交会自行安装表面尺寸的纹理, 因此其后的呈现不再重建。
带类型的 SurfaceRetry(Timeout) 由应用在该窗口的下一个有效帧周期处理,保留脏状态而不进入
原生自重试循环。SurfaceRetry(Occluded) 抑制帧。Atlas、Outdated、Suboptimal 和 SurfaceLost
仍由呈现器拥有重试。公开的 render -> Result 适配器只为 Timeout 和 Occluded 恢复旧的原生
重试,不对其它原因重复请求。DeferStop 和 Stop 保持原有行为。
只有 macOS 上仅后端报告的遮挡会启用异常路径的一秒表面可用性探测。原生遮挡/可见事件取消 它;应用隐藏、结构停放或设备停止的窗口不贡献探测期限。该方法通过设备门禁准入 GPU 工作, 在获取纹理前拒绝非 Metal 适配器:固定版本的 Metal 能丢弃已获取纹理,而 Vulkan 的丢弃操作 为空实现。探测只获取并丢弃,不编码、上传、提交、呈现或确认脏行。成功会清除保留身份并安排 一次 Visibility 帧;Timeout 和 Occluded 在一秒后重试。Outdated/Suboptimal 重新配置,SurfaceLost 重新创建;只有再次确认设备门禁后才重新计时。次优纹理在 configure 前丢弃。门禁拒绝时停止 探测;表面重建错误会被记录,仅当设备仍可用、窗口仍为后端遮挡、未隐藏且未结构停放时, 才重新安排一秒后的探测。这不会组装帧或消耗脏状态。原生 acquire/configure 可能阻塞; 这是低频异常检查,不是非阻塞保证,也不是普通心跳。
__occlude_next_surface_acquire 是测试故障入口,在 wgpu 呈现器的 acquire 步骤到达真实的带类型
重试出口,无需切换 Space 或遮挡窗口。它适用于各平台的 wgpu 呈现器;Windows 软件呈现器没有
surface acquire,因此已设置的故障会等到 wgpu 帧。Windows 释放顺序测试经由它驱动兼容包装器,
并检查 surface 重试保留网格脏状态。假时钟窗口测试和源代码契约覆盖策略,但不能代替同一窗口的完整应用 CPU 测量,
也不能代替恢复后首帧完整呈现的原生证据。
锁争用重试
每个窗口将 retry_not_before 与上一帧时间戳分开保存。只有收集器未能取得的可见解析器或图像存储
才进入重试路径。每次收集先试探每个可见解析器,遇到忙碌的解析器则等待,所有可见窗格共用同一个
2 毫秒截止时间;到截止时间仍忙碌,或在截止时间之后才取得,都算未取得。调度抢占可能超出该截止时间。
图像存储只试探、不等待。PTY 工作线程以公平方式释放每个解析器分段,在自己重新加锁之前把锁交给
选中的一个等待者;等待中的收集与其他阻塞的解析器调用者一起参与这次选择,不保证得到下一次交接。
没有这段等待时,洪泛期间首尾相接的分段几乎不给不等待的试探留下空隙,
大多数重绘都落入此重试下限。两个窗口角色的帧收集器都不访问非活动标签页或缩放隐藏的存储,且先持有
可见解析器,再复制可见媒体;两类快照分开取得,并非原子快照。布局结构无效时跳过整次组装,
不设置该重试下限;关闭中且没有布局的标签页静默跳过。
到期的解析器/图像收集失败时, 期限设为尝试时刻加有效帧周期,并作为普通帧节奏(包括降级输入法周期)的下限。更早的输入 或重绘事件既不能绕过它,也不能推迟它。到期再次失败才重新计时;成功收集完整帧后,会在 图集/表面重试策略之前清除该状态。关闭窗口时一并丢弃,不引入无条件重绘心跳或阻塞锁。一帧只在 组帧期间持有可见解析器保护对象;在 GPU 和 GDI 路径上,它们都会在获取表面和呈现之前释放。重试 下限仍为一个完整帧周期。
Windows CPU 呈现
Windows 上启用降级时,software_frame::SoftwareFrame 把同一套上游生成的矩形、文字字形、
彩色字形和内联图像实例合成到完整的预乘 BGRA 缓冲。仅在 Windows 编译的
software_windows 桥接层借用经过尺寸验证的帧,再用 GDI SetDIBitsToDevice 呈现到 HWND。
软件路径总是呈现完整帧,不把保留式 GPU 损伤规则再当作第二套软件呈现策略。
CPU 合成代码不导入原生窗口或 GDI,也禁止 unsafe 代码;它在 Windows 生产构建和所有主机的
单元测试中编译。同级 software_frame_tests.rs 保留像素断言,其中已有的 GPU 对照用例还需要
无窗口的 wgpu 适配器。cargo test -p sonicterm-gpu 会在 macOS、Windows 和 Linux 上运行
这些测试。原生 GDI 能力、选区呈现及冒烟检查仍只在 Windows 运行。为测试编译 CPU 合成器
不会给 macOS 或 Linux 新增软件呈现器。
软件帧任一轴最多 16,384 像素,总量最多 160 MiB。创建或调整尺寸超过任一限制时会失败, 并保留原有有效分配。帧键命中时可直接再次呈现已有 CPU 帧,无需重新合成。
软件绘制使用 CPU 图集,GPU 镜像保持 1×1 占位符。返回 GPU 时重建完整纹理、重置 携带 UV 的缓存并强制完整重绘。像素转换和采样与 GPU 绘制一致,详见 渲染与字体。
GDI 呈现器生效时不使用 wgpu 帧纹理,因此它为 1×1(4 B),否则为表面尺寸。build_frame_texture 在构造、
调整尺寸、恢复和降级切换时确定其尺寸;离开 GDI 时一次性分配完整纹理,并强制下一帧完整绘制。设备已停止时
保留旧纹理,恢复时按当前模式重建。该纹理属于 GPU 内存,不计入 retained_amounts;
GpuRenderer::frame_texture_extent 报告其尺寸。
已停止的 GPU 设备
wgpu 的 Validation、OutOfMemory 或 Internal 错误,或者设备丢失,都会停止所有窗口的渲染,因为
这些窗口共享同一设备;隔离规则见架构内部机制。
两种呈现器都遵守这一停止:wgpu
路径不提交也不呈现,Windows CPU 呈现器既不合成也不呈现帧,也不重新 blit 未变化的帧。窗口保持打开;最后呈现的像素是否
仍然可见,由操作系统和驱动决定。脏行保持未确认,shell、输入、会话和窗口生命周期照常工作。设备
停止期间修改软件渲染策略时,只记录新策略,不配置表面,也不重建 GPU 图集纹理。没有丢失记录的
Unusable 设备保持停止;已提交设备变为 Lost 后会开始共享上下文恢复。
日志中的 sonic::gpu 记录会写明使设备停止的操作和错误。
共享设备恢复
应用拥有一个已提交上下文和一个恢复协调器。设备丢失后,按启动时的特性协商和分配策略创建新的 实例、适配器、设备和队列。一个常驻工作线程请求适配器与设备,不阻塞事件循环;超时的工作线程 既不会被替换,也不会被 join。
每轮预算最多五次尝试,分别延迟 0、250 ms、1 s、4 s 和 16 s,每次请求期限为 10 s。如果较早的 请求仍在运行,到期的下一次尝试会消耗预算,但不会启动第二个工作线程。迟到结果会被丢弃,其 候选设备在事件循环线程上销毁。只有新代次首次确认呈现之后至少 30 s 才再次丢失,才会获得新预算; 单纯创建设备不算稳定证据。预算耗尽后渲染保持停止,PTY 继续存活。
事件循环先在候选设备上准备全部可见和预热渲染器,再在同一次回调中提交它们。即使尺寸相同,也会
重建表面、保留帧纹理、管线和图集上传对象。CPU 图集与携带 UV 的缓存会重置;字体、单元格度量、
终端状态和帧计数保留。恢复会重新读取当前软件渲染策略,但已有窗口保留其原生 backdrop。部分提交
失败时,在恢复事件分发前关闭并销毁候选设备。成功提交后退役旧设备,并用经过验证的替换快照
准入每个重新绑定的窗口。隐藏或原生遮挡的窗口保留脏状态而不请求帧;每个可渲染窗口合并一次
恢复帧请求。只有真正的 Presented 结果才能确认网格脏状态。
带代次标记的回调不会复活已退役设备,也不会为它们启动恢复。发起请求的窗口关闭后,请求所拥有的 在途表面仍然有效;结果返回时会重新检查仍存活的窗口。仅恢复用途的定时器不请求重绘。未返回的 结果每 100 ms 检查一次,预算耗尽后降为每 1 s 一次,仅用于在完成提示丢失时释放结果;空闲协调器 没有此类定时器。
请求期限只限定放弃尝试的决策时刻,不限定原生驱动析构或表面配置。正常结果在事件循环上释放。 应用退出后,分离工作线程的迟到结果只保证所有权安全并尽力释放,可能因原生主线程析构而阻塞; 退出不会等待该线程。启动时创建设备失败仍走原有启动路径,恢复不引入新的渲染后端。
保留像素与损伤区域
损伤区域与绘制顺序见渲染与字体。
网格脏行使用实时缓冲区的行号,因此帧计划会把每个脏行映射到绘制它的视口行位置。
实时行 r 对应绝对行 scrollback_len + r。主屏幕视图向上回滚 k 行时,它画在
第 r + k 个行位置;r + k 超出最后一行时,它不在视图中。主屏幕损伤只覆盖这些
行位置;备用屏幕没有回滚历史,仍然损伤整个窗格。每个组装的帧(Full 或 Partial)
都会让背景 quad 缓存删除表面上每个窗格的每个脏实时行对应的绝对行 scrollback_len + r,
无论该行是否在屏幕上。字形缓存不因脏行删除任何条目:它按内容为行建键,因此未变化的内容在
其他位置仍可被复用。复用仍需要保留的完整条目、匹配的键输入与图集身份,以及有效的软件块字形尺寸。
Partial 帧只组装上面列出的行。未组装的行保留其已保留的像素和墨迹记录;帧没有绘制其
行位置的脏实时行保留脏位。任何未呈现的帧(表面重试、图集重试或设备停止)都不提交记录或
回执,并清除帧键,因此下一帧是整表面的 Full。
如果一帧只改变了窗格修订号,并且每个变化窗格的脏行都已滚出视图,两条路径都不呈现
任何内容:计划为 Noop,损伤为空,也不确认任何脏行。这些行保持脏状态,直到某一帧
把它们显示出来;滚动会改变视口,所以那一帧是整表面的 Full。当旧键或新键中有覆盖层
处于活动状态(IME 预编辑、搜索、命令面板、通知、链接预览、拖动标签或焦点闪烁)时,帧键
的任何变化都改为重绘整个表面,因为预编辑跟随实时光标,而帧键只记录绘制出的光标单元格;
光标隐藏、窗口失焦、窗格只读或视图向上回滚时,该单元格不存在。没有脏实时行
也没有其他损伤的修订号变化(例如 set_autowrap 引起的)在两条路径上同样规划为 Noop。
光标、焦点、标签栏带、选区和滚动条的变化只损伤各自的区域(见渲染与字体)。 这种窄损伤只在 wgpu 保留路径绘制时生效:macOS,以及通过 wgpu 绘制的 Windows 或 Linux。降级路径 对这些变化都重绘整个表面,Windows GDI 呈现器合成整帧,不读取损伤区域。
诊断
启动日志会记录适配器后端、名称、设备类型和 software_rendering=true|false。最终启用
降级时,应用会记录:
software-render degrade engaged
并附带 detected、mode、frame_period 字段。Windows 的面包屑渲染器身份会把
CPU/GDI 软件呈现与 wgpu 区分开。
若要查看各帧阶段耗时,把 [logging].level 设为 "debug",读取 render_timing 日志目标;它为每个完成
的帧的各阶段计时。对于它看不到的内容,在同一级别读取 frame_counters 日志目标
(日志):被推迟或遇到锁忙碌的重绘、重试及其他结果、呈现间隔、解析器锁的
等待与持有、flush 到重绘的延迟,以及分发停顿。某一帧慢时用 render_timing,帧迟到、缺失或发生争用时
用 frame_counters;后者每个窗口每秒最多写一行。
内存快照与分配器状态的解释由日志和内存负责。
代码位置
| 主题 | 主要路径 |
|---|---|
| 适配器分类与表面策略 | crates/sonicterm-gpu/src/core.rs |
| 配置到降级决策 | crates/sonicterm-app/src/app/{frame_pacing,event_loop,config_apply}.rs |
| 帧节奏 | crates/sonicterm-app/src/app/{mod,frame_pacing,redraw,display_link}.rs |
| 保留帧与损伤 | crates/sonicterm-gpu/src/core.rs |
| 设备错误隔离 | crates/sonicterm-gpu/src/{device_errors,core,present}.rs |
| 共享设备恢复 | crates/sonicterm-app/src/app/{gpu_recovery,gpu_recovery_worker}.rs、crates/sonicterm-gpu/src/{recovery,recovery_context,rebind}.rs |
| GPU 绘制 | crates/sonicterm-gpu/src/wezterm_pipeline.rs |
| 保留帧复制 | crates/sonicterm-gpu/src/core.rs |
| CPU 合成与 Windows 桥接 | crates/sonicterm-gpu/src/{software_frame,software_windows}.rs |
| Windows backdrop 覆盖 | crates/sonicterm-windows/src/{main,software_presenter}.rs |