1、framebuffer应用编程
(1)打开设备文件
(2)获取设备信息
宏定义的命令在/linux/fb.h中
不可变信息FSCREENINFO,使用ioctl参数有FBIOGET_FSCREENINFO宏名,表示用ioctl从驱动中获取lcd设备的不变的信息
可变信息VSCREENINFO,使用ioctl参数有FBIOGET_VSCREENINFO宏名,表示用ioctl从驱动中获取lcd设备的可变信息
fb的驱动框架将屏幕的所有硬件信息分为了两类,一类为不可变的,是通过软件不可更改的(比如屏幕尺寸,长短等)。一类是可以变的,比如分辨率是可以变的。
内核中分别定义了两个结构体来表示lcd设备的可变信息和不可变信息,也在/include/linux/fb.h中。
内核fb驱动框架提供的描述lcd屏幕的不可变信息的结构体。这部分不可变的信息和应用层的关系其实不大,应用层最多就是读出来看一下不可变信息。
struct fb_fix_screeninfo { char id[16]; /* identification string eg "TT Builtin" */ unsigned long smem_start; /* Start of frame buffer mem */ //fb在内存中的物理地址的起始地址 /* (physical address) */ __u32 smem_len; /* Length of frame buffer mem */ /fb在内存中占用的物理地址的字节长度 __u32 type; /* see FB_TYPE_* */ __u32 type_aux; /* Interleave for interleaved Planes */ __u32 visual; /* see FB_VISUAL_* */ __u16 xpanstep; /* zero if no hardware panning */ __u16 ypanstep; /* zero if no hardware panning */ __u16 ywrapstep; /* zero if no hardware ywrap */ __u32 line_length; /* length of a line in bytes */ unsigned long mmio_start; /* Start of Memory Mapped I/O */ /* (physical address) */ __u32 mmio_len; /* Length of Memory Mapped I/O */ __u32 accel; /* Indicate to driver which */ /* specific chip/card we have */ __u16 reserved[3]; /* Reserved for future compatibility */ };
跟应用层有关系的结构体是关于fb驱动框架提供的lcd屏幕可变信息的结构体如下
struct fb_var_screeninfo { __u32 xres; /* visible resolution */ __u32 yres; //可视分辨率 __u32 xres_virtual; /* virtual resolution */ __u32 yres_virtual; //虚拟分辨率 __u32 xoffset; /* offset from virtual to visible */ //屏幕的参考点,就是fb的起始参考坐标。 __u32 yoffset; /* resolution */ __u32 bits_per_pixel; /* guess what */ //像素的深度,就是每个像素用多少个位来表示。 __u32 grayscale; /* != 0 Graylevels instead of colors */ //灰度级别 struct fb_bitfield red; /* bitfield in fb mem if true color, */ //描述红色 struct fb_bitfield 结构体是用来描述颜色域的 struct fb_bitfield green; /* else only length is significant */ //描述绿色 struct fb_bitfield blue; //描述蓝色 struct fb_bitfield transp; /* transparency */ //描述透明度 __u32 nonstd; /* != 0 Non standard pixel format */ __u32 activate; /* see FB_ACTIVATE_* */ __u32 height; /* height of picture in mm */ //屏幕显示图片大小的实际物理尺寸大小, __u32 width; /* width of picture in mm */ __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ /* Timing: All values in pixclocks, except pixclock (of course) */ __u32 pixclock; /* pixel clock in ps (pico seconds) */ //像素时钟 __u32 left_margin; /* time from sync to picture */ //从这个到下面的六个是参数。 初始化lcd时序时的那几个参数。裸机中讲过 __u32 right_margin; /* time from picture to sync */ __u32 upper_margin; /* time from sync to picture */ __u32 lower_margin; __u32 hsync_len; /* length of horizontal sync */ __u32 vsync_len; /* length of vertical sync */ __u32 sync; /* see FB_SYNC_* */ __u32 vmode; /* see FB_VMODE_* */ __u32 rotate; /* angle we rotate counter clockwise */ __u32 reserved[5]; /* Reserved for future compatibility */ };
什么是可视分辨率什么是虚拟分辨率呢?可视分辨率就是能看到的分辨率,比如你的屏幕是1024*468的,那么分辨率在1024*468范围内的东西你都可以看到。虚拟分辨率就是分辨率比实际的屏幕分辨率大,比如你的屏幕分辨率是800*480,但是你设置的分辨率是800*960,这就是虚拟分辨率。如果起始参考点是(0, 0),那么虚拟分辨率在屏幕实际分辨率部分的是可以看到的,虚拟分辨率不在屏幕分辨率部分的像素点是看不到的。
有一种机制叫做双缓冲机制,也叫做乒乓结构。意思就是屏幕分辨率是800*480,虚拟分辨率是800*960,应用操作显示的时候,首先将起始参考点移动到(0, 0)的位置,然后应用刷一幅图进去,第二幅图片可以刷到(0, 480)的位置,这样显示第二幅图片的时候,应用只需要将起始参考点移动到(0, 480)的位置,那么第二幅图片就可以显示出来。
fb的显存占用的内存字节数,可以用读出来的分辨率乘以位深度占用的字节来算出来,比如位深度是32位,那么位深度占用的就是4个字节,即一个像素点占用四个字节,虚拟分辨率是800*960,所以fb的显存部分占用的内存字节数就是800*960*4。
2、截止目前为止分析的过程,然后编写的应用程序代码如下
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/ioctl.h> // 宏定义 #define FBDEVICE "/dev/fb0" int main(void) { int fd = -1, ret = -1; struct fb_fix_screeninfo finfo = {0}; //定义结构体变量,读取屏幕信息时用来记录屏幕不可变信息的 struct fb_var_screeninfo vinfo = {0}; //定义结构体变量,读取屏幕信息时用来记录屏幕可变信息的 // 第1步:打开设备 fd = open(FBDEVICE, O_RDWR); if (fd < 0) { perror("open"); return -1; } printf("open %s success.\n", FBDEVICE); // 第2步:获取设备的硬件信息 ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo); //传该命令进去,表示获取不可变的信息,记录到finfo结构体中。命令和结构体在linux/fb.h中。 if (ret < 0) { perror("ioctl"); return -1; } printf("smem_start = 0x%x, smem_len = %u.\n", finfo.smem_start, finfo.smem_len); //fb占用显存的起始物理地址和使用的内存字节长度 ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); //传该命令进去,表示获取屏幕的可变信息,记录到vinfo中,命令和结构体在linux/fb.h中。 if (ret < 0) { perror("ioctl"); return -1; } printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres); //可变信息,屏幕分辨率 800 480 printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual); //可变信息,虚拟分辨率 800 960 printf("bpp = %u.\n", vinfo.bits_per_pixel); //可变信息,位深度 32 return 0; }