搜索
bottom↓
回复: 30

Linux下framebuffer及qvfb编程示例

[复制链接]

出0入0汤圆

发表于 2009-10-22 22:47:07 | 显示全部楼层 |阅读模式
framebuffer编程示例是我从tslib-1.4的ts_test示例程序中提取出来的。内含基本的画线,画矩形8x8,8x16字符显示,虽没有什么实用价值,但是用来学习还是可以的。直接使用arm-linux-gcc编译就可以了。

点击此处下载 ourdev_494787.rar(文件大小:22K) (原文件名:framebuffer.tar.gz.rar)

下载后去掉.rar扩展名。

另外是一些相关的参考资料。

点击此处下载 ourdev_494788.mht(文件大小:87K) (原文件名:FrameBuffer研究-------转载 - linux sys - 沈阳冬天.mht)
点击此处下载 ourdev_494789.mht(文件大小:131K) (原文件名:全面的framebuffer详解 - linux sys - 沈阳冬天.mht)



    qvfb编程示例disqvfb是我分析minigui的gal引擎后,再加上从tslib中提取的代码写的。下载后去掉.rar扩展名,使用gcc就可以编译。对qvfb的操作是通过/tmp/.qtvfb_mouse-0来创建共享内存进行访问的,其关键是QVFbHeader数据结构,如下:

typedef struct
{
    int width;              //宽度
    int height;             //高度
    int depth;              //色深
    int linestep;           //每一行的字节数
    int dataoffset;         //图像数据在共享内存中的偏移
    RECT update;            //要更新的区域
    BYTE dirty;             //是否更新,把它设为1,qvfb就会把update指定的区域显示到屏幕上
    int  numcols;           //颜色数
    unsigned int clut[256]; //颜色索引
}QVFbHeader;



点击此处下载 ourdev_495183.rar(文件大小:19K) (原文件名:disqvfb.tar.gz.rar)



(原文件名:qvfb.jpg)

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2009-10-22 22:48:59 | 显示全部楼层
FrameBuffer研究-------转载


大家都知道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 29, 0 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之类的函数去包装一下低层的对线性存储空间的读写。但是有了画点的程序,再写出画线画圆的函数就不是非常困难了。




有个叫 direct frame buffer 的项目,做的类似于楼主所说的事情:
http://www.directfb.org/


http://blog.chinaunix.net/u1/51844/showart.php?id=1710549

出0入0汤圆

 楼主| 发表于 2009-10-23 21:48:38 | 显示全部楼层
点击此处下载 ourdev_495191.rar(文件大小:778K) (原文件名:qvfb-1.1.tar.gz.rar)
(下载后去掉.rar)

qvfb的编译使用如下命令
tar zxvf qvfb-1.1.tar.gz.rar
cd qvfb-1.1
./configure
make
cd qvfb
cp qvfb /bin

在qvfb子目录下就可以看到可执行的qvfb了。

解压下载的qvfb例子disqvfb.tar.gz,进入disqvfb目录,执行如下命令:
qvfb &
./disqvfb

就可以看到上面的图了。


有了对qvfb和framebuffer编程的例子,我们可以很轻松的学习在linux下的底层图形编程,不用搞什么图形库。

出0入0汤圆

 楼主| 发表于 2009-10-23 21:57:10 | 显示全部楼层
再发一个超简单的例子,直接使用gcc就可以编译。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

typedef struct {
  int left,top,right,bottom;
}RECT;

typedef unsigned char BYTE;

typedef struct
{
    int width;
    int height;
    int depth;
    int linestep;
    int dataoffset;
    RECT update;
    BYTE dirty;
    int  numcols;
    unsigned int clut[256];
}QVFbHeader;

void draw_rectfill(QVFbHeader *qvfb,int left,int top,int right,int bottom,int color)
{
    int x,y;
    int *buffer;

    for(y=top;y<bottom;y++)
    {
      for(x=left;x<right;x++)
      {
      
        buffer=(int *)((int)qvfb+qvfb->dataoffset
            +qvfb->linestep*y+x*qvfb->depth/8);
        *buffer=color;
      }
    }
}

