显示驱动基础:从像素到画面的第一公里
做显示驱动这么多年,我始终觉得一个道理颠扑不破——基础不牢,地动山摇。很多工程师一上来就追高刷、追低延迟,结果连帧缓冲区怎么工作的都说不清楚。今天咱们就把这第一块基石夯实了。
1.1 显示系统架构:谁在指挥谁?
先看一张图,这是我手绘的显示系统整体框架。你想想看,从你点开一个视频到屏幕上出现画面,中间经历了什么?
这张图我画了好几个版本才满意。说白了,整个显示系统就是一条流水线:应用层生成内容 → GPU渲染 → 帧缓冲区暂存 → 显示控制器读取 → 面板点亮。每个环节都有坑,我一个个说。
1.2 像素与分辨率:不是点越多越好
像素是什么?就是屏幕上最小的发光单元。一个像素通常由R、G、B三个子像素组成。分辨率呢,就是横向×纵向的像素数量。
但这里有个误区——分辨率高不等于显示效果好。我在项目里遇到过一块4K屏,色彩表现被1080p的OLED屏吊打。为什么?因为像素密度只是一方面,像素的响应时间、色域覆盖、子像素排列方式同样关键。
常见分辨率对照表(我整理项目时常用的)
| 名称 | 分辨率 | 宽高比 | 总像素数 |
|---|---|---|---|
| HD | 1280×720 | 16:9 | 921,600 |
| FHD | 1920×1080 | 16:9 | 2,073,600 |
| QHD | 2560×1440 | 16:9 | 3,686,400 |
| 4K UHD | 3840×2160 | 16:9 | 8,294,400 |
| 8K UHD | 7680×4320 | 16:9 | 33,177,600 |
嗯,这里要注意:分辨率翻倍,像素数翻4倍。这意味着带宽需求、功耗、发热都会指数级增长。我见过有人硬上8K@60Hz,结果面板驱动芯片直接过热保护——这就是没算好账。
1.3 刷新率概念:60Hz真的够用吗?
刷新率,就是屏幕每秒更新画面的次数。单位Hz。60Hz就是每秒刷新60次,每帧约16.67ms。
但这里有个容易混淆的点:刷新率 ≠ 帧率。帧率是GPU能生成多少帧,刷新率是屏幕能显示多少帧。两者不匹配时,就会出现撕裂(tearing)或者卡顿(stutter)。
我的经验之谈:
- 60Hz:日常办公、视频够用。但快速滚动网页时能感觉到闪烁
- 90Hz:人眼能感知到「流畅」的起点。我用过90Hz的手机后,再回60Hz就觉得卡
- 120Hz:游戏玩家的甜点频率。延迟从16.7ms降到8.3ms,体感明显
- 144Hz及以上:专业电竞。说实话,普通人肉眼很难分辨144Hz和240Hz的差别
为什么会这样?因为人眼的视觉暂留效应大约在10ms左右。刷新间隔低于10ms,人眼就很难感知到闪烁了。所以120Hz(8.3ms)已经超过了人眼的感知极限。
1.4 帧缓冲区原理:显存里的那点事
帧缓冲区(Frame Buffer),说白了就是显存里的一块区域,专门存放一帧画面的像素数据。GPU渲染完一帧,写到帧缓冲区;显示控制器从帧缓冲区读数据,送给面板。
这里有个经典问题:双缓冲和三缓冲。
单缓冲时代,GPU写和显示控制器读共用同一块内存。结果就是——GPU还没写完,显示控制器就开始读了,画面出现撕裂。我早期做嵌入式显示时就被这个坑过,画面一半是上一帧一半是下一帧,看着像鬼影。
解决方案?双缓冲:
// 伪代码:双缓冲交换机制
while(1) {
// 前缓冲区:显示控制器正在读取
// 后缓冲区:GPU正在渲染
render_to_back_buffer();
// 等待垂直消隐期(VBlank)
wait_for_vblank();
// 交换前后缓冲区指针
swap_buffers();
// 此时前缓冲区变成后缓冲区,继续渲染
}
双缓冲解决了撕裂,但引入了新问题——如果GPU渲染速度跟不上刷新率,画面会卡顿。比如屏幕60Hz,GPU只能跑30fps,那同一帧会被显示两次,看起来一卡一卡的。
三缓冲就是再加一个缓冲区,让GPU可以提前渲染下一帧。代价是延迟增加一帧,但画面更平滑。
我曾经踩过的坑:
在做一款高刷平板时,我用了三缓冲,结果触控延迟从20ms飙升到45ms。用户反馈「点下去半天才有反应」。后来发现是三缓冲引入了额外的帧排队延迟。解决方案是:在游戏模式下切回双缓冲,牺牲一点平滑度换响应速度。
所以,没有银弹。双缓冲、三缓冲各有适用场景,得根据产品定位来选。
1.5 时序基础:HBlank和VBlank
显示控制器读取帧缓冲区时,不是一口气读完的。它是一行一行扫描的,从左到右,从上到下。
每扫完一行,需要一段水平消隐期(HBlank)——让电子枪(或者TFT扫描线)回到下一行的起点。每扫完一帧,需要一段垂直消隐期(VBlank)——让扫描回到左上角起点。
这段消隐期不是浪费,恰恰相反:
- VBlank期间可以安全交换缓冲区,不会产生撕裂
- HBlank期间可以传输音频或辅助数据(比如eDP的AUX通道)
- 消隐期也是面板自刷新(PSR)的窗口——静态画面时,显示控制器可以休眠,省电
我习惯用这个公式估算实际带宽需求:
实际带宽 = 分辨率宽 × 分辨率高 × 刷新率 × 每像素位数 × (1 + 消隐开销)
举例:4K@60Hz,8bit RGB
= 3840 × 2160 × 60 × 24 × 1.15
≈ 13.7 Gbps
注意:这是原始数据率,还没算编码开销(比如DSI的8b/9b编码会额外增加12.5%)
你看,算下来4K@60Hz就需要将近14Gbps的带宽。如果上到4K@120Hz,直接翻倍到27Gbps。这就是为什么高刷需要更高速的接口——HDMI 2.1或者DP 1.4起步。
1.6 小结:基础决定上限
这一章的内容,说白了就是显示驱动的「ABC」。像素怎么算、刷新率怎么理解、帧缓冲区怎么管理、时序怎么估算——这些搞不清楚,后面做高刷设计就是空中楼阁。
我个人习惯是,每接手一个新项目,先把这几项参数列个表算一遍。算完心里就有底了:带宽够不够、延迟能不能接受、要不要上双缓冲还是三缓冲。这些决策,都建立在对基础概念的透彻理解上。
下一章咱们会深入具体的时序参数——HFP、HBP、VFP、VBP这些缩写到底代表什么,怎么配置才能让面板正常工作。嗯,到时候再细聊。
公众号:蓝海资料掘金营,微信deep3321