linux FB 是CPU 到显示器中的中间人,像一个池子一样。CPU 将操作好的数据项放到池子中,然后再将这些数据显示到屏幕上。
它的好处在于 用户可以将FB看成一个显示内存的映射,当将其映射到用户进程空间是可以直接进行读写操作。操作的方式是通过ioctl的方式,有底层驱动实现。
直接使用命令行操作FB 的方式
- 用命令:
$ dd if=/dev/zero of=/dev/fb
清空屏幕
- 用命令:
#dd if=/dev/fb of=fbfile
可以将fb中的内容保存下来;
- 可以重新写回屏幕:
#dd if=fbfile of=/dev/fb
;
值得一提的是 fbfile
文件大小为6MB。
使用ioctl FBIOGET_FSCREENINFO FBIOGET_VSCREENINFO
可以获取到显存大小和实际屏幕的大小。
在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
内存长度恰好为 6291456 / 1024 /1024 = 6。每行占4K的空间。(原文为4M),色彩深度为32bit。屏幕上的点由 1024*768 = 786432个,每个点占32bit,屏幕一共占有内存 32 * 786432 = 25165824 ==》 25165824 / 8 / 1024 /1024 = 3MB。恰好为3MB,但是上面的程序告诉我们有6MB的存储空间。这是因为,多重缓冲技术。显存中有两页的屏幕数据,接替显示,可以实现屏幕抗闪烁等效果。
目前了解了FB,然后可以就在屏幕上进行一个点一个线的绘制。在linux 中一切都是文件,即对屏幕的绘制就是对/dev/fb0
的绘制,那么在屏幕上画点的流程就是。
-
打开设备
-
通过mmap的方式将/dev/fb0
映射到用户的进程空间中,然后获取到这个一块内存的大小。
fbp = mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,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; /* 是否透明*/
如果画线的话,就循环画点呗。
完整实例
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <sys/mman.h>
int main(void)
{
int fp = 0;
struct fb_var_screeninfo v_info;
struct fb_fix_screeninfo f_info;
long s32ScreenSize = 0;
char * fbp = 0;
int x = 0;
int y = 0;
long s32Location = 0;
fp = open("/dev/fb0", O_RDWR);
if(fp < 0 ) {
perror("open");
exit(1);
}
int s32Ret = -1;
s32Ret = ioctl(fp, FBIOGET_FSCREENINFO, &f_info);
if(s32Ret) {
perror("ioctl");
goto err;
}
s32Ret = ioctl(fp, FBIOGET_VSCREENINFO, &v_info);
if(s32Ret) {
perror("ioctl");
goto err;
}
printf("The mem is :%d\n", f_info.smem_len);
printf("The line_length is :%d\n", f_info.line_length);
printf("The xres is :%d\n", v_info.xres);
printf("The yres is :%d\n", v_info.yres);
printf("bits_per_pixel is :%d\n",v_info.bits_per_pixel);
printf("long size[%lu] \n", sizeof(long));
s32ScreenSize = v_info.xres * v_info.yres * v_info.bits_per_pixel / 8;
// void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
fbp = (char*) mmap(NULL, s32ScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, fp, 0);
if(fbp == NULL){
perror("mmap");
goto err;
}
x = 400;
y = 400;
s32Location = x * (v_info.bits_per_pixel / 8) + y * f_info.line_length;
int i = 0;
for(i = 0; i < 100 ; i++) {
*(fbp + s32Location + i) = 100;
*(fbp + s32Location + i + 1) = 15;
*(fbp + s32Location + i + 2) = 200;
*(fbp + s32Location + i + 3) = 0;
}
munmap(fbp,s32ScreenSize);
close(fp);
return 0;
err:
close(fp);
exit(1);
return -1;
}
/dev/fb0入门练习(linux FrameBuffer)