int main(void)
{
    key_t key;
    int shmid;
    QVFbHeader *qvfb;

    key = ftok ("/tmp/.qtvfb_mouse-0", 'b');

    shmid = shmget (key, 0, 0);
    if (shmid != -1)
        qvfb= (QVFbHeader*)shmat (shmid, 0, 0);

    if ((int)qvfb == -1 || qvfb== NULL)
    {
        return -1;
    }

    draw_rectfill(qvfb,10,10,230,310,9000);//画矩形

    qvfb->update.left=40;            //设置要更新的区域
    qvfb->update.top=40;
    qvfb->update.right=210;
    qvfb->update.bottom=290;
   
    qvfb->dirty=1;                 //设置为1后,qvfb就会更新上面指定的区域

    printf("width     :%d\n",qvfb->width);
    printf("height    :%d\n",qvfb->height);
    printf("depth     :%d\n",qvfb->depth);
    printf("dataoffset:%d\n",qvfb->dataoffset);

    shmdt (qvfb);
    return 0;
}

出0入0汤圆

 楼主| 发表于 2009-10-23 23:09:02 | 显示全部楼层
这次来个带鼠标输入的,可以模拟触摸屏了。


点击此处下载 ourdev_495237.rar(文件大小:20K) (原文件名:touch.tar.gz.rar)

(原文件名:touch.jpg)


竟然没有一个人回帖!!!难道这个东西一点用都没有???

出0入0汤圆

发表于 2009-10-26 15:25:53 | 显示全部楼层
不是没用,是大家都没搞过这个

出0入0汤圆

发表于 2009-10-26 15:38:38 | 显示全部楼层
很不错,顶一下

这里搞linux比较少, 楼主可能要去别的网站才能找到组织 ^_^

出0入0汤圆

发表于 2009-10-26 15:58:53 | 显示全部楼层
非常好的一个帖子

对FrameBuffer解释得很清楚~~~~

出20入0汤圆

发表于 2009-10-26 19:18:35 | 显示全部楼层
相当好的帖子  估计很多人都对framebuffer不懂吧!呵呵

出0入0汤圆

发表于 2010-3-26 22:53:55 | 显示全部楼层
mark,最近正要用这个东西,上一次玩framebuffer还是6年前了,都忘的差不多了!

出0入0汤圆

发表于 2010-3-26 23:01:35 | 显示全部楼层
mark!~~~

出0入0汤圆

发表于 2010-3-31 19:09:46 | 显示全部楼层
非常感谢,照着学习中……

出0入0汤圆

发表于 2010-4-2 06:58:34 | 显示全部楼层
很猛的行为,需要努力学习。

出0入0汤圆

发表于 2010-4-14 23:45:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-20 15:13:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-30 16:42:24 | 显示全部楼层
学习中!

出0入0汤圆

发表于 2010-8-31 12:00:11 | 显示全部楼层
谢谢,mark!

出0入0汤圆

发表于 2010-8-31 13:11:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-31 18:59:18 | 显示全部楼层
FrameBuffer
发现你在我的QQ好友里

出0入0汤圆

发表于 2011-3-9 21:17:08 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-14 15:36:28 | 显示全部楼层
顶起,感谢LZ的无私分享。

出0入0汤圆

发表于 2011-3-24 12:30:33 | 显示全部楼层
问个问题:在用户程序中 如何修改xres_virtual的值?!

出0入4汤圆

发表于 2011-3-24 12:44:30 | 显示全部楼层
太好了,我正在做这部分的驱动程序,很好参考价值。

出0入0汤圆

发表于 2011-3-24 19:11:15 | 显示全部楼层
在framebuffer里面有个结构体是 fb_var_screeninfo() 在这个里面定义了 可视区域大小和虚拟区域大小,我如何能够修改这个 虚拟区域的大小?!用(ioctl(fp,FBIOGET_FSCREENINFO,&finfo)能够获取,但是我应该如何设置呢?!

出0入0汤圆

发表于 2011-6-21 17:19:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-1-6 15:29:06 | 显示全部楼层
好东东。。。。mark!

出0入0汤圆

发表于 2012-1-6 16:46:30 | 显示全部楼层
很给力

出0入0汤圆

发表于 2012-2-5 11:40:04 | 显示全部楼层
mark!!!

出0入0汤圆

发表于 2014-6-20 14:42:15 | 显示全部楼层
果然是大牛啊,最近正好在学习LCD显示方面的东东

出0入0汤圆

发表于 2014-6-27 03:44:17 | 显示全部楼层
顶下,以前也移植过

出0入0汤圆

发表于 2014-11-18 13:37:34 | 显示全部楼层
谢谢楼主分享。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 03:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表