注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

时间记录器

记录我的Linux、Android学习之路

 
 
 

日志

 
 

FrameBuffer编程(二)  

2010-08-04 13:43:30|  分类: Linux |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Framebuffer简单编程例子(转贴)

http://shinco-js.spaces.live.com/Blog/cns!94EC79D6B044343C!629.entry

    大家都知道Unix/Linux系统是由命令驱动的。那么最基本的系统是命令行的(就是想DOS一样的界面)。X-Window-System是 Unix/Linux上的图 形系统,它是通过X-Server来控制硬件的。但有一些Linux的发行版在引导的时候就会在屏幕上出现图形,这时的图形是不可能由X来完成的,那 是什么机制呢?答案是FrameBuffer。

    FrameBuffer不是一个图形系统,更不是窗口系统。它比X要低级,简单来说FrameBuffer就是一种机制的实现。这种机制是把屏幕上的每个点映射 成一段线性内存空间,程序可以简单的改变这段内存的值来改变屏幕上某一点的颜色。X的高度可移植性就是来自于这种机制,不管是在那种图形 环境下,只要有这种机制的实现就可以运行X。所以在几乎所有的平台上都有相应的X版本的移植。
    下面我们来看看可以利用FrameBuffer来干点什么。首先看看是否有了相应的驱动:找一下在/dev/下是否有fb*这个设备文件 ,这是个字符类的特殊文件。

命令:
ls -l /dev/fb0 (Enter)      
crw-rw----  1 root video 290 Jan 27 15:32 /dev/fb0

    如果没有这个文件也可以找找其他的比如:/dev/fb1,/dev/fb2...如果找不到这些文件,那就得重新编译内核了。下面假设存在这个文 件/dev/fb0,这就是FrameBuffer的设备文件。有了这个我们可以play with FrameBuffer了。(一下的操作不一定要在X下,可以在启动了FrameBuffer的虚拟控制台下)

命令:
cat /dev/fb0 > sreensnap 
ls -l sreensnap
-rw-r--r--  1 wsw wsw 6291456 Jan 27 21:30 sreensnap

我们得到了一个恰好6M的文件,再做下面的操作:

命令:
clear     /*清除屏幕的输出*/
cat sreensnap > /dev/fb0

是不是奇怪的事情发生了?好像是中了病毒一般?屏幕又恢复了以前的状态?不用着急,

命令:
clear
这样屏幕就正常了。

    通过以上的操作,我们可以知道,文件/dev/fb0就是控制屏幕上的每一点的颜色的文件。我们可以写程序来改变这个文件的内容,就可以方便 的在屏幕上画图了:-)

下面的小程序,用来探测一下屏幕的属性。

#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/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\n",finfo.smem_len); 
    printf("The line_length is :%d\n",finfo.line_length); 
    printf("The xres is :%d\n",vinfo.xres); 
    printf("The yres is :%d\n",vinfo.yres); 
    printf("bits_per_pixel is :%d\n",vinfo.bits_per_pixel); 
    close (fp);
}

struct fb_var_screeninfo 和 struct fb_fix_screeninfo 两个数据结构是在/usr/include/linux/fb.h中定义的,里面有些有趣的值:(都是 无符号32位的整数)
在fb_fix_screeninfo中有
    __u32 smem_len 是这个/dev/fb0的大小,也就是内存大小。
    __u32 line_length 是屏幕上一行的点在内存中占有的空间,不是一行上的点数。
在fb_var_screeninfo 中有
    __u32 xres ,__u32 yres 是x和y方向的分辨率,就是两个方向上的点数。
    __u32 bits_per_pixel 是每一点占有的内存空间。

把上面的程序编译以后运行,在我的机器上的结果如下:

命令:
The mem is :6291456
The line_length is :4096
The xres is :1024
The yres is :768
bits_per_pixel is :32

内存长度恰好是6M,每行占有4M的空间,分辨率是1024x768,色彩深度是32位。细心的你可能已经发现有些不对。屏幕上的点有1024x768=  786432个,每个点占有32比特。屏幕一共的占有内存数为32x786432=25165824 就是3145728字节,恰好是3M但是上面的程序告诉我们有6M的存储 空间。这是因为在现代的图形系统中大多有缓冲技术,显存中存有两页屏幕数据,这是方便快速的改变屏幕内容实现动画之类比较高的要求。关 于这种缓冲技术有点复杂,我们目前先不讨论。对于我们来说只有这3M内存来存放这一个屏幕的颜色数据。
好了,现在你应该对FrameBuffer有一个大概的了解了吧。那么接下来你一定会想在屏幕上画一些东西,让我们先从画一个点开始吧。先说说我的 想法:在类Unix系统中,一切东西都是文件。我们对屏幕的读写就可以转换成对/dev/fb0的读写。那么就把/dev/fb0用open打开,再用 lseek定 位要读写的位置,最后调用read或者write来操作。通过这么一大段的操作我们才完成了对一个点的读或者写。这种方法开销太大了。还有一种方 法,我们把/dev/fb0映射到程序进程的内存空间中来,然后得到一个指向这段存储空间的指针,这样就可以方便的读写了。但是我们要知道能映 射多少和该映射多少,这能很方便的从上面一个程序得出的参数来决定。
下面是程序代码:

代码:
#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; 
    long screensize=0
    char *fbp = 0
    int x = 0, y = 0
    long location = 0
    
    fp = open ("/dev/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); 
    }  
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8
    /*这就是把fp所指的文件中从开始到screensize大小的内容给映射出来,得到一个指向这块空间的指针*/ 
    fbp =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);   
    if ((int) fbp == -1)     
    {        
        printf ("Error: failed to map framebuffer device to memory.\n");        
        exit (4);     
    }
    /*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/  
    x = 100;    
    y = 100;  
    location = x * (vinfo.bits_per_pixel / 8) + y  *  finfo.line_length;  
    *(fbp + location) = 100;  /* 蓝色的色深 */  /*直接赋值来改变屏幕上某点的颜色*/  
    *(fbp + location + 1) = 15/* 绿色的色深*/     
    *(fbp + location + 2) = 200/* 红色的色深*/     
    *(fbp + location + 3) = 0;  /* 是否透明*/    
    munmap (fbp, screensize); /*解除映射*/  
    close (fp);    /*关闭文件*/  
    return 0;
}

因为这是对线性存储空间的读写,所以代码有点不清晰,不易理解。但是有了这个基本的代码实现,我们可以很容易写一些DrawPoint之类的函数去包装一下低层的对线性存储空间的读写。但是有了画点的程序,再写出画线画圆的函数就不是非常困难了。
  评论这张
 
阅读(1388)| 评论(2)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017