1. Framebuffer 基础概念
1.1 什么是 Framebuffer
Framebuffer(帧缓冲)是 Linux 内核提供的一种显示输出抽象层,它将显存映射到用户空间,使应用程序可以直接向屏幕写入像素数据。从概念上讲,Framebuffer 是一块连续的物理内存区域,每个内存单元对应屏幕上的一个像素点。
核心定义:Framebuffer 是内核中用于存储屏幕图像数据的缓冲区,通过
/dev/fb0 设备文件暴露给用户态程序,实现“写内存即画图”的显示模式。
Framebuffer 的关键特性包括:
- 内存映射:通过
mmap()系统调用将内核缓冲区映射到用户进程的虚拟地址空间。 - 像素格式:支持 RGB565、RGB888、ARGB8888 等多种颜色编码格式。
- 固定参数:分辨率、位深、行跨度等参数通过
struct fb_fix_screeninfo获取。 - 可变参数:颜色格式、显示时序等可通过
struct fb_var_screeninfo调整。
| 结构体 | 作用 | 关键字段 |
|---|---|---|
fb_fix_screeninfo |
固定硬件参数 | smem_start(物理地址)、smem_len(缓冲区大小)、line_length(行字节数) |
fb_var_screeninfo |
可变显示参数 | xres/yres(分辨率)、bits_per_pixel(位深)、red/green/blue(颜色通道偏移) |
fb_cmap |
颜色查找表(伪彩色模式) | red/green/blue(16位颜色值数组)、start/len(索引范围) |
实战提示:在嵌入式设备中,Framebuffer 的物理内存通常位于连续 DMA 区域,
smem_start 字段可用于硬件图层叠加时的物理地址传递。
1.2 Framebuffer 在 Linux 图形栈中的位置
Linux 图形系统从底层到上层分为多个层次,Framebuffer 位于内核空间与用户空间的交界处,是直接操作显示硬件的底层接口。
从图中可以看出,Framebuffer 处于内核空间的核心位置:
- 向下:屏蔽不同显示控制器的硬件差异,提供统一的
fb_ops操作接口。 - 向上:通过
/dev/fb0字符设备和ioctl系统调用,为应用程序提供标准化的显示服务。
注意:在现代 Linux 系统中,DRM(Direct Rendering Manager)逐渐取代传统 fbdev 成为主流显示框架。但在嵌入式领域,Framebuffer 因其简单、轻量、无依赖的特点,仍然是裸机显示和快速原型开发的首选方案。
1.3 Framebuffer 设备文件 (/dev/fb0)
/dev/fb0 是系统默认的 Framebuffer 设备节点,属于字符设备,主设备号为 29,次设备号从 0 开始递增。系统中有多个显示设备时,依次注册为 /dev/fb0、/dev/fb1 等。
设备文件操作流程
- 打开设备:
int fd = open("/dev/fb0", O_RDWR); - 获取固定信息:
ioctl(fd, FBIOGET_FSCREENINFO, &fix); - 获取可变信息:
ioctl(fd, FBIOGET_VSCREENINFO, &var); - 内存映射:
void *fbp = mmap(NULL, fix.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - 像素操作:直接通过
fbp指针读写像素数据。 - 释放资源:
munmap(fbp, fix.smem_len); close(fd);
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/fb.h>
int main() {
int fd = open("/dev/fb0", O_RDWR);
if (fd < 0) {
perror("open fb0 failed");
return -1;
}
struct fb_fix_screeninfo fix;
struct fb_var_screeninfo var;
// 获取固定参数
ioctl(fd, FBIOGET_FSCREENINFO, &fix);
// 获取可变参数
ioctl(fd, FBIOGET_VSCREENINFO, &var);
printf("分辨率: %d x %d\n", var.xres, var.yres);
printf("位深: %d bpp\n", var.bits_per_pixel);
printf("缓冲区大小: %d bytes\n", fix.smem_len);
printf("行跨度: %d bytes\n", fix.line_length);
// 映射显存到用户空间
size_t screensize = fix.smem_len;
char *fbp = (char *)mmap(NULL, screensize,
PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (fbp == MAP_FAILED) {
perror("mmap failed");
close(fd);
return -1;
}
// 将屏幕上半部分填充为红色 (RGB565: 0xF800)
for (int y = 0; y < var.yres / 2; y++) {
for (int x = 0; x < var.xres; x++) {
unsigned short *pixel = (unsigned short *)(fbp + y * fix.line_length + x * 2);
*pixel = 0xF800; // 红色
}
}
munmap(fbp, screensize);
close(fd);
return 0;
}
关键点:
fix.line_length 可能大于 var.xres * (var.bits_per_pixel / 8),因为硬件可能要求行对齐到特定字节边界。遍历像素时必须使用 line_length 作为行步长。
常用 ioctl 命令
| 命令 | 功能 | 参数类型 |
|---|---|---|
FBIOGET_FSCREENINFO |
获取固定屏幕信息 | struct fb_fix_screeninfo * |
FBIOGET_VSCREENINFO |
获取可变屏幕信息 | struct fb_var_screeninfo * |
FBIOPUT_VSCREENINFO |
设置可变屏幕信息 | struct fb_var_screeninfo * |
FBIOGETCMAP |
获取颜色查找表 | struct fb_cmap * |
FBIOPUTCMAP |
设置颜色查找表 | struct fb_cmap * |
FBIOBLANK |
控制屏幕开关 | int(0=开启,1=关闭) |
像素格式与内存布局
Framebuffer 支持多种像素格式,常见的有:
- RGB565(16位):R占5位,G占6位,B占5位,每个像素2字节。
- RGB888(32位):R/G/B各占8位,A占8位(或忽略),每个像素4字节。
- CLUT8(8位):每个像素1字节,作为颜色查找表索引,支持256种颜色。
内存计算公式:
- 每像素字节数 =
bits_per_pixel / 8 - 每行字节数 =
line_length(由硬件决定,可能大于xres × 每像素字节数) - 像素 (x, y) 的偏移地址 =
y × line_length + x × (bits_per_pixel / 8)
1.4 本章小结
Framebuffer 是嵌入式 Linux 显示系统的基础设施,通过 /dev/fb0 设备文件和 mmap 内存映射机制,为应用程序提供了直接操作屏幕像素的能力。理解 Framebuffer 的层次位置、设备操作流程和内存布局,是后续实现图层合成与光标叠加的基石。