帧缓冲设备¶
上次修订时间:2001 年 5 月 10 日
0. 介绍¶
帧缓冲设备为图形硬件提供了一个抽象。它代表了某些视频硬件的帧缓冲,并允许应用程序软件通过定义良好的接口访问图形硬件,因此软件不需要了解任何关于底层(硬件寄存器)的东西。
该设备通过特殊的设备节点访问,通常位于 /dev 目录中,例如 /dev/fb*。
1. /dev/fb* 的用户视角¶
从用户的角度来看,帧缓冲设备看起来就像 /dev 中的任何其他设备。它是一个主设备号为 29 的字符设备;次设备号指定帧缓冲编号。
按照惯例,使用以下设备节点(数字表示设备次设备号)
0 = /dev/fb0 First frame buffer
1 = /dev/fb1 Second frame buffer
...
31 = /dev/fb31 32nd frame buffer
为了向后兼容,您可能需要创建以下符号链接
/dev/fb0current -> fb0
/dev/fb1current -> fb1
等等...
帧缓冲设备也是普通内存设备,这意味着您可以读取和写入它们的内容。 例如,您可以通过以下方式制作屏幕快照
cp /dev/fb0 myfile
也可以同时存在多个帧缓冲,例如,如果除了内置硬件之外,您还有一张显卡。 相应的帧缓冲设备(/dev/fb0 和 /dev/fb1 等)独立工作。
使用帧缓冲设备的应用程序软件(例如 X 服务器)默认将使用 /dev/fb0(较旧的软件使用 /dev/fb0current)。 您可以通过将环境变量 $FRAMEBUFFER 设置为帧缓冲设备的路径名来指定替代帧缓冲设备,例如(对于 sh/bash 用户)
export FRAMEBUFFER=/dev/fb1
或(对于 csh 用户)
setenv FRAMEBUFFER /dev/fb1
此后,X 服务器将使用第二个帧缓冲。
2. /dev/fb* 的程序员视角¶
如您所知,帧缓冲设备是像 /dev/mem 这样的内存设备,它具有相同的功能。 您可以读取它、写入它、寻址到其中的某个位置并对其进行 mmap()(主要用法)。 区别仅在于特殊文件中出现的内存不是整个内存,而是某些视频硬件的帧缓冲。
/dev/fb* 还允许对其进行多个 ioctl 操作,通过这些操作可以查询和设置有关硬件的许多信息。 颜色映射处理也通过 ioctl 进行。 查看 <linux/fb.h> 以获取有关存在的 ioctl 以及它们所作用的数据结构的更多信息。 这是一个简要概述
您可以请求有关硬件的不可更改的信息,例如名称、屏幕内存的组织方式(平面、压缩像素...)以及屏幕内存的地址和长度。
您可以请求和更改有关硬件的可变信息,例如可见和虚拟几何体、深度、颜色映射格式、时序等。 如果您尝试更改该信息,驱动程序可能会舍入一些值以满足硬件的功能(如果不可能,则返回 EINVAL)。
您可以获取和设置颜色映射的一部分。 通信使用每个颜色部分(红色、绿色、蓝色、透明度)16 位来完成,以支持所有现有硬件。 驱动程序会完成所有需要的计算,以将其应用于硬件(向下舍入到更少的位,可能会丢弃透明度)。
所有这些硬件抽象使得应用程序的实现更加容易和更具可移植性。 例如,X 服务器完全在 /dev/fb* 上运行,因此不需要知道例如具体硬件的颜色寄存器是如何组织的。 XF68_FBDev 是用于位图、非加速视频硬件的通用 X 服务器。 必须构建到应用程序中的唯一东西是屏幕组织(位平面或块状像素等),因为它直接在帧缓冲图像数据上运行。
将来计划将图形卡等帧缓冲驱动程序实现为运行时加载的内核模块。 这样的驱动程序只需调用 register_framebuffer()
并提供一些函数。 独立于内核编写和分发此类驱动程序将节省很多麻烦...
3. 帧缓冲分辨率维护¶
帧缓冲分辨率使用实用程序 fbset 维护。 它可以更改帧缓冲设备的视频模式属性。 它的主要用途是更改当前的视频模式,例如在您的 /etc/rc.* 或 /etc/init.d/* 文件之一中启动期间。
Fbset 使用存储在配置文件中的视频模式数据库,因此您可以轻松添加自己的模式并使用简单的标识符引用它们。
4. X 服务器¶
X 服务器 (XF68_FBDev) 是帧缓冲设备最著名的应用程序。 从 XFree86 release 3.2 开始,X 服务器是 XFree86 的一部分,并具有 2 种模式
如果 /etc/XF86Config 文件中 fbdev 驱动程序的 Display 小节包含
Modes "default"行,X 服务器将使用上述方案,即它将在 /dev/fb0(如果设置了 $FRAMEBUFFER)确定的分辨率下启动。 您仍然必须指定颜色深度(使用 Depth 关键字)和虚拟分辨率(使用 Virtual 关键字)。 这是 XFree86 提供的配置文件的默认设置。 它是最简单的配置,但有一些限制。
因此,也可以在 /etc/XF86Config 文件中指定分辨率。 这允许在保持相同虚拟桌面大小的同时进行动态分辨率切换。 使用的帧缓冲设备仍然是 /dev/fb0current(或 $FRAMEBUFFER),但可用分辨率现在由 /etc/XF86Config 定义。 缺点是您必须以不同的格式指定时序(但 fbset -x 可能会有所帮助)。
要调整视频模式,您可以使用 fbset 或 xvidtune。 请注意,xvidtune 与 XF68_FBDev 不能 100% 兼容:报告的时钟值始终不正确。
5. 视频模式时序¶
监视器通过使用电子束在屏幕上绘制图像(彩色型号使用 3 个电子束,单色监视器使用 1 个电子束)。 屏幕正面覆盖着彩色荧光粉(像素)的图案。 如果荧光粉被电子击中,它会发射光子,从而变得可见。
电子束从左到右,从屏幕顶部到底部绘制水平线(扫描线)。 通过修改电子束的强度,可以显示具有各种颜色和强度的像素。
在每条扫描线之后,电子束必须移回屏幕的左侧并移动到下一行:这称为水平回扫。 在绘制完整个屏幕(帧)后,光束移回左上角:这称为垂直回扫。 在水平和垂直回扫期间,电子束关闭(消隐)。
电子束绘制像素的速度由图形板中的点时钟决定。 对于例如 28.37516 MHz(每秒数百万个周期)的点时钟,每个像素的长度为 35242 ps(皮秒)
1/(28.37516E6 Hz) = 35.242E-9 s
如果屏幕分辨率为 640x480,则需要
640*35.242E-9 s = 22.555E-6 s
才能在一条扫描线上绘制 640 (xres) 个像素。 但水平回扫也需要时间(例如 272 像素),因此完整的扫描线需要
(640+272)*35.242E-9 s = 32.141E-6 s
我们会说水平扫描速率约为 31 kHz
1/(32.141E-6 s) = 31.113E3 Hz
完整的屏幕计算 480 (yres) 行,但我们也必须考虑垂直回扫(例如 49 行)。 因此,完整的屏幕将需要
(480+49)*32.141E-6 s = 17.002E-3 s
垂直扫描速率约为 59 Hz
1/(17.002E-3 s) = 58.815 Hz
这意味着屏幕数据每秒刷新约 59 次。 为了获得没有可见闪烁的稳定图像,VESA 建议垂直扫描速率至少为 72 Hz。 但感知到的闪烁非常依赖于人:有些人可以毫无问题地使用 50 Hz,而如果低于 80 Hz 我会注意到。
由于监视器不知道何时开始新的扫描线,因此图形板将为每条扫描线提供同步脉冲(水平同步或 hsync)。 同样,它为每个新帧提供同步脉冲(垂直同步或 vsync)。 图像在屏幕上的位置受到同步脉冲发生的时刻的影响。
下图总结了所有时序。 水平回扫时间是左边距、右边距和 hsync 长度的总和,而垂直回扫时间是上边距、下边距和 vsync 长度的总和
+----------+---------------------------------------------+----------+-------+
| | ↑ | | |
| | |upper_margin | | |
| | ↓ | | |
+----------###############################################----------+-------+
| # ↑ # | |
| # | # | |
| # | # | |
| # | # | |
| left # | # right | hsync |
| margin # | xres # margin | len |
|<-------->#<---------------+--------------------------->#<-------->|<----->|
| # | # | |
| # | # | |
| # | # | |
| # |yres # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # ↓ # | |
+----------###############################################----------+-------+
| | ↑ | | |
| | |lower_margin | | |
| | ↓ | | |
+----------+---------------------------------------------+----------+-------+
| | ↑ | | |
| | |vsync_len | | |
| | ↓ | | |
+----------+---------------------------------------------+----------+-------+
帧缓冲设备期望所有水平时序都以点时钟数(以皮秒为单位,1E-12 秒)表示,而垂直时序以扫描线数表示。
6. 将 XFree86 时序值转换为帧缓冲设备时序¶
XFree86 模式行由以下字段组成
"800x600" 50 800 856 976 1040 600 637 643 666
< name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
帧缓冲设备使用以下字段
pixclock:像素时钟,单位为 ps(皮秒)
left_margin:从同步到图片的间隔
right_margin:从图片到同步的间隔
upper_margin:从同步到图片的间隔
lower_margin:从图片到同步的间隔
hsync_len:水平同步的长度
vsync_len:垂直同步的长度
像素时钟
xfree:单位为 MHz
fb:单位为皮秒 (ps)
pixclock = 1000000 / DCF
水平时序
left_margin = HFL - SH2
right_margin = SH1 - HR
hsync_len = SH2 - SH1
垂直时序
upper_margin = VFL - SV2
lower_margin = SV1 - VR
vsync_len = SV2 - SV1
可以在 XFree86 源代码树的“xc/programs/Xserver/hw/xfree86/doc/modeDB.txt”下找到 VESA 时序的良好示例。
7. 参考¶
有关帧缓冲设备及其应用的更多具体信息,请访问 Linux-fbdev 网站
以及以下文档
fbset 的手册页:fbset(8), fb.modes(5)
XFree86 的手册页:XF68_FBDev(1), XF86Config(4/5)
强大的内核源代码
linux/drivers/video/
linux/include/linux/fb.h
linux/include/video/
8. 邮件列表¶
kernel.org 上有一个与帧缓冲设备相关的邮件列表:linux-fbdev@vger.kernel.org。
将您的 Web 浏览器指向 http://sourceforge.net/projects/linux-fbdev/ 以获取订阅信息和存档浏览。
9. 下载¶
所有必要的文件都可以在
及其镜像上找到。
fbset 的最新版本可以在
找到。
10. 鸣谢¶
本自述文件由 Geert Uytterhoeven 编写,部分基于 Roman Hodek 和 Martin Schaller 的原始 X-framebuffer.README。 第 6 节由 Frank Neumann 提供。