Skip to content

硬件与显示链:一帧 UI 如何到达面板 ​

返回系统栈 · 内核与驱动 · 平台、引擎与应用 · 跨层故障链

本页只处理“物理输入到像素发光”这一段。操作系统、驱动、窗口系统和引擎并不在这里重复展开,但会在交接处说明它们拿走了什么状态、又归还了什么完成信号。

先排除一个常见误解:GPU 不等于一张独立显卡。手机、笔记本的集成 GPU、SoC 内的显示控制器、统一内存架构上的图形处理器,都能走这条链。离散 GPU 会多出 PCIe 和独立显存;统一内存机器则主要受共享带宽、缓存一致性和内存压力约束。逻辑上的队列、buffer 所有权和显示时序仍然存在。

贯通例子:按下开关到一帧亮起 ​

假设一个 120 Hz 的应用中,用户点击开关,界面立即从“关”变成“开”。这一帧不能简单理解为“CPU 把像素写到屏幕”。实际发生的是一连串可并行、也必须在边界上等待的转交:

text
手指/鼠标
  -> 输入设备报告
  -> 控制器 DMA 或中断通知
  -> CPU 处理事件并更新应用状态
  -> 应用/引擎写入图形命令和资源引用
  -> GPU 执行绘制、栅格和合成
  -> 新 buffer 变为可展示
  -> 显示控制器在 vblank 后选中它
  -> 扫描器逐行送往面板
  -> 像素改变,用户看见“开”

在 120 Hz 下,相邻 vblank 的理论间隔约为 8.33 ms;在 60 Hz 下约为 16.67 ms。这不是应用可独占的预算。输入到达的位置、CPU 是否被抢占、资源是否已在显存、GPU 队列深度、合成器策略、面板刷新方式都会挤占或改变它。错过一次显示提交窗口,通常不是晚 1 ms,而是至少再等一个刷新周期。

1. 输入设备和控制器:动作先成为报告 ​

鼠标、键盘、触摸屏、手写笔并不把“点击组件 A”交给应用。它们产生的是设备报告:按键位、相对位移、绝对坐标、接触点、压力、时间等。USB HID、I2C HID、蓝牙 HID 是常见传输与报告约定;触摸屏控制器通常还会做去噪、接触点追踪或坐标转换的一部分工作。

项目内容
输入物理开关变化、光学传感器采样、电容触摸采样
拥有状态设备固件中的采样/去抖状态,主控中的报告环形缓冲区
输出给总线控制器的报告;最终进入内核输入子系统
同步/等待中断通知 CPU,或由驱动轮询;报告可在内核队列中排队
用户可见故障鼠标跳动、漏抬起、触摸漂移、输入整体滞后;这些发生时 UI 代码可能完全没有运行

这里的关键时间不是“浏览器收到 click”,而是硬件第一次完成采样。操作系统会在后续阶段添加时间戳和坐标变换;不同平台对它们的精度与语义不同,不能把 JavaScript 或 Flutter 的事件时间直接当成传感器时间。

2. CPU、缓存与主内存:把报告变成状态变更 ​

CPU 核执行中断处理、内核输入路径、窗口系统路由、应用事件处理以及部分图形命令录制。它没有一块统一的“CPU 内存”:寄存器、L1/L2 缓存、可能共享的末级缓存和 DRAM 组成层级。越靠近核心,容量越小、延迟越低;跨核心共享数据需要缓存一致性协议和内存屏障来约束可见顺序。

对 UI 帧而言,应用线程更常见的敌人是延迟抖动而非平均吞吐:

  • 事件线程在忙于长脚本、布局、垃圾回收或锁竞争,内核已经有报告但用户动作还未被处理。
  • 工作集超过缓存,或内存分配与访问模式很差,CPU 花在 cache miss 和内存等待上的时间上升。
  • 内存紧张导致压缩、回收或换页。换页落到磁盘时,交互延迟会远超一帧预算。
  • 多核心不自动等于更快。关键路径若需要同一线程串行运行,额外核心只能承担可拆分的工作;跨线程同步还可能增加等待。
