Linux下Framebuffer驱动简介

Version: V0.1

Time:09/06/2008

Author:Green-waste@163.com

最近接触了一些关于Linux下framebuffer方面的东西和LCD的framebuffer驱动,所以去了解了一些相关基础知识。为了避免其他人走我走过的弯路,所以就把我的一些很少的心得,和大家分享一下,希望对有些人有帮助。

【什么是FrameBuffer】

FrameBuffer直译就是,帧缓冲。

Frame帧:你所看到的屏幕的图像,或者在一个窗口中的图像,就叫一帧。

Buffer缓冲:一段RAM,用来暂存图像数据,这些数据会被直接写入到显示设备。

帧缓冲就相当于介于 图形操作 和 图像输出中间的一个中间人。将程序对图形数据的处理操作,反馈到显示输出上。

显卡(显存中的数据) <-> 帧缓冲(程序对其中的数据进行处理) <-> 显示器(输出图像)

帧缓冲可用于,实现原先视频卡并不支持的分辨率。

显卡可能并不支持你当前某个更大分辨率的显示器,但是可以通过帧缓冲获取显卡的显存中的数据,处理之后,实现更大的分辨率的图像,然后将数据直接输出到显示器上。

【双显示器例子】

一个例子,可能就是双显示,最近刚刚看到实际某开发者的系统,就是两个显示器,鼠标移动超过单个显示器,到最右边的时候,就跑到另一个显示器了。对于常常用多系统或者需要打开很多东西的开发人员,这个功能很实用。

帧缓冲可以用于 页面交换page flipping(也常叫做 双缓冲double buffering),许多游戏都是采用此技术,以实现更流畅的视频输出,以便用户获得更好的游戏体验。此技术也被用于3D图形加速。

【双缓冲的主要实现原理】

假如你的显示器是VGA模式,640×400,也就是虚拟的分辨率是640X800,也就是800线(每一行的数据,称为一条线,也就是640X1的数据了)。800线的数据存储于Framebuffer,而实际的显示内容,只是400线,Linux内核中的Framebuffer模型中,对应有个变量yoffset,就是表示的这个具体的纵坐标,默认是0,所以显示的内容就是,0-399线,由于和实际显示 页面大小等同,所以此处可以简称为第一帧。如果yoffset改变了,比如此例中变为400,那就是显示剩余的部分,400-799线。此处简称为第二帧。

在系统显示第一帧的时候,系统在后台悄悄地准备第二帧的数据,所以,等第一帧显示完成,多数时候,第二帧的数据也准备好了,就可以直接显示,同时系统又在准备接下来的一帧的数据,这样就可以大大提高显示效率。

【平滑地滚动页面的实现原理】

同上,在显示完第一帧数据的时候,也就是0-399线的时候,将yoffset设置为1,就可以显示1-400线的数据了,显示完成后,再设置yoffset为2,就显示2-401线的数据,这样,就可以一点点地,平滑地显示整个滚动画面了。其实也就是画面在垂直方向的滚动。其中yoffset的增加,可以使用定时器,各个一段时间,比如10us,增加1,系统自动会更新显示对应的内容,这样我们所看到的内容就是滚动的画面了。

此外,Linux中的Framebuffer模型中,提供了一些ioctl功能,给定一些参数,然后系统可以实现对应的功能,其中有个参数就是FBIOPAN_DISPLAY。具体也就是类似如下调用:

ioctl (framebuffer_handler, FBIOPAN_DISPLAY, &variable_info);
而这个调用,如果显示不支持framebuffer的双缓冲的话,那么其framebuffer的缓冲大小,就是和物理上的显示器大小等同,那么对应的yoffset也就不会像双缓冲那样变化了。

也就是说,如果显卡/显示屏控制器不支持双缓冲,那么yoffset就应该一直为0,并且在运行时候,也不应该改变,也不应该去给FBIOPAN_DISPLAY的参数调用ioctl。 

小tip:

【测试显示屏是否正常工作】

在加载了显示屏驱动后,不知道是否已经工作正常的话,

