FrameBuffer 是 Linux 系统中的一种显示驱动接口。FrameBuffer 将显示硬件进行抽象,对用户表现为一块显示内存,用户空间进程可以直接操作这块内存空间完成写屏操作。FrameBuffer 在设备上表现为一个字符设备,设备节点为 /dev/fb*。用户对设备节点进程 open、mmap、ioctl、read、write 等操作,就可以控制最终的显示输出。

fb.png

FrameBuffer 使用的简单流程

FrameBuffer 在结构上是一个相对简单的驱动,操作流程也比较简单,一般的流程为:

  1. 使用 open() 打开 fb 设备节点。
  2. 通过 ioctl() 设置和获取显示区域的显示属性(FBIOPUT_VSCREENINFO / FBIOGET_VSCREENINFO)。
  3. 通过 ioctl() 获取硬件上显示缓存区的参数(FBIOGET_FSCREENINFO)。
  4. 使用 mmap() 结合上面获取的信息映射显示缓冲区。
  5. 在映射的缓冲区上写入图像数据,就可以获得对应的显示输出。
  6. 完成显示后,调用 close() 关闭 fb 设备。

FrameBuffer 中的数据结构

FrameBuffer 驱动的实现与硬件关系非常大,很难有一个统一的开发流程,所以实现细节也不介绍了。在软件实现上,很多都是围绕驱动中的几个数据结构来实现的。

fb_struct.png

  • fb_info:记录了 FrameBuffer 驱动中全部重要信息,包括驱动状态、设备属性、操作方法等等,并且关联到其他结构体。一个 FrameBuffer 对应一个 fb_info 。
  • fb_ops:FrameBuffer 中的操作函数。
  • fb_cmap:记录 FrameBuffer 驱动中的调色板信息,通过 FBIOGETCMAP 和 FBIOPUTCMAP 进行操作。我在实际使用中并没有用到这个结构体,我对它的理解是用户与驱动对颜色的一种约定,通过这个调色板,用户和驱动可以统一某些颜色。
  • fb_var_screeninfo:存储了用户可以修改的显示属性,例如屏幕分辨率、像素比特数、透明度、像素时钟时序等。通过 FBIOPUT_VSCREENINFO 和 FBIOGET_VSCREENINFO 进行操作。
  • fb_fix_screeninfo:存储了硬件固有的显示属性,如缓冲区的物理地址、缓冲区的长度、显示色彩模式、内存映射的开始位置等。这个结构体在驱动程序初始化时就已经确定,不能由用户修改。通过FBIOGET_FSCREENINFO 进行操作。

其他

FrameBuffer 驱动结构上比较简单,但这并不意味着开发会很简单,开发复杂度与硬件复杂度有很大关系。如果仅仅是一个显示控制,那么实现对应的驱动接口可能就差不多了。但是如果显示单元中包含显示后处理,画质调节等其他硬件单元时,显示驱动就可能变得比较复杂,并且调试难度也增加很多。

FrameBuffer 这种简单的结构也带来了很大的灵活性,许多复杂的处理可以交给上层应用或更底层的硬件来做。例如多个图层渲染,可以由应用使用软件或 GPU 先进行合成,再交给 FrameBuffer 显示。如果硬件支持多个显示层,也可以将每个图层送给 FrameBuffer,然后由硬件进行合成。

另一个常见的问题就是显示流畅性。当使用单缓冲时,很难确保显示画面没有撕裂。单缓冲的流畅显示需要保证软件送显与硬件显示保持相同的帧率,并且显示缓冲的准备时间要尽量短,必须小于帧周期。使用双缓冲时,要求就小很多,更容易保证显示流畅。双缓冲使用乒乓结构,当一个缓冲用于硬件显示时,另一个缓冲用来软件写入。双缓冲可以在应用层或驱动层实现,驱动实现时通过 FBIOPAN_DISPLAY 来交换缓冲。为了确保流畅性,现在有使用三缓冲或更多缓冲来实现,缓冲越多越有利于流畅性,但消耗的内存会更多。设计架构时需要根据实际情况来选择缓冲数。


戈壁老王
143 声望61 粉丝

做为一个不称职的老年码农,一直疏忽整理笔记,开博记录一下,用来丰富老年生活,


引用和评论

0 条评论