项目内容
输入内核调度的事件处理、应用状态、布局/绘制计算、资源数据
拥有状态线程寄存器与栈、缓存行、虚拟地址空间、应用堆和图形命令内存
输出新应用状态、显示列表/命令缓冲、给驱动的资源引用与提交请求
同步/等待线程调度、锁/原子操作、fence 等待、缺页处理;缓存一致不等同于业务状态正确
用户可见故障点后数十到数百毫秒才反馈、滚动卡住、偶发长卡顿、同一操作时快时慢

CPU 的虚拟地址不是 GPU 或显示控制器一定能直接读取的物理地址。内核和驱动会建立页映射、pin 或 DMA 映射,并在安全边界上验证访问。具体机制见内核与驱动。

3. 内存边界:PCIe、统一内存与资源驻留 ​

图形资源包括顶点/路径数据、纹理、字形图集、离屏渲染目标和最终可展示的 surface。应用通常只持有 API 对象或映射过的内存;真正的物理页位置、是否可被 GPU 访问、何时可以复用由运行时、驱动和内核共同决定。

离散 GPU ​

离散 GPU 有自己的显存(VRAM)。CPU 侧数据上传到 VRAM 或从 VRAM 读回,可能经过 PCIe。PCIe 带宽很高,但不是零成本、也不是与 DRAM 一样的访问路径;频繁上传整张大纹理、每帧从 GPU readback 到 CPU、或在总线两端来回复制,都会造成可测量的延迟和带宽消耗。

集成 GPU 与 SoC ​

集成 GPU 或移动 SoC 通常与 CPU 共享物理 DRAM,有时称统一内存。共享物理内存不表示“零同步”或“零复制”:CPU/GPU 缓存域、内存布局、保护域与访问时序仍需协调;GPU 大量读取纹理和显示控制器 scanout 也会与 CPU 争用 DRAM 带宽。某些平台还会有专用的压缩格式、tile memory 或片上缓存。

项目内容
输入CPU 生成的资源、已有纹理/目标 surface、GPU 对页和布局的访问需求
拥有状态驱动的资源映射与驻留信息,GPU 的缓存与地址转换状态,内存控制器的带宽仲裁
输出GPU 可读写的 buffer/纹理;可供显示控制器读取的 scanout buffer
同步/等待上传完成、资源 barrier、CPU-GPU cache flush/invalidate、fence;API 隐式同步的具体时机因驱动而异
用户可见故障首次显示图片卡顿、切换页面掉帧、显存/内存压力下纹理被逐出后重传、readback 导致动画顿挫

开发者层的实际原则是:资源尽量在被消费的一侧保持可复用,避免把每帧像素搬回 CPU;但不应以设备型号猜测实现。用图形调试器、性能计数器和 trace 验证上传、带宽与队列等待。

4. GPU:命令队列不是“立刻画完” ​

GPU 擅长对大量顶点、像素或计算线程执行相近指令。它通常有一个或多个硬件/驱动可见队列。CPU 把命令缓冲提交到队列,提交成功只表示工作被接收或排队,不表示像素已经生成。GPU 的执行单元、纹理采样单元、缓存、光栅后端和内存系统会在随后执行这些工作。

对传统 2D/3D 图形,可粗略看成以下管线:

text
几何/路径或四边形
  -> 顶点处理与图元装配
  -> 裁剪、变换、光栅化
  -> fragment/pixel shader 取纹理、计算颜色
  -> 深度/模板/混合
  -> 写入渲染目标

现代 UI 并不一定逐项使用经典 3D 管线。文本、圆角、阴影、路径可能先在 CPU 或 GPU 上栅格化为纹理,也可能通过计算着色器生成;合成器再把多个图层作为纹理画成最终表面。共同点是:命令描述工作,GPU 异步产生 buffer 中的像素,不能在尚未完成时被显示控制器或 CPU 当成稳定结果读取。

