1. Framebuffer 基础概念
Framebuffer(帧缓冲)是 Linux 内核为显示子系统提供的一种抽象接口,它将显存抽象为一个可直接通过文件 I/O 和内存映射(mmap)访问的字符设备。应用程序无需关心底层 GPU 或显示控制器的具体实现,只需向 Framebuffer 设备写入像素数据,即可在屏幕上呈现图像。
核心理解:Framebuffer 本质上是一块内存区域,每个像素点对应内存中的若干字节。修改这些字节就是修改屏幕上的显示内容。
1.1 Framebuffer 设备文件
在 Linux 系统中,Framebuffer 设备以字符设备文件的形式暴露给用户空间,通常位于 /dev/fbX 命名空间下:
| 设备文件 | 主设备号 | 次设备号 | 典型用途 |
|---|---|---|---|
/dev/fb0 |
29 | 0 | 主显示器(LCD / HDMI) |
/dev/fb1 |
29 | 1 | 第二显示器 / 扩展屏 |
/dev/fb2 |
29 | 2 | 第三显示器 / 叠加层 |
每个 /dev/fbX 设备对应一个独立的显示缓冲区。系统通过 ioctl 系统调用查询和设置设备参数,包括分辨率、像素格式、行跨度等。
关键操作:使用
open("/dev/fb0", O_RDWR) 打开设备,通过 ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) 获取可变屏幕信息,通过 ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) 设置屏幕参数。
1.2 显示缓冲区 (Display Buffer)
显示缓冲区是 Framebuffer 设备在内存中映射的一块连续区域,其大小由屏幕分辨率与像素格式共同决定。缓冲区中的每个字节都对应屏幕上的一个像素点或像素分量。
缓冲区大小的计算公式:
buffer_size = 屏幕宽度 × 屏幕高度 × (颜色深度 / 8)
例如:1024 × 768 × 32bpp → 1024 × 768 × 4 = 3,145,728 字节 ≈ 3 MB
注意:实际缓冲区大小可能大于理论值,因为行跨度(stride)可能因硬件对齐要求而大于屏幕宽度。始终通过
FBIOGET_FSCREENINFO 获取 smem_len 字段来确认实际缓冲区大小。
1.3 像素格式与颜色深度
像素格式决定了每个像素在缓冲区中的编码方式。颜色深度(bits per pixel, bpp)表示每个像素占用的比特数。常见的像素格式包括:
| 颜色深度 | 像素格式 | 每个像素字节数 | 颜色通道 | 典型应用 |
|---|---|---|---|---|
| 8 bpp | 伪彩色 (索引色) | 1 | 调色板索引 | 低端嵌入式 / 字符界面 |
| 16 bpp | RGB565 | 2 | R:5 G:6 B:5 | 低成本 LCD / 无 GPU 设备 |
| 24 bpp | RGB888 | 3 | R:8 G:8 B:8 | 标准桌面 / 高清显示 |
| 32 bpp | ARGB8888 / XRGB8888 | 4 | A:8 R:8 G:8 B:8 | 现代嵌入式 / 带透明叠加 |
RGB565 格式详解:每个像素占用 2 字节。高 5 位为红色,中间 6 位为绿色,低 5 位为蓝色。内存布局为小端序:低字节包含 G 的低 3 位和 B 的 5 位,高字节包含 R 的 5 位和 G 的高 3 位。
1.4 获取像素格式信息
应用程序通过 ioctl 获取 struct fb_var_screeninfo 结构体,其中包含完整的像素格式描述:
struct fb_var_screeninfo {
__u32 xres; // 可见分辨率宽度
__u32 yres; // 可见分辨率高度
__u32 bits_per_pixel; // 颜色深度 (8/16/24/32)
__u32 xres_virtual; // 虚拟分辨率宽度
__u32 yres_virtual; // 虚拟分辨率高度
__u32 xoffset; // 虚拟到可见的偏移
__u32 yoffset;
struct fb_bitfield red; // 红色通道: offset, length
struct fb_bitfield green; // 绿色通道: offset, length
struct fb_bitfield blue; // 蓝色通道: offset, length
struct fb_bitfield transp;// 透明度通道: offset, length
__u32 nonstd; // 非标准格式标志
__u32 activate;
__u32 height; // 物理高度 (mm)
__u32 width; // 物理宽度 (mm)
__u32 accel_flags;
__u32 pixclock; // 像素时钟 (皮秒)
__u32 left_margin;
__u32 right_margin;
__u32 upper_margin;
__u32 lower_margin;
__u32 hsync_len;
__u32 vsync_len;
__u32 sync;
__u32 vmode;
__u32 rotate;
__u32 colorspace;
__u32 reserved[4];
};
实用技巧:使用
fbset 命令可以快速查看当前 Framebuffer 的像素格式和分辨率:fbset -i /dev/fb0。输出中会显示 geometry(分辨率与深度)和 rgba(通道位宽与偏移)。
1.5 多屏同显的硬件基础
多屏同显(克隆模式 / Mirror Mode)要求多个显示控制器共享同一份显示缓冲区数据。在硬件层面,这可以通过以下方式实现:
- 共享缓冲区指针:多个 Framebuffer 设备指向同一块物理内存地址,写入一个设备的数据同时出现在所有屏幕上。
- DMA 引擎复制:主屏的显示缓冲区通过 DMA 定期复制到从屏缓冲区,适用于硬件不支持共享的场景。
- 显示控制器叠加:部分 SoC 支持将同一个图层(Layer)输出到多个显示接口,实现零拷贝同显。