4. 帧缓冲关键数据结构:struct fb_info、struct fb_var_screeninfo、struct fb_fix_screeninfo 详解
在 Linux 帧缓冲驱动架构中,用户空间通过 ioctl 系统调用与内核驱动交互,而内核驱动则通过三个核心数据结构来管理和描述显示硬件。理解 struct fb_info、struct fb_var_screeninfo 和 struct fb_fix_screeninfo 是掌握帧缓冲调试与参数调优的基础。
4.1 数据结构层级关系
这三个结构体在驱动中扮演不同角色:struct fb_info 是帧缓冲设备的顶层抽象,包含设备状态、操作函数指针和两个描述屏幕参数的结构体成员。下图展示了它们之间的组织关系。
4.2 struct fb_info:帧缓冲设备核心
struct fb_info 是帧缓冲驱动的“大脑”,每个注册的帧缓冲设备对应一个 fb_info 实例。它包含设备的所有状态信息、操作函数表以及指向显存和寄存器的指针。
| 字段 | 类型 | 说明 |
|---|---|---|
| var | struct fb_var_screeninfo |
可变屏幕参数,用户空间可通过 FBIOPUT_VSCREENINFO 修改 |
| fix | struct fb_fix_screeninfo |
固定屏幕参数,由硬件特性决定,通常只读 |
| fbops | struct fb_ops * |
帧缓冲操作函数表,包含 fb_open、fb_release、fb_ioctl 等 |
| screen_base | void __iomem * |
显存在内核空间的虚拟地址映射 |
| screen_size | unsigned long |
显存总大小(字节) |
| pseudo_palette | void * |
伪调色板,用于 8/16 位色深模式下的颜色查找 |
| device | struct device * |
关联的 Linux 设备模型节点 |
| state | int |
设备状态标志,如 FBINFO_STATE_RUNNING |
调试提示: 使用
fbset -i 或直接读取 /sys/class/graphics/fb0/ 下的 sysfs 属性,可以获取当前 fb_info 中的关键信息。例如 cat /sys/class/graphics/fb0/virtual_size 可查看虚拟分辨率。
4.3 struct fb_var_screeninfo:可变屏幕参数
该结构体描述用户可调整的显示参数,包括分辨率、色深、时序等。通过 FBIOPUT_VSCREENINFO ioctl 修改后,驱动会重新配置硬件。这也是 fbset 工具主要操作的对象。
| 字段 | 类型 | 说明 | 典型值示例 |
|---|---|---|---|
| xres | __u32 |
可见水平分辨率(像素) | 1024 |
| yres | __u32 |
可见垂直分辨率(像素) | 768 |
| xres_virtual | __u32 |
虚拟水平分辨率(支持双缓冲) | 2048 |
| yres_virtual | __u32 |
虚拟垂直分辨率 | 768 |
| xoffset | __u32 |
虚拟到可见区域的水平偏移 | 0 |
| yoffset | __u32 |
虚拟到可见区域的垂直偏移 | 0 |
| bits_per_pixel | __u32 |
每像素位数(色深) | 32 |
| grayscale | __u32 |
灰度标志(非零表示灰度模式) | 0 |
| red / green / blue / transp | struct fb_bitfield |
各颜色分量的位偏移和长度 | 见下方说明 |
| pixclock | __u32 |
像素时钟(皮秒) | 15384 |
| left_margin / right_margin | __u32 |
水平消隐前肩/后肩(像素) | 160 / 24 |
| upper_margin / lower_margin | __u32 |
垂直消隐前肩/后肩(行) | 23 / 3 |
| hsync_len / vsync_len | __u32 |
水平/垂直同步脉冲宽度 | 136 / 6 |
| sync | __u32 |
同步标志(如 FB_SYNC_HOR_HIGH_ACT) |
0 |
| vmode | __u32 |
视频模式(隔行/逐行等) | FB_VMODE_NONINTERLACED |
颜色位域结构:
struct fb_bitfield 包含 offset(起始位)、length(位数)和 msb_right(MSB 对齐标志)。对于 32 位 ARGB 模式,典型值为:red.offset=16, red.length=8; green.offset=8, green.length=8; blue.offset=0, blue.length=8; transp.offset=24, transp.length=8。
4.4 struct fb_fix_screeninfo:固定屏幕参数
该结构体描述由硬件决定的固定属性,用户空间通常只能读取,不能修改。它包含显存物理地址、行长度、显示类型等信息。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | char[16] |
驱动名称标识符,如 s3c-fb、mxcfb |
| smem_start | unsigned long |
显存物理起始地址 |
| smem_len | __u32 |
显存总长度(字节) |
| type | __u32 |
显示类型,如 FB_TYPE_PACKED_PIXELS |
| type_aux | __u32 |
类型辅助信息(通常为 0) |
| visual | __u32 |
视觉模式,如 FB_VISUAL_TRUECOLOR、FB_VISUAL_PSEUDOCOLOR |
| xpanstep / ypanstep | __u16 |
硬件支持的平移步长(像素/行),0 表示不支持 |
| ywrapstep | __u16 |
硬件支持的卷绕步长(0 表示不支持) |
| line_length | __u32 |
每行显存字节数(行跨度) |
| mmio_start | unsigned long |
MMIO 寄存器物理起始地址 |
| mmio_len | __u32 |
MMIO 寄存器区域长度 |
| accel | __u32 |
硬件加速类型标志 |
| capabilities | __u16 |
硬件能力标志(如 FB_CAP_FOURCC) |
调试陷阱:
smem_start 在大多数现代内核中已不再直接暴露给用户空间(出于安全考虑),用户空间通过 mmap 映射显存时使用的是文件偏移而非物理地址。调试时请通过 /sys/class/graphics/fb0/ 下的 sysfs 属性获取信息。
4.5 数据结构与用户空间交互流程
用户空间程序(如 fbset)通过 ioctl 系统调用与内核驱动交互,读取或修改上述数据结构。下图展示了典型的交互流程。
4.6 使用 fbset 查看数据结构实例
通过 fbset 命令可以直观地查看当前帧缓冲设备的 var 和 fix 参数。以下是一个实际输出示例:
# fbset -i
mode "1024x768-60"
# D: 65.003 MHz, H: 48.365 kHz, V: 60.006 Hz
geometry 1024 768 1024 768 32
timings 15384 160 24 23 3 136 6
accel true
rgba 8/16,8/8,8/0,8/24
endmode
Frame buffer device information:
Name : s3c-fb
Address : 0xfb200000
Size : 3145728
Type : PACKED PIXELS
Visual : TRUECOLOR
XPanStep : 1
YPanStep : 1
YWrapStep : 0
LineLength : 4096
Accelerator : 0
参数对应关系: 上述输出中
geometry 1024 768 1024 768 32 对应 var.xres、var.yres、var.xres_virtual、var.yres_virtual、var.bits_per_pixel。LineLength: 4096 对应 fix.line_length,计算公式为 line_length = xres_virtual * (bits_per_pixel / 8),即 1024 * 4 = 4096。
4.7 数据结构在调试中的关键作用
在帧缓冲调试过程中,这三个数据结构是定位问题的核心入口:
- 显示异常排查: 检查
var.xres和var.yres是否与显示器 EDID 信息匹配;检查var.pixclock和时序参数是否在显示器支持范围内。 - 内存访问问题: 检查
fix.smem_len是否足够容纳帧缓冲区(xres * yres * (bits_per_pixel / 8));检查fix.line_length是否与预期一致。 - 颜色显示异常: 检查
var.bits_per_pixel和var.red/green/blue/transp位域设置是否正确;检查fix.visual是否为FB_VISUAL_TRUECOLOR。 - 双缓冲调试: 检查
var.xres_virtual和var.yres_virtual是否大于可见分辨率;检查var.xoffset和var.yoffset的切换是否生效。 - 硬件加速问题: 检查
fix.accel字段是否指示硬件加速类型;检查fb_info.fbops中的加速函数是否被正确调用。
实战技巧: 在调试过程中,建议先通过
fbset -i 获取当前参数快照,然后使用 fbset -xres 1280 -yres 720 -depth 32 修改参数,再通过 fbset -i 确认修改是否生效。如果修改后显示异常,立即检查 var.pixclock 和时序参数是否合理。