1. FrameBuffer 基础概念
1.1 什么是 FrameBuffer
FrameBuffer(帧缓冲)是 Linux 内核为显示设备提供的一套抽象接口层,它将显存映射到用户空间,使应用程序可以直接向显示缓冲区写入像素数据,而无需关心底层显示控制器的具体寄存器操作。FrameBuffer 的本质是一块连续的内存区域,每个内存单元对应屏幕上的一个像素点。
核心定义:FrameBuffer 是位于系统主存或专用显存中的一块连续内存区域,用于存储一帧完整的图像数据。驱动程序通过操作该缓冲区实现屏幕内容的更新。
| 概念 | 说明 |
|---|---|
| 帧缓冲 (FrameBuffer) | 存储一帧完整图像数据的连续内存区域 |
| 像素 (Pixel) | 屏幕显示的最小单位,每个像素由 RGB 或 ARGB 颜色分量组成 |
| 颜色深度 (Color Depth) | 每个像素占用的位数,常见 16bpp、24bpp、32bpp |
| 分辨率 (Resolution) | 屏幕的宽度和高度像素数,如 1920×1080 |
| 行跨度 (Pitch/Stride) | 每行像素占用的实际字节数,可能包含对齐填充 |
提示:FrameBuffer 的大小 = 分辨率宽度 × 分辨率高度 × (颜色深度 / 8)。例如 1920×1080@32bpp 的帧缓冲大小为 1920×1080×4 = 8,294,400 字节(约 7.9 MB)。
1.2 显示子系统架构
嵌入式 Linux 显示子系统采用分层架构设计,从上到下依次为:用户空间应用程序、图形库/窗口系统、FrameBuffer 设备驱动、显示控制器硬件。
1.3 帧缓冲与显存的关系
帧缓冲与显存之间存在紧密的映射关系。在嵌入式系统中,显存可以是系统主存的一部分(通过 DMA 预留),也可以是独立的视频内存。FrameBuffer 驱动负责建立帧缓冲与显存之间的映射,并管理数据的传输。
| 特性 | 系统主存作为显存 | 独立显存 |
|---|---|---|
| 典型场景 | 低端嵌入式设备、MCU | 高端 SoC、GPU 集成 |
| 访问速度 | 受系统总线带宽限制 | 高带宽专用接口 |
| 成本 | 低(共享内存) | 高(额外芯片) |
| DMA 传输 | 需要 CPU 参与或 DMA 引擎 | 硬件自动刷新 |
| 典型容量 | 几百 KB ~ 几 MB | 几十 MB ~ 几百 MB |
1.4 FrameBuffer 设备文件与操作接口
在 Linux 系统中,FrameBuffer 设备以字符设备文件的形式呈现,通常位于 /dev/fb0、/dev/fb1 等。应用程序通过标准的文件操作接口与 FrameBuffer 交互。
关键设备文件:
/dev/fb0— 主显示设备(通常为 LCD 屏幕)/dev/fb1— 次显示设备(如 HDMI 输出)/proc/fb— 查看当前系统注册的 FrameBuffer 设备列表
// 典型的 FrameBuffer 操作流程
int fb_fd = open("/dev/fb0", O_RDWR);
if (fb_fd < 0) {
perror("open fb0 failed");
return -1;
}
// 获取固定信息(显存大小、起始地址等)
struct fb_fix_screeninfo fix;
ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix);
// 获取可变信息(分辨率、颜色深度等)
struct fb_var_screeninfo var;
ioctl(fb_fd, FBIOGET_VSCREENINFO, &var);
// 将帧缓冲映射到用户空间
size_t screensize = var.xres * var.yres * (var.bits_per_pixel / 8);
char *fbp = (char *)mmap(NULL, screensize, PROT_READ | PROT_WRITE,
MAP_SHARED, fb_fd, 0);
// 直接写入像素数据
memset(fbp, 0xFF, screensize); // 全白显示
// 清理
munmap(fbp, screensize);
close(fb_fd);
1.5 关键数据结构
FrameBuffer 驱动核心使用两个关键结构体来描述显示设备:fb_fix_screeninfo(固定信息)和 fb_var_screeninfo(可变信息)。
| 结构体 | 字段 | 说明 |
|---|---|---|
| fb_fix_screeninfo | smem_start |
帧缓冲物理起始地址 |
smem_len |
帧缓冲总长度(字节) | |
line_length |
每行像素的字节数(含对齐) | |
type |
显示类型(如 FB_TYPE_PACKED_PIXELS) | |
| fb_var_screeninfo | xres / yres |
可见分辨率宽度和高度 |
xres_virtual / yres_virtual |
虚拟分辨率(支持双缓冲时更大) | |
bits_per_pixel |
颜色深度(16/24/32) | |
red / green / blue / transp |
各颜色分量的位偏移和长度 | |
activate |
参数生效模式(立即/垂直同步) |
注意:虚拟分辨率(
xres_virtual / yres_virtual)是实现双缓冲机制的关键。通过将虚拟分辨率设置为可见分辨率的 2 倍(高度方向),可以在同一帧缓冲中容纳两个页面,通过修改显示起始地址实现页面切换。
1.6 帧缓冲与显存的数据传输路径
从应用程序写入像素数据到屏幕最终显示,数据经历以下传输路径:
- 用户空间写入:应用程序通过 mmap 映射直接向帧缓冲写入像素数据
- 内核缓冲同步:驱动将用户数据同步到内核管理的 DMA 缓冲区
- DMA 传输:显示控制器通过 DMA 引擎从物理显存读取数据
- 像素扫描输出:显示控制器按行扫描顺序将像素数据发送到显示接口
- 屏幕刷新:LCD/HDMI 接口接收像素数据并刷新屏幕显示
性能要点:在双缓冲机制中,应用程序写入后台缓冲区的同时,显示控制器读取前台缓冲区,两者互不干扰。通过 DMA 传输可以避免 CPU 直接参与像素数据的搬运,显著降低 CPU 占用率。