1. 帧缓冲(Framebuffer)基础概念
1.1 什么是帧缓冲
帧缓冲(Framebuffer) 是操作系统内核中用于管理显示输出的一块连续内存区域,它直接映射到显示设备的像素数据。应用程序通过向帧缓冲写入像素数据,即可在屏幕上呈现图像,无需关心底层显示硬件的具体细节。
在 Linux 系统中,帧缓冲被抽象为一个字符设备,通常位于 /dev/fb0、/dev/fb1 等节点。用户空间程序可以通过 mmap() 系统调用将帧缓冲映射到进程的虚拟地址空间,然后直接读写像素数据。
核心要点:帧缓冲的本质是“显存”的抽象层。它将物理显存或系统内存中的显示区域暴露给用户空间,使得开发者可以像操作普通内存一样操作屏幕像素。
1.2 帧缓冲的核心数据结构
Linux 帧缓冲驱动通过 struct fb_info 结构体来描述一个帧缓冲设备,其关键成员如下:
| 成员 | 类型 | 说明 |
|---|---|---|
var |
struct fb_var_screeninfo |
可变屏幕参数:分辨率、位深、像素格式、虚拟分辨率、偏移量等 |
fix |
struct fb_fix_screeninfo |
固定屏幕参数:物理地址、内存长度、行字节数、类型等 |
fbops |
struct fb_ops * |
帧缓冲操作函数集:fb_open、fb_release、fb_read、fb_write、fb_ioctl、fb_mmap、fb_fillrect、fb_copyarea、fb_imageblit 等 |
screen_base |
char * |
帧缓冲在虚拟地址空间中的基地址 |
screen_size |
unsigned long |
帧缓冲内存总大小(字节) |
pseudo_palette |
u32 * |
伪调色板,用于 8/16 位色深模式下的颜色查找 |
1.3 帧缓冲在 Linux 显示子系统中的位置
Linux 显示子系统采用分层架构,帧缓冲位于中间层,向上对接用户空间应用程序,向下屏蔽具体显示硬件差异。整体架构如下图所示:
从图中可以看出,帧缓冲层处于内核空间的核心位置,它通过标准系统调用接口与用户空间交互,并通过硬件抽象层与具体显示芯片通信。这种分层设计使得上层应用无需关心底层硬件差异。
1.4 帧缓冲与 DRM/KMS 的关系
Linux 内核中存在两套显示子系统框架:传统 fbdev 和 现代 DRM/KMS。它们之间的关系和差异如下:
| 对比维度 | fbdev (帧缓冲) | DRM/KMS |
|---|---|---|
| 引入时间 | Linux 2.2 时代(1999年) | Linux 3.x 时代(2012年) |
| 设计哲学 | 简单、直接、单缓冲为主 | 复杂、灵活、多图层、原子操作 |
| 多显示器支持 | 弱(每个 fb 设备独立管理) | 强(统一的 CRTC/Encoder/Connector 模型) |
| 硬件加速 | 仅提供基本的填充/拷贝/位块传输 | 支持 GPU 合成、缩放、旋转、混合 |
| 垂直同步(VBlank) | 通过 FBIO_WAITFORVSYNC ioctl |
通过 DRM 事件机制,更精确 |
| 当前状态 | 维护模式,新硬件不再优先支持 | 主流方案,新硬件首选 |
| 兼容性 | DRM 驱动可通过 drm_fb_helper 模拟 fbdev |
fbdev 无法模拟 DRM 功能 |
关键理解:DRM/KMS 是 fbdev 的演进替代方案。在嵌入式 Linux 中,fbdev 仍然广泛存在于老旧内核(Linux 4.x 以下)和资源受限设备中。现代嵌入式平台(如 i.MX8、RK3588)虽然主推 DRM,但通常通过
drm_fb_helper 模块提供 /dev/fb0 兼容节点,以保证旧版应用程序的兼容性。
1.5 fbdev 与 DRM/KMS 的共存模式
在实际嵌入式系统中,fbdev 和 DRM/KMS 并非完全互斥。现代内核通过 drm_fb_helper 实现了两者的桥接,其架构关系如下图所示:
1.6 帧缓冲的工作流程
一个典型的帧缓冲应用程序工作流程如下:
- 打开设备:
fd = open("/dev/fb0", O_RDWR); - 获取固定信息:
ioctl(fd, FBIOGET_FSCREENINFO, &fix);— 获取物理地址、行长、内存大小 - 获取可变信息:
ioctl(fd, FBIOGET_VSCREENINFO, &var);— 获取分辨率、位深、像素格式 - 设置可变信息(可选):
ioctl(fd, FBIOPUT_VSCREENINFO, &var);— 修改分辨率或像素格式 - 内存映射:
fbp = mmap(NULL, fix.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - 绘制像素:直接向
fbp指向的内存写入像素数据 - 释放资源:
munmap(fbp, fix.smem_len); close(fd);
注意事项:帧缓冲操作不提供垂直同步保护,直接写入可能导致屏幕撕裂(tearing)。如果需要平滑动画,建议使用双缓冲技术:在内存中维护一个后备缓冲区,在垂直消隐期间通过
FBIO_WAITFORVSYNC 同步切换显示缓冲区。
1.7 帧缓冲的像素格式
帧缓冲支持多种像素格式,通过 fb_var_screeninfo 中的位域偏移和长度来描述:
| 颜色深度 | 像素格式 | 典型布局 | 每像素字节 |
|---|---|---|---|
| 8 bpp | 伪彩色 (Pseudo Color) | 索引值 → 调色板查找 | 1 |
| 16 bpp | RGB 565 | R[15:11] G[10:5] B[4:0] | 2 |
| 16 bpp | ARGB 1555 | A[15] R[14:10] G[9:5] B[4:0] | 2 |
| 24 bpp | RGB 888 | R[23:16] G[15:8] B[7:0] | 3 |
| 32 bpp | ARGB 8888 | A[31:24] R[23:16] G[15:8] B[7:0] | 4 |
在嵌入式设备中,RGB 565 是最常用的格式,因为它平衡了色彩表现力和内存占用。对于需要透明效果的 UI 场景,ARGB 8888 是首选。
1.8 本章小结
- 帧缓冲 是 Linux 显示子系统的基础抽象层,将显存映射为用户空间可操作的内存区域。
- fbdev 是传统的帧缓冲框架,结构简单但功能有限,适合资源受限的嵌入式设备。
- DRM/KMS 是现代显示框架,功能强大但复杂度高,通过
drm_fb_helper兼容 fbdev 接口。 - 理解帧缓冲的 数据结构、工作流程 和 像素格式,是后续实现屏幕旋转功能的基础。