2. 显示系统基础

在开始移植 Framebuffer 或 DRM 驱动之前,必须先建立一套关于“显示系统如何把一块内存变成屏幕画面”的完整心智模型。显示子系统本质上是一条从显存中的像素数据到屏幕上的可见光的流水线:CPU/GPU 负责往显存里写像素,显示控制器(Display Controller)按固定节奏把像素读出来,通过接口送到面板,面板再逐行逐帧地点亮。理解这条链路上的每个术语,是后续排查“黑屏、花屏、偏移、撕裂、刷新异常”等问题的前提。

一、像素格式:内存中一个像素长什么样

像素格式(Pixel Format)描述的是“一个像素在内存里如何编码”。它至少包含三个维度:颜色分量(RGB、YUV、灰度)、每分量位宽(如 5/6/5、8/8/8)、内存排布顺序(如 RGB565 与 BGR565 的区别)。Framebuffer 驱动中最常见的格式包括:

  • RGB565:16bpp,红 5 位、绿 6 位、蓝 5 位,常用于低成本 LCD。
  • RGB888 / XRGB8888:32bpp,实际使用 24 位颜色,最高字节常被忽略或作为 Alpha。
  • ARGB8888:带 8 位 Alpha,用于图层混合与半透明叠加。
  • YUV420:视频常用,亮度与色度分离,常见于摄像头与视频播放通路。

像素格式不匹配是“颜色错乱”的第一大原因。例如把 RGB565 的数据按 RGB888 解释,会出现明显的偏色与条纹;把 BGR 当成 RGB,则红蓝通道互换。移植时务必确认 struct fb_var_screeninfo 中的 red/green/blue 偏移与位宽,或 DRM 中的 DRM_FORMAT_* 四字符码。

二、分辨率、刷新率与显存带宽

分辨率指一帧画面的像素列数与行数,如 1920×1080。它决定了单帧像素总量。刷新率(Refresh Rate)指每秒扫描输出的完整帧数,单位 Hz,如 60Hz。二者与像素格式共同决定了显存带宽需求:

带宽 ≈ 宽 × 高 × 每像素字节数 × 刷新率 × 开销系数
例:1920×1080×4B×60Hz ≈ 497 MB/s(不含消隐与多图层开销)

这个数字非常关键:如果 DDR 带宽不足或显示控制器与 GPU 争抢总线,就会出现掉帧、闪烁甚至花屏。很多移植失败并非驱动逻辑错误,而是带宽预算没有算清。

三、时序参数:扫描输出的“节拍表”

显示控制器并不是只输出有效像素,它还必须输出消隐区(Blanking)。一帧的完整时序由以下参数描述:

  • Hactive / Vactive:水平/垂直有效像素数,即分辨率。
  • Hfront porch / Hback porch:水平前肩与后肩,用于行同步前后的空闲期。
  • Hsync:水平同步脉冲宽度。
  • Vfront porch / Vback porch / Vsync:垂直方向对应参数。
  • Pixel Clock:像素时钟,决定每个像素输出的时间基准。

这些参数通常由面板数据手册(Datasheet)给出,或由 EDID 读取得到。移植时若时序写错,典型现象是画面偏移、抖动、无法点亮或只显示部分区域。下面这张图展示了从显存到面板的完整信号链与关键参数位置:

显示系统数据流:从显存到面板 显存 Framebuffer 像素格式:RGB565 ARGB8888 / YUV420 stride / pitch 对齐 显示控制器 DMA 读取 + FIFO 时序发生器 图层混合 / Gamma 显示接口 RGB / MIPI-DSI LVDS / eDP / HDMI 差分对 / 时钟 面板 LCD / OLED 背光 / 驱动 IC 逐行扫描 一帧时序参数(以 1920×1080@60Hz 为例) Hsync HBP Hactive = 1920 HFP 下一行 Vsync VBP Vactive = 1080 VFP 下一帧 关键参数与常见取值 Pixel Clock 148.5 MHz Htotal / Vtotal 2200 / 1125 刷新率 60 Hz 带宽需求 ≈ 497 MB/s

四、显存与扫描输出:谁在什么时候读内存

扫描输出(Scanout)是显示控制器按像素时钟节奏,从显存中逐行读取像素并送往接口的过程。它有两个关键特性:

  1. 连续性:扫描输出必须持续不断,一旦 FIFO 下溢(Underflow),画面就会闪烁或撕裂。
  2. 地址映射:显存中的帧缓冲通常不是“一行紧接一行”的连续区域,而是按 stride(行跨度)对齐。若 stride 设置错误,画面会倾斜或出现斜纹。

在 Framebuffer 框架中,这些信息由 fb_fix_screeninfo 与 fb_var_screeninfo 描述;在 DRM 中,则由 drm_framebuffer、drm_plane 与 drm_crtc 共同管理。移植时最常见的动作就是:根据面板手册填写 mode,分配 framebuffer,设置格式与 stride,然后使能 CRTC。

核心公式: Pixel Clock = Htotal × Vtotal × 刷新率。其中 Htotal = Hactive + HFP + Hsync + HBP,Vtotal = Vactive + VFP + Vsync + VBP。任何一项写错,都会导致刷新率偏离或无法点亮。

五、案例场景:一次“画面右移”的排查

某项目移植 MIPI-DSI 面板后,画面整体向右偏移约 80 像素,左侧出现黑边。排查过程如下:

  • 确认分辨率与刷新率正确,排除模式设置错误。
  • 检查 Hback porch,发现驱动中写成了 40,而面板手册要求 120。
  • 修正 HBP 后,Pixel Clock 需同步重算,否则刷新率会从 60Hz 变为约 58Hz。
  • 重新编译并加载驱动,画面恢复正常。

这个案例说明:时序参数是一个整体,修改任何一项都要重新校验 Pixel Clock 与刷新率,不能孤立地“只改一个数”。

六、常见术语速查表

术语 含义 移植关注点
Pixel Format 像素在内存中的编码方式 RGB/BGR 顺序、位宽、Alpha
Resolution 有效像素列数×行数 与面板物理分辨率一致
Refresh Rate 每秒输出帧数 由 Pixel Clock 与总时序反推
Porch 同步前后的消隐区 HBP/HFP/VBP/VFP 必须匹配手册
Stride / Pitch 显存中一行占用的字节数 对齐要求、避免斜纹
Scanout 控制器从显存读取并输出 FIFO 下溢、带宽争抢
EDID 显示器能力描述数据 HDMI/eDP 自动获取时序
常见误区:很多初学者认为“分辨率对了画面就对了”。实际上,分辨率只决定有效区域,消隐区、同步极性、Pixel Clock 共同决定画面是否稳定、是否偏移、是否能被面板锁定。移植时请把时序参数当作一个整体来校验。
实操建议:拿到一块新面板,先做三件事:① 从手册抄下完整时序表;② 用公式反算 Pixel Clock 与刷新率;③ 在驱动中打印 fb_var_screeninfo 或 DRM mode,确认写入值与手册一致。这三步能排除大部分“点不亮”和“显示异常”问题。

掌握像素格式、分辨率、刷新率、时序参数、显存与扫描输出这六个基础概念后,后续无论是分析 Framebuffer 的 ioctl 调用,还是理解 DRM 的 Atomic Modesetting,都会有一个稳定的参照系。它们是显示驱动移植中最底层、也最不该被跳过的一课。