项目内容
输入command buffer、管线状态、几何、纹理、uniform、目标 buffer、同步对象
拥有状态队列顺序、上下文/管线状态、片上缓存、正在执行的 wave/warp,资源读写依赖
输出写完的渲染目标、信号化的 fence/semaphore、时间戳或查询结果
同步/等待队列内通常按提交顺序;跨队列、跨进程或交给显示前依赖显式/隐式同步;CPU 不应在热路径阻塞等待 GPU 完成
用户可见故障GPU 满载时动画稳定地低帧率;shader 首次编译或纹理 miss 造成首帧毛刺;错误同步可能是闪烁、旧帧或损坏画面

栅格化与合成的边界 ​

栅格化回答“矢量、文本、图片和效果怎样变成一个 buffer 的像素”;合成回答“哪些已经准备好的 layer 以什么变换、裁剪、不透明度顺序放进最终帧”。把滚动层、视频层或动画层独立出来,可能让合成器只重组已有纹理而不重画整页;但 layer 过多也会增加显存、提交和合成成本。浏览器和 Flutter 的具体决策见平台、引擎与应用。

5. Buffer 所有权:生产、展示和复用必须分开 ​

最终画面至少涉及三个角色:生产者(GPU/合成器)、消费者(显示控制器)和协调者(窗口系统/合成器/驱动)。同一块 buffer 在一个时刻不能既被 GPU 改写又被显示控制器扫描,否则画面会混合新旧内容。

双缓冲的基本模型是:显示控制器扫描 front buffer,生产者写 back buffer;在合适的刷新边界交换它们。三缓冲或更多队列 buffer 可以让 GPU 继续生产,减少生产者因错过 vblank 而空等,但也可能让最新输入排在旧帧之后,提高端到端延迟。低延迟与稳定吞吐之间没有一套对所有产品都最优的缓冲深度。

text
GPU/合成器写 buffer N
          |  (render-complete fence)
          v
窗口系统/驱动把 N 标为可展示
          |  (下一次允许的 page flip / present)
          v
显示控制器扫描 N
          |  (release / retire 信号)
          v
生产者才可复用 N
项目内容
输入已申请的 surface/buffer,GPU 完成信号,显示刷新事件
拥有状态每个 buffer 的 producer/consumer 所有权、acquire/release fence、队列深度、展示顺序
输出被选作 scanout 的 buffer,或归还给生产者复用的 buffer
同步/等待acquire 表示可写/可读,release 表示消费者已用完;不同系统名称不同,所有权转换不可省略
用户可见故障buffer 不够时 producer 阻塞并掉帧;队列太深时操作“跟手”变差;同步错误可见为闪屏、旧内容或随机花屏

6. 显示控制器和 scanout:最后不是 GPU 在“刷新屏幕” ​

显示控制器(display controller / display engine)通常是 SoC 或 GPU 内的专用硬件。它从一个或多个指定 buffer 按像素时钟和时序读取数据,进行可能的平面叠加、缩放、颜色转换、HDR/色彩管理处理,然后将信号送往内建面板或 HDMI/DisplayPort 等链路。这个连续读取过程叫 scanout。

面板通常从顶部到下方逐行接收一帧,而非在某个瞬间整体替换像素。完成一帧扫描到下一帧开始之间会出现垂直消隐相关的时序窗口;操作系统和图形栈常把 vblank 事件作为安全地 page flip 或节流提交的参考点。实际面板、接口和合成策略会改变精确时机。

项目内容
输入scanout buffer 的地址/格式、平面配置、显示模式、page-flip 请求
拥有状态当前与待切换的 framebuffer、时钟/扫描位置、颜色与平面配置
输出面板或外接显示器的像素流;vblank/page-flip 完成事件
同步/等待只能读取 render-complete 的 buffer;正常 vsync 策略等待恰当扫描边界;可变刷新率还会协商刷新区间
用户可见故障全屏卡顿但 CPU 未满、外接屏刷新异常、颜色/缩放不对、特定显示器下闪烁或黑屏

vblank、vsync、撕裂和掉帧 ​

  • vblank 是显示扫描时序中的事件/区间,硬件与内核可报告它。
  • vsync 是图形栈把展示或生产节奏与显示刷新对齐的一类策略。不同 API、窗口系统和厂商驱动对其命名及默认行为不同。
  • 撕裂(tearing) 发生在显示控制器正在扫描一帧时,scanout 源被切换或其中内容被改写,屏幕上部和下部来自不同帧。允许立即展示可降低等待,却增加撕裂风险。
  • 掉帧(missed frame) 是新 buffer 没赶上预定展示窗口,显示器只能重复旧帧或展示较旧的已完成帧。掉帧不必然撕裂;撕裂也不等于应用掉帧。

