2. Framebuffer 核心数据结构

在 Linux Framebuffer 驱动模型中,用户空间通过 ioctl 系统调用与内核交换显示参数。三个核心数据结构构成了整个帧缓冲的配置骨架:可变信息、固定信息 和 颜色映射表。理解它们的字段含义与协作关系,是正确实现 mmap 映射和颜色空间转换的前提。

关键认知: fb_var_screeninfo 描述“当前可变的显示模式”(分辨率、位深、时序),fb_fix_screeninfo 描述“硬件固定的内存布局”(起始地址、步长、I/O 地址),fb_cmap 描述“调色板映射”(仅对索引色模式有效)。三者通过 FBIOGET_VSCREENINFO / FBIOGET_FSCREENINFO / FBIOGETCMAP 获取。
Framebuffer 三大数据结构关系图 Framebuffer 三大数据结构协作关系 fb_var_screeninfo 可变信息 分辨率 · 位深 · 时序 fb_fix_screeninfo 固定信息 物理地址 · 步长 · 类型 fb_cmap 颜色映射表 红/绿/蓝/透明度索引 用户空间获取流程 open("/dev/fb0") → ioctl(FBIOGET_VSCREENINFO) → ioctl(FBIOGET_FSCREENINFO) → ioctl(FBIOGETCMAP) mmap 映射时依赖 fix.smem_start + fix.line_length 计算偏移

2.1 struct fb_var_screeninfo — 可变显示参数

该结构体定义在 linux/fb.h 中,存储用户空间可动态修改的显示模式参数。每次切换分辨率或位深时,驱动通过 FBIO_SET_VSCREENINFO 更新此结构。

fb_var_screeninfo 核心字段
字段类型说明典型值
xres__u32可见区域水平像素1024
yres__u32可见区域垂直像素768
xres_virtual__u32虚拟缓冲区水平像素(可大于 xres)2048
yres_virtual__u32虚拟缓冲区垂直像素(支持双缓冲)1536
bits_per_pixel__u32每个像素的位数(bpp)32
red/green/blue/transpstruct fb_bitfield各颜色分量的位偏移与长度R:16/8, G:8/8, B:0/8
pixclock__u32像素时钟(皮秒)10000
left_margin/right_margin__u32行同步前后肩48/16
upper_margin/lower_margin__u32帧同步前后肩33/10
hsync_len/vsync_len__u32同步脉冲宽度96/2
vmode__u32显示模式(非隔行/隔行/双扫描)FB_VMODE_NONINTERLACED
调优关注点: 颜色空间转换时,bits_per_pixel 和 red/green/blue 的位域布局决定了像素格式。例如 32bpp 下常见 RGBA8888(R 偏移 16、G 偏移 8、B 偏移 0)或 BGRA8888。转换前必须读取这些字段,否则会产生颜色错乱。

2.2 struct fb_fix_screeninfo — 固定硬件信息

该结构体描述帧缓冲的物理内存布局,在驱动初始化时确定,用户空间通常只能读取不能修改。

fb_fix_screeninfo 核心字段
字段类型说明mmap 映射中的角色
smem_startunsigned long帧缓冲物理起始地址作为 mmap 的偏移参数(需页对齐)
smem_len__u32帧缓冲总长度(字节)mmap 映射长度不能超过此值
type__u32帧缓冲类型(包/平面/其他)FB_TYPE_PACKED_PIXELS 最常用
visual__u32颜色模式(真彩/伪彩/直接色)决定是否使用 fb_cmap
line_length__u16一行像素的字节数(步长)计算像素偏移:offset = y * line_length + x * (bpp/8)
mmio_startunsigned longMMIO 物理起始地址用于硬件寄存器映射(非像素数据)
mmio_len__u32MMIO 区域长度—
常见陷阱: smem_start 是物理地址,用户空间不能直接访问。mmap 时使用 MAP_SHARED 标志,并将 smem_start 作为 offset 参数传入。但某些嵌入式平台(如 ARM)的帧缓冲物理地址可能不在页边界上,需要先 mmap 到页对齐的地址再计算偏移。
fb_fix_screeninfo 指导 mmap 映射 fb_fix_screeninfo 指导 mmap 映射 物理帧缓冲内存 (smem_start ~ smem_start + smem_len) line_length 字节 line_length 字节 line_length 字节 … 像素 (x, y) 的偏移 = y × line_length + x × (bits_per_pixel / 8)

2.3 struct fb_cmap — 颜色映射表(调色板)

当 fb_fix_screeninfo.visual 为 FB_VISUAL_PSEUDOCOLOR 或 FB_VISUAL_DIRECTCOLOR 时,像素值不直接表示 RGB,而是作为索引查表。此时 fb_cmap 定义了索引到实际颜色的映射关系。

fb_cmap 字段说明
字段类型说明
start__u32起始索引号(通常为 0)
len__u32映射表长度(颜色数)
red__u16 *红色分量数组(每个值 0~65535)
green__u16 *绿色分量数组
blue__u16 *蓝色分量数组
transp__u16 *透明度分量数组(可为 NULL)
颜色空间转换场景: 在 8bpp 伪彩模式下,像素值 0x3F 对应索引 63,实际颜色为 red[63]、green[63]、blue[63]。若要将伪彩转换为 32bpp 真彩,必须通过 FBIOGETCMAP 读取整个调色板,然后逐像素查表替换。调优时注意 len 通常为 256(8bpp)或 16(4bpp)。
fb_cmap 索引查表流程 伪彩模式:像素索引 → 调色板查表 → RGB 输出 像素值 0x3F (63) fb_cmap 调色板 red[63]=0x8A green[63]=0x3F, blue[63]=0xC2 RGB 像素 0x8A3FC2 转换时需遍历所有像素,用像素值作为索引从 red/green/blue 数组中取出分量,组合成真彩色

2.4 三个结构体的协作流程

在实际的 Framebuffer 编程中,三个结构体按以下顺序协同工作:

  1. 打开设备: int fd = open("/dev/fb0", O_RDWR);
  2. 获取可变信息: ioctl(fd, FBIOGET_VSCREENINFO, &var); — 得到分辨率、位深、颜色位域。
  3. 获取固定信息: ioctl(fd, FBIOGET_FSCREENINFO, &fix); — 得到物理地址、步长、内存长度。
  4. 获取颜色映射(仅伪彩/直接色): ioctl(fd, FBIOGETCMAP, &cmap); — 读取调色板。
  5. mmap 映射: mmap(NULL, fix.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  6. 像素操作: 根据 var.bits_per_pixel 和 fix.line_length 计算偏移,直接读写映射内存。
性能提示: 颜色空间转换时,var 中的 red.offset、green.offset、blue.offset 决定了像素格式的字节序。例如在 ARM 小端平台上,32bpp 的 RGBA8888 实际内存布局为 B、G、R、A。转换前务必打印这些位域值,避免“红蓝颠倒”。

2.5 数据结构对比总结

三种数据结构对比
特性fb_var_screeninfofb_fix_screeninfofb_cmap
可变性可读可写(用户可修改)只读(驱动初始化固定)可读可写(通过 FBIO_SETCMAP)
主要用途描述当前显示模式描述内存布局描述索引色映射
mmap 相关间接(决定像素格式)直接(提供地址和步长)无关(仅查表用)
颜色空间转换提供位域布局提供行对齐信息提供索引→RGB 映射
获取 ioctlFBIOGET_VSCREENINFOFBIOGET_FSCREENINFOFBIOGETCMAP