可以通过在某个文件夹下有稍微多些文件的地方,去ls,以便显示有出来东西,

然后通过

ls > /dev/fb0

将当前文件夹列表出来的一些数据,送到framebuffer的默认设备/dev/fb0,如果显示屏驱动已经正常加载,显示屏可以正常工作的话,那么你会在显示屏左上角看到一些乱码花屏一类的东西,这就是你刚刚ls送过去的数据。

发现其他教程上的命令,效果更好:

cat screenshot >/dev/fb0

即将当前截屏内容送给LCD显示。

【LCD液晶显示器的坐标轴】

左上角为(0,0),水平向左是X轴正向,垂直向下,是Y轴正向。即:

(0,0) X→

Y

↓ 

【写驱动前预先要了解的知识】

1.       软件方面:

要搞懂Linux的Framebuffer驱动的框架。

其中就包括熟悉Linux下,为了framebuffer专门实现的数据结构,尤其是

 
 
  1. struct fb_fix_screeninfo { 
  2.        char id[16];   /* identification string eg "TT Builtin" */ 
  3.        unsigned long smem_start;/* Start of frame buffer mem(physical address)*/
  4.        __u32 smem_len; /* Length of frame buffer mem */
  5.        __u32 type; /* see FB_TYPE_* */
  6.        __u32 type_aux; /* Interleave for interleaved Planes */
  7.        __u32 visual; /* see FB_VISUAL_*/
  8.        __u16 xpanstep; /* zero if no hardware panning */
  9.        __u16 ypanstep; /* zero if no hardware panning */
  10.        __u16 ywrapstep; /* zero if no hardware ywrap    */
  11.        __u32 line_length; /* length of a line in bytes    */
  12.        unsigned long mmio_start;/* Start of Memory Mapped I/O(physical address)*/
  13.        __u32 mmio_len; /* Length of Memory Mapped I/O */
  14.        __u32 accel; /* Type of acceleration available */
  15.        __u16 reserved[3]; /* Reserved for future compatibility */
  16. }; 

 
 
  1. /* more kernel header files copied shamelessly */ 
  2. struct fb_bitfield { 
  3.        __u32 offset; /* beginning of bitfield  */ 
  4.        __u32 length; /* length of bitfield */ 
  5.        __u32 msb_right;/* != 0 : Most significant bit is right */ 
  6. }; 
  7.  
  8. struct fb_var_screeninfo { 
  9.        __u32 xres; /* visible resolution*/ 
  10.        __u32 yres;        __u32 xres_virtual;/* virtual resolution*/ 
  11.        __u32 yres_virtual; 
  12.        __u32 xoffset;/* offset from virtual to visible */ 
  13.        __u32 yoffset;/* resolution*/ 
  14.        __u32 bits_per_pixel;/* guess what */ 
  15.        __u32 grayscale; /* != 0 Graylevels instead of colors */ 
  16.        struct fb_bitfield red;/* bitfield in fb mem if true color, */ 
  17.        struct fb_bitfield green; /* else only length is significant */ 
  18.        struct fb_bitfield blue;
  19.        struct fb_bitfield transp; /* transparency*/ 
  20.        __u32 nonstd; /* != 0 Non standard pixel format */ 
  21.        __u32 activate;/* see FB_ACTIVATE_*        */ 
  22.         __u32 height;/* height of picture in mm    */ 
  23.        __u32 width;/* width of picture in mm     */ 
  24.        __u32 accel_flags;/* acceleration flags (hints)    */ 
  25.         /* Timing: All values in pixclocks, except pixclock (of course) */ 
  26.        __u32 pixclock; /* pixel clock in ps (pico seconds) */ 
  27.        __u32 left_margin; /* time from sync to picture */ 
  28.        __u32 right_margin; /* time from picture to sync */ 
  29.        __u32 upper_margin; /* time from sync to picture */ 
  30.        __u32 lower_margin; 
  31.        __u32 hsync_len; /* length of horizontal sync   */ 
  32.        __u32 vsync_len; /* length of vertical sync       */ 
  33.        __u32 sync; /* see FB_SYNC_* */ 
  34.        __u32 vmode; /* see FB_VMODE_* */ 
  35.        __u32 reserved[6]; /* Reserved for future compatibility */ 
  36. }; 

