帧缓冲设备

上次修订时间: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:垂直同步的长度

  1. 像素时钟

    xfree:单位为 MHz

    fb:单位为皮秒 (ps)

    pixclock = 1000000 / DCF

  2. 水平时序

    left_margin = HFL - SH2

    right_margin = SH1 - HR

    hsync_len = SH2 - SH1

  3. 垂直时序

    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 提供。