可变刷新率(VRR)可以在面板支持范围内改变相邻刷新的间隔,减少固定刷新下的等待或重复帧;它不能让尚未完成的 CPU/GPU 工作凭空完成,也不能修复错误的 buffer 同步。

7. 把现象放回正确节点 ​

现象优先检查的边界不应直接下的结论
点击后很久才有视觉反馈输入时间戳、主线程调度、事件处理与第一笔图形提交“GPU 慢”
动画每隔几秒顿一下CPU 长任务、GC、资源上传、shader 编译、GPU 队列等待“刷新率不够”
平均帧率高但拖动不跟手buffer 队列深度、present 策略、输入到展示延迟“60 FPS 就足够低延迟”
画面出现横向断层scanout/page flip 时序、允许 tearing 的展示策略“布局算错了”
首次打开某页卡一下图片解码、纹理上传、管线/着色器准备、内存驻留“框架首次渲染必然慢”
外接屏独有的闪烁或颜色问题显示模式、线缆/接口、驱动、色彩/HDR、VRR“应用 CSS 或 Widget 有问题”

定位应沿链采集证据:输入事件时间、应用状态变更、CPU trace、图形 API/驱动提交、GPU 队列与频率、present/page-flip、实际 vblank。单独看应用日志、单独看 FPS 或单独看 CPU 利用率,都不足以定位端到端延迟。

平台差异与边界 ​

上文描述的是跨平台的职责关系,不是某一厂商驱动的内部实现承诺。

  • Linux 常用 DRM/KMS 表达 connector、CRTC、plane、framebuffer 与 page flip;Android SurfaceFlinger/BufferQueue、Windows DWM/DXGI、macOS 的 WindowServer/Metal、浏览器自身合成器会以不同对象名实现相近的所有权交接。
  • Vulkan、Metal、Direct3D、OpenGL 与 WebGPU 的同步模型不同。显式 API 会把更多 barrier/fence/semaphore 责任暴露给调用方;高层框架通常封装了一部分,但不能消除硬件依赖。
  • 合成器能否绕过一次合成直接使用硬件 plane、显示器是否支持 VRR、buffer 数量、tile-based 或 immediate-mode GPU、独显或统一内存,都会改变性能特征和 trace 的具体形态。
  • 刷新率只是显示链的一项参数。触摸采样率、合成节奏、输入预测、面板响应时间和系统的节能策略同样影响用户感到的延迟。

因此,先用本页的状态、所有权和等待点建立假设,再在目标设备、目标系统版本和目标驱动上验证。不要从某台机器的一张性能图推导所有客户端的规律。

一手资料与规范 ​

  • Linux DRM/KMS documentation,Linux 内核文档,访问日期:2026-07-30。说明 KMS 对象、atomic modesetting 和 page flip 的内核接口;Linux 专属。
  • Linux input subsystem,Linux 内核文档,访问日期:2026-07-30。说明输入设备与事件处理;Linux 专属。
  • Vulkan Specification: Synchronization and Cache Control,Khronos,访问日期:2026-07-30。说明 GPU/内存依赖和同步的规范语义;适用于 Vulkan,不可直接外推到其他 API。
  • Vulkan Guide: Swapchain,Khronos,访问日期:2026-07-30。说明 image acquisition、presentation 和 swapchain;具体 present mode 取决于平台与驱动。
  • Android graphics architecture,Android Open Source Project,访问日期:2026-07-30。说明 BufferQueue、SurfaceFlinger 与显示合成;Android 平台专属。
  • Apple: Metal Best Practices Guide,Apple,访问日期:2026-07-30。说明资源、命令缓冲和同步的 Metal 视角;Apple 平台专属,内容随 SDK 更新。

下一页:内核与驱动。

学习规划与研究资料库