1. FrameBuffer 基础概念
1.1 什么是 FrameBuffer
FrameBuffer(帧缓冲)是 Linux 内核提供的一种抽象显示设备接口。它将显存映射到用户空间,应用程序可以直接向这块内存写入像素数据,无需关心底层显示硬件的具体实现。简单来说,FrameBuffer 就是一块“画布”,CPU 或 GPU 在上面绘制图像,显示控制器则定时扫描这块画布的内容并输出到显示器。
核心定义:FrameBuffer 是位于系统主存或专用显存中的一块连续内存区域,存储了屏幕每个像素的颜色值。Linux 通过
/dev/fb0 设备文件暴露给用户空间,应用程序使用 mmap() 系统调用将其映射到进程地址空间,直接读写像素数据。
| 概念 | 说明 |
|---|---|
| 像素数据 | 每个像素由若干字节表示,常见格式有 RGB565(16位)、RGB888(24位)、ARGB8888(32位) |
| 显存地址 | FrameBuffer 的物理地址由显示控制器固定映射,通过 mmap() 映射到用户虚拟地址空间 |
| 刷新机制 | 显示控制器以固定帧率(如 60Hz)从 FrameBuffer 读取数据,逐行扫描输出到显示器 |
| 设备节点 | /dev/fb0 是第一个帧缓冲设备,/dev/fb1 对应第二个,以此类推 |
1.2 帧缓冲在 Linux 图形栈中的位置
Linux 图形栈从底层到上层分为多个层次,FrameBuffer 位于内核空间,是显示输出的最底层接口之一。理解它的位置有助于把握整个图形系统的数据流向。
| 层次 | 组件 | 说明 |
|---|---|---|
| 用户空间应用 | Qt / GTK / SDL / Wayland 客户端 | 图形界面程序,通过 EGL / DRM / fbdev 接口绘制 |
| 显示服务器 | Xorg / Wayland (Weston / KWin) | 管理窗口合成、输入事件分发,输出合成后的帧 |
| 图形库 | Mesa / EGL / OpenGL ES / Vulkan | 提供硬件加速渲染 API,生成像素数据 |
| 内核 DRM/KMS | Direct Rendering Manager + Kernel Mode Setting | 现代 Linux 显示核心,管理显存、模式设置、VSync |
| FrameBuffer 层 | fbmem.c + fb_ops 驱动回调 | 传统帧缓冲接口,提供 /dev/fb0 设备节点 |
| 硬件层 | LCD 控制器 / HDMI TX / VGA DAC | 物理显示接口,将数字信号转换为模拟/数字视频信号 |
注意:在嵌入式 Linux 系统中,FrameBuffer 仍然是主流显示接口,尤其在没有 GPU 或 DRM 支持的平台上。而在桌面 Linux 中,DRM/KMS 已逐步取代传统 FrameBuffer,但
/dev/fb0 作为兼容接口仍然存在。
1.3 FrameBuffer 与 VGA/HDMI 的关系
FrameBuffer 是内存中的像素数据缓冲区,而 VGA 和 HDMI 是物理传输接口标准。两者之间的关系可以概括为:FrameBuffer 提供“内容”,VGA/HDMI 提供“通道”。
- VGA(Video Graphics Array):模拟视频接口,传输 RGB 模拟信号 + 行场同步信号。显示控制器将 FrameBuffer 中的数字像素值通过 DAC(数模转换器)转换为模拟电压,经 VGA 线缆传输到显示器。
- HDMI(High-Definition Multimedia Interface):数字视频/音频接口,传输 TMDS 差分信号。显示控制器将 FrameBuffer 中的数字像素值直接打包为 TMDS 数据包,通过 HDMI 线缆传输,无需 DAC 转换。
- 共同点:无论使用哪种物理接口,显示控制器都从同一个 FrameBuffer 内存区域读取像素数据。驱动只需配置好显存地址和时序参数,硬件自动完成扫描输出。
| 特性 | VGA | HDMI | FrameBuffer 角色 |
|---|---|---|---|
| 信号类型 | 模拟(RGB + 同步) | 数字(TMDS 差分) | 提供数字像素源 |
| 是否需要 DAC | 是(数字→模拟) | 否(直接数字传输) | FrameBuffer 始终为数字格式 |
| 最大分辨率 | 2048×1536(受限于模拟带宽) | 4096×2160(HDMI 2.0) | 由显存大小和控制器能力决定 |
| 音频传输 | 不支持 | 支持(内嵌音频流) | FrameBuffer 仅处理视频像素 |
| 驱动配置 | 设置时序、DAC 参考电压 | 设置时序、TMDS 时钟、EDID 解析 | 统一通过 fb_var_screeninfo 配置 |
常见误区:FrameBuffer 不等于 VGA 或 HDMI。FrameBuffer 是软件层面的内存缓冲区,VGA/HDMI 是硬件物理接口。同一个 FrameBuffer 驱动可以同时支持 VGA 和 HDMI 输出,只需在硬件初始化时配置不同的显示控制器寄存器。例如,许多嵌入式 SoC 的 LCDC 控制器可以同时驱动 VGA DAC 和 HDMI PHY。
1.4 FrameBuffer 驱动核心数据结构
Linux 内核中,FrameBuffer 驱动围绕 struct fb_info 和 struct fb_ops 两个核心结构体展开。理解这些数据结构是编写 FrameBuffer 驱动的基础。
/* 核心结构体:fb_info */
struct fb_info {
struct fb_var_screeninfo var; /* 可变参数:分辨率、位深、时序 */
struct fb_fix_screeninfo fix; /* 固定参数:显存地址、行长度 */
struct fb_ops *fbops; /* 驱动操作函数指针 */
struct device *device; /* 关联的设备 */
char __iomem *screen_base; /* 显存虚拟地址基址 */
unsigned long screen_size; /* 显存大小(字节) */
void *par; /* 驱动私有数据 */
};
/* 可变参数结构体:应用层可修改 */
struct fb_var_screeninfo {
__u32 xres; /* 可见分辨率:宽度(像素) */
__u32 yres; /* 可见分辨率:高度(像素) */
__u32 bits_per_pixel; /* 每像素位数:16/24/32 */
__u32 pixclock; /* 像素时钟(皮秒) */
__u32 left_margin; /* 行同步后沿 */
__u32 right_margin; /* 行同步前沿 */
__u32 upper_margin; /* 场同步后沿 */
__u32 lower_margin; /* 场同步前沿 */
__u32 hsync_len; /* 行同步脉冲宽度 */
__u32 vsync_len; /* 场同步脉冲宽度 */
};
/* 固定参数结构体:驱动初始化时设定,应用层只读 */
struct fb_fix_screeninfo {
char id[16]; /* 驱动名称标识 */
unsigned long smem_start; /* 显存物理地址 */
__u32 smem_len; /* 显存长度 */
__u32 line_length; /* 一行像素占用的字节数 */
__u32 visual; /* 颜色模式:真彩/伪彩/灰度 */
};
关键字段说明:
screen_base:驱动通过ioremap()或dma_alloc_coherent()映射的虚拟地址,应用程序mmap()时最终映射到该地址。line_length:等于xres * bits_per_pixel / 8,通常需要对齐到 4 字节或 16 字节边界。pixclock:决定刷新率,refresh = 1 / (pixclock * (xres+hmargin) * (yres+vmargin))。
1.5 本章小结
- FrameBuffer 是 Linux 内核提供的显存抽象接口,通过
/dev/fb0暴露给用户空间。 - 在 Linux 图形栈中,FrameBuffer 位于内核空间,位于 DRM/KMS 之下、硬件层之上。
- FrameBuffer 提供像素数据内容,VGA/HDMI 提供物理传输通道,两者通过显示控制器桥接。
- 驱动核心数据结构为
struct fb_info,包含可变参数(分辨率、时序)和固定参数(显存地址、行长度)。