FrameBuffer相关概念
FrameBuffer中文译名为帧缓冲驱动,它是出现在2.2.xx内核中的一种驱动程序接口。
Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。FrameBuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过FrameBuffer的读写直接对显存进行操作。用户可以将FrameBuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节,这些都是由FrameBuffer设备驱动来完成的。
但FrameBuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池。CPU将运算后的结果放到这个水池,水池再将结果流到显示器,中间不会对数据做处理。应用程序也可以直接读写这个水池的内容在这种机制下,尽管FrameBuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU负担很重。
帧缓冲驱动应用广泛,在 linux 的桌面系统中,X window 服务器就是利用帧缓冲进行窗口的绘制。尤其是通过帧缓冲可显示汉字点阵,成为Linux 汉化的唯一可行方案。
在开发者看来,FrameBuffer 本质上是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。所以说FrameBuffer就是一块白板。例如对于初始化为16位色的FrameBuffer来说,FrameBuffer 中的两个字节代表屏幕上一个点,从上到下,从左至右,屏幕位置与内存地址是顺序的线性关系。
帧缓存可以在系统存储器(内存)的任意位置,视频控制器通过访问帧缓存来刷新屏幕。帧缓存也叫刷新缓存FrameBuffer或RefreshBuffer,这里的帧(frame)是指整个屏幕范围。
帧缓存有个地址,是在内存里。我们通过不停的向 FrameBuffer 中写入数据, 显示控制器就自动的从FrameBuffer中取数据并显示出来。全部的图形都共享内存中同一个帧缓存。
CPU 指定显示控制器工作,则显示控制器根据CPU的控制到指定的地方去取数据和指令,目前的数据一般是从显存里取,如果显存里存不下,则从内存里取, 内存也放不下,则从硬盘里取,当然也不是内存放不下,而是为了节省内存的话, 可以放在硬盘里,然后通过指令控制显示控制器去取。帧缓存 FrameBuffer里面存储的东西是一帧一帧的, 显卡会不停的刷新 FrameBuffer, 这每一帧如果不捕获的话,则会被丢弃,也就是说是实时的。这每一帧不管是保存在内存还是显存里, 都是一个显性的信息,这每一帧假设是800x600的分辨率,则保存的是800x600个像素点和颜色值。
Frambuffer介绍
帧缓冲在linux体系中居于上层应用和底层显示设备之间,如下图所示。它的设计意图是对上层应用屏蔽掉低层不同硬件的操作细节:对于不同厂家不同类型的显示硬件,由于各自厂商在技术上扬长避短的需要,所以在具体的细节比如寄存器数量和种类的设计上就会存在相当大的差异,而且对于各个寄存器的初始化的定义和引脚信号的定义也不近相同,这样即便是两种性能相近的产品,例如夏普3.5寸LCD模块与三星的3.5寸模块其操作细节也截然不同。如果让擅长于开发图形界面的开发人员费尽心思去琢磨属于硬件范畴的液晶模块寄存器写入时序问题,无疑是很大的浪费。因此,需要在上层开发和底层设备之间加入一个中间层以节省开发人员的时间和精力。
图像显示过程
屏幕显示调用的是framebuffer,首先建立一个fb_dev结构体,里边有设备指针、内存空间指针、横竖像素数、颜色位数等信息:
struct fb_dev
{
int fb;
void *fb_mem;
int fb_width, fb_height, fb_line_len, fb_size;
int fb_bpp;
} fbdev;
初始化framebuffer设备,并进行内存地址映射,可以直接把处理后的数据映射到framebuffer的缓存中进行显示:
int fb;
if ((fb = open("/dev/fb0", O_RDWR)) < 0)
{
perror(__func__);
return (-1);
}
fb_stat(fb);
fbdev.fb_mem = mmap (NULL, fbdev.fb_size,
PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
fbdev.fb = fb;
其中fb_stat(fb)函数如下定义,得到framebuffer的长、宽和位宽,成功则返回0,失败返回-1:
int fb_stat(int fd)
{
struct fb_fix_screeninfo fb_finfo;
struct fb_var_screeninfo fb_vinfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo))
{
perror(__func__);
return (-1);
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo))
{
perror(__func__);
return (-1);
}
fbdev.fb_width = fb_vinfo.xres;
fbdev.fb_height = fb_vinfo.yres;
fbdev.fb_bpp = fb_vinfo.bits_per_pixel;
bdev.fb_line_len = fb_finfo.line_length;
fbdev.fb_size = fb_finfo.smem_len;
return (0);
}
在屏幕上显示数据,需要直接对像素点上直接显示像素颜色,因为原始解码的数据是24位RGB数据,而屏幕的颜色位数是16位,则需要将RGB888转换为RGB565数据:主要是对不用颜色位数进行移位。
color=(unsigned short) (((buffer[x3s]<<8) & 0xF800)|((buffer[x3s+1]<<3) & 0x07E0)|((buffer[x3s+2] >> 3) & 0x001F));
因为开发板自带的NEC 3.5寸液晶屏分辨率是240×320,而摄像头输出的数据为320×240,故显示时需进行矩阵转置,由fbmem基址 + x * width + y确定:
if ((x > width) || (y > height)
return (-1);
unsigned short *dst = ((unsigned short *) fbmem + x * width + y);
*dst = color;
在程序最后,需要解除内存映射和关闭设备:
munmap(fbdev.fb_mem,fbdev.fb_size);
close(fb);
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__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 capabilities; /* see FB_CAP_* */
__u16 reserved[2]; /* Reserved for future compatibility */
};
struct fb_image {
__u32 dx; /* Where to place image */
__u32 dy;
__u32 width; /* Size of image */
__u32 height;
__u32 fg_color; /* Only used when a mono bitmap */
__u32 bg_color;
__u8 depth; /* Depth of the image */
const char *data; /* Pointer to image data */
struct fb_cmap cmap; /* color map info */
};