此处简单描述一下,fb_fix_screeninfo对应的是物理设备的相关属性,包括映射后的显存的起始地址,长度,类型等。

fb_var_screeninfo包含了很多具体驱动运行时候的,framebuffer,即显示内容的具体属性,包括实际的显示器上可见的分辨率大小,xres和yres,Framebuffer的分辨率大小xres_virtual和 yres_virtual,如果是上面提到的双缓冲,那么这个分辨率就是可以显示的分辨率的两倍了。

xoffset 和yoffset就是上面提到的,如果是双缓冲,对应不同的应用,就会在运行时刻,改变对应的xoffset 或yoffset,以实现不同的显示效果。

其他一些成员,具体看注释就知道了。

关于Framebuffer的使用,详情请参考第二个链接,里面已经说得很好很详细了,我就没必要再一一翻译了。

2. 硬件方面

了解自己的开发板上的LCD显示屏的大小,具体支持的哪些特性,比如是否支持双缓冲等。

把这些相关信息,在驱动编写的时候,进行对应的赋值。

【如何写framebuffer的LCD驱动】

主要是实现Linux的Framebuffer框架下的,一些函数,最基本的一些就是,以Linux内核中的S3c2410举例,在s3c2410fb.c中,有个对应的结构体: 

 
 
  1. static struct fb_ops s3c2410fb_ops = { 
  2.        .owner           = THIS_MODULE, 
  3.        .fb_check_var = s3c2410fb_check_var, 
  4.        .fb_set_par     = s3c2410fb_set_par, 
  5.        .fb_blank = s3c2410fb_blank, 
  6.        .fb_setcolreg   = s3c2410fb_setcolreg, 
  7.        .fb_fillrect      = cfb_fillrect, 
  8.        .fb_copyarea   = cfb_copyarea, 
  9.        .fb_imageblit   = cfb_imageblit, 
  10. }; 

可以看到,这里,将自己实现的那些对framebuffer的操作函数,包括设置LCD的参数,剪切,拷贝,清空等,赋值给那个结构体变量,这样上层framebuffer框架中的函数调用的时候,就会调用你自己实现的那些函数了。

有些函数,如fb_pan_display等,如果你没有实现,那么系统就会调用上层框架中默认实现的函数来去做对应的操作。

上层的默认的函数实现在 drivers/video/fbmem.c中。相关具体的细节,感兴趣的自己去看吧。 

关于fb驱动中的probe函数,在insmod对应驱动后执行,主要就是一些初始化,其中就包括了上面提到的几个全局变量,结构体的初始化,比如此例中的s3c2410fb_probe()中:

 
 
  1. fbinfo->fix.type          = FB_TYPE_PACKED_PIXELS; 
  2. fbinfo->fix.type_aux          = 0; 
  3. fbinfo->fix.xpanstep          = 0; 
  4. fbinfo->fix.ypanstep          = 0; 
  5. fbinfo->fix.ywrapstep        = 0; 
  6. fbinfo->fix.accel        = FB_ACCEL_NONE; 
  7. fbinfo->var.nonstd      = 0; 
  8. fbinfo->var.activate           = FB_ACTIVATE_NOW; 
  9. fbinfo->var.accel_flags     = 0; 
  10. fbinfo->var.vmode      = FB_VMODE_NONINTERLACED; 

设置了fb和var的各自属性,是FB_ACTIVATE_NOW 立即激活类型,FB_VMODE_NONINTERLACED非交互模式(不支持双缓冲?)等等。

本人目前了解到的就是这么多,欢迎其他高手指出不妥之处和互相交流。

【参考资料】

【1】What is the Framebuffer?

 

【2】Console programming HOWTO - 7. framebuffer

 

【3】Linux Framebuffer Driver Writing HOWTO

 

【4】frame buffer device驱动程序

(Green-waste)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值