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

       大家都知道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操作可读取/设置显示设备及屏幕的参数,如分辨率,显示颜色数,屏幕大小等等。ioctl 的操作是由底层的驱动程序来完成的。
    典型程序段如下: 

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>

int main () {
    int fp=0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    fp = open ("/dev/graphics/fb0",O_RDWR);

    if (fp < 0){
        printf("Error : Can not open framebuffer device/n");
        exit(1);
    }

    if (ioctl(fp,FBIOGET_FSCREENINFO,&finfo)){
        printf("Error reading fixed information/n");
        exit(2);
    }
    if (ioctl(fp,FBIOGET_VSCREENINFO,&vinfo)){
        printf("Error reading variable information/n");
        exit(3);
    }

    printf("The mem is :%d\r\n",finfo.smem_len);
    printf("The line_length is :%d\r\n",finfo.line_length);
    printf("The xres is :%d\r\n",vinfo.xres);
    printf("The yres is :%d\r\n",vinfo.yres);
    printf("bits_per_pixel is :%d\r\n",vinfo.bits_per_pixel);
    close (fp);
}

     在服务器上加上如下的makefile用ARM交叉编译器编译后,拷贝到MID或手机:

CROSS_COMPILE  = /home/zhangcheng/gcc/arm-2008q3/bin/arm-linux-
CC    = $(CROSS_COMPILE)gcc

testFB: testFB.c
	$(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 

你可能感兴趣的:(linux,struct,buffer,FP,makefile,图形)