Linux的帧缓冲(Frame Buffer)之一:原理及控制参数

2019-07-13 08:18发布

大家都知道Unix/Linux系统是由命令驱动的。X-Window-System是Unix/Linux上的图形系统,它是通过X-Server来控制硬件的。但有一些Linux的发行版在引导的时候就会在屏幕上出现图形,这时的图形是不可能由X来完成的,那是什么机制呢?答案是FrameBuffer。
       帧缓冲(framebuffer)是 Linux 为显示设备提供的一个接口,把显存抽象后的一种设备,他允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer 设备驱动来完成的,所以可知其具有良好的移植性。
       帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示卡,Linux 下还可支持多个帧缓冲设备,最多可达32 个,分别为/dev/fb0 到/dev/fb31,当前缺省的帧缓冲设备通常指向/dev/fb0。当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,次设备号则从0到31。分别对应/dev/fb0-/dev/fb31。在MID上,设备信息是/dev/graphics/fb0。   
      通过/dev/fb,应用程序的操作主要有这几种: 
1.读/写(read/write)/dev/fb:相当于读/写屏幕缓冲区。在MID上,采用的方式是cat /dev/graphics/fb0 tmp和cat tmp > /dev/graphics/fb0可以实现屏幕内存存储和重现,但是本人试了没有效果(原因不知)。
2.映射(map)操作:由于 Linux 工作在保护模式,每个应用程序都有自己的虚拟地址空间,在应用程序中是不能直接访问物理缓冲区地址的。为此,Linux 在文件操作 file_operations 结构中提供了 mmap 函数,可将文件的内容映射到用户空间。对于帧缓冲设备,则可通过映射操作,可将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址中,之后用户就可以通过读写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图了。       mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。成功执行时,mmap()返回被映射区的指针,munmap()返回0。
3.I/O控制:对于帧缓冲设备,对设备文件的 ioctl操作可读取/设置显示设备及屏幕的参数,如分辨率,显示颜 {MOD}数,屏幕大小等等。ioctl 的操作是由底层的驱动程序来完成的。
    典型程序段如下:  [cpp] view plain copy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6.   
  7. int main () {  
  8.     int fp=0;  
  9.     struct fb_var_screeninfo vinfo;  
  10.     struct fb_fix_screeninfo finfo;  
  11.     fp = open ("/dev/graphics/fb0",O_RDWR);  
  12.   
  13.     if (fp < 0){  
  14.         printf("Error : Can not open framebuffer device/n");  
  15.         exit(1);  
  16.     }  
  17.   
  18.     if (ioctl(fp,FBIOGET_FSCREENINFO,&finfo)){  
  19.         printf("Error reading fixed information/n");  
  20.         exit(2);  
  21.     }  
  22.     if (ioctl(fp,FBIOGET_VSCREENINFO,&vinfo)){  
  23.         printf("Error reading variable information/n");  
  24.         exit(3);  
  25.     }  
  26.   
  27.     printf("The mem is :%d ",finfo.smem_len);  
  28.     printf("The line_length is :%d ",finfo.line_length);  
  29.     printf("The xres is :%d ",vinfo.xres);  
  30.     printf("The yres is :%d ",vinfo.yres);  
  31.     printf("bits_per_pixel is :%d ",vinfo.bits_per_pixel);  
  32.     close (fp);  
  33. }  
     在服务器上加上如下的makefile用ARM交叉编译器编译后,拷贝到MID或手机: [cpp] view plain copy
  1. CROSS_COMPILE  = /home/zhangcheng/gcc/arm-2008q3/bin/arm-linux-  
  2. CC    = $(CROSS_COMPILE)gcc  
  3.   
  4. testFB: testFB.c  
  5.     $(CC)  -o testFB testFB.c -static  
   运行得到结果是: The mem is :1536000
The line_length is :1600
The xres is :800
The yres is :480
bits_per_pixel is :16      其中,struct fb_var_screeninfo 和 struct fb_fix_screeninfo 两个数据结构是在/usr/include/linux/fb.h中定义的,在fb_fix_screeninfo中有__u32 smem_len 是这个/dev/fb0的大小,也就是内存大小。__u32 line_length 是屏幕上一行的点在内存中占有的空间,不是一行上的点数。在fb_var_screeninfo 中有__u32 xres ,__u32 yres 是x和y方向的分辨率,就是两个方向上的点数。__u32 bits_per_pixel 是每一点占有的内存空间。
      如上:内存长度是1536000B,一行占的内存是1600B,分辨率是800*480,每像素占2B。你会发现1536000/(800*480*2)=2,分配的内存空间是单帧画面需要的内存空间的2倍?这是因为在现代的图形系统中大多有缓冲技术,显存中存有两页屏幕数据,这是方便快速的交换屏幕内容。        运行这个程序需要注意几点:(1)文本编辑后要从DOS转换成UNIX格式,否则易出错;(2)回车换行符与DOS中相同;(3)运行时要放在设备的内部空间上,比如/data,在SD卡中运行会提示权限问题;(4)可以通过手机本身的终端执行,也可以通过DOS连ADB后是用root权限执行。(5)有的运行平台上会有几个fb设备(当然一般LCD是fb0),为了确定LCD到底是哪个设备,可以采用# cat nice_1.bmp > /dev/graphics/fb0,正常状况下屏幕会有图像刷新。   参考地址:http://blog.ednchina.com/exbob/37028/category.aspx 参考地址:http://blog.csdn.net/scwinter/archive/2010/01/08/5148967.aspx