帧缓冲(framebuffer)是Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差别,容许上层应用程序在图形模式下直接对显示缓冲区进行读写操做。用户没必要关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动自己来完成。
framebuffer机制模仿显卡的功能,将显卡硬件结构抽象为一系列的数据结构,能够经过framebuffer的读写直接对显存进行操做。用户能够将framebuffer当作是显存的一个映像,将其映射到进程空间后,就能够直接进行读写操做,写操做会直接反映在屏幕上。node
帧缓冲设备为标准的字符型设备,在Linux中主设备号29,定义在/include/linux/major.h中的FB_MAJOR,次设备号定义帧缓冲的个数,最大容许有32个FrameBuffer,定义在/include/linux/fb.h中的FB_MAX,对应于文件系统下/dev/fb%d设备文件,使用以下方式(前面的数字表示次设备号):
0 = /dev/fb0 第一个fb 设备
1 = /dev/fb1 第二个fb 设备linux
fb 也是一种普通的内存设备,能够像内存设备(/dev/mem)同样,对其read,write,seek 以及mmap。但区别在于fb 使用的不是整个内存区,而是显存部分。数据结构
典型的显示机制如图所示:app
对于用户程序而言,它和其余的设备并无什么区别,用户能够把fb当作是一块内存,既能够向内存中写数据,也能够读数据。fb的显示缓冲区位于内核空间,应用程序能够把此空间映射到本身的用户空间,在进行操做。ide
(1) 在应用程序中,操做/dev/fbn的通常步骤以下:
打开/dev/fbn设备文件。函数
(2) 用ioctl()操做取得当前显示屏幕的参数,如屏幕分辨率、每一个像素点的比特数。根据屏幕参数可计算屏幕缓冲区的大小。ui
(3) 用mmap()函数,将屏幕缓冲区映射到用户空间。this
(4) 映射后就能够直接读/写屏幕缓冲区,进行绘图和图片显示了。spa
(5) 使用完帧缓冲设备后须要将其释放。3d
(6) 关闭文件。
ioctl来用各类命令控制fb,控制的实现都定义在<linux/fb.h>中。这个头文件是内核源码中的,因为交叉编译器中将其包含了,因此咱们能够在应用层直接调用。
<linux/fb.h>,里面定义了一些ioctl的命令
/* ioctls
0x46 is 'F' */
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOGETCMAP 0x4604
#define FBIOPUTCMAP 0x4605
#define FBIOPAN_DISPLAY 0x4606
咱们主要使用FBIOGET_VSCREENINFO和FBIOGET_FSCREENINFO 命令。从字面意思咱们不难看出,这两个命令的意思分别为
fb’s ioctl, to get variable screen info:获取应用程序可改变的参数(如设定的分辨率)
fb’s ioctl, to get fixed screen info:获取固定的参数(如屏幕的分辨率,通常只是拿来看看)
<linux/fb.h>中还提供了专门的结构体类型,用来存放上述两个参数。
存放可变参数的结构体类型:struct fb_var_screeninfo,其详细定义参照“相关结构体”部分。
比较重要的可变参数有:
xres、yres:可视画面的x、y轴分辨率(应用层改不了)
xres_virtual、yres_virtual:虚拟画面(即fb)x、y轴分辨率
xoffset、yoffset:可视画面相对于虚拟画面的x、y轴偏移量
bits_per_pixel:像素深度
虚拟画面通常会被默认设为(不必定的)可视画面的两倍,这种结构被称之为“双缓冲机制”,这样作的好处是能够一边显示,一边缓冲下一幅画面 。
相关结构体及其关系为:
这个结构描述了显示卡的特性。
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 resolution */ __u32 yoffset; __u32 bits_per_pixel; /* guess what */ __u32 grayscale; /* != 0 Gray levels instead of colors */ struct fb_bitfield red; /* bitfield in fb mem if true color, */ 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; /* acceleration flags (hints) */ /* 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 */ __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 reserved[6]; /* Reserved for future compatibility */ };
这个结构在显卡被设定模式后建立,它描述显示卡的属性,而且系统运行时不能被修改;好比FrameBuffer内存的起始地址。它依赖于被设定的模式,当一个模 式被设定后,内存信息由显示卡硬件给出,内存的位置等信息就不能够修改。
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; /* Type of acceleration available */ __u16 reserved[3]; /* Reserved for future compatibility */ };
用户应用可使用ioctl()系统调用来操做设备,这个结构就是用以支持ioctl()的这些操做的。
struct fb_ops {
/* open/release and usage marking */
struct module *owner; int (*fb_open)(struct fb_info *info, int user); int (*fb_release)(struct fb_info *info, int user); /* get non settable parameters */ int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); /* get settable parameters */ int (*fb_get_var)(struct fb_var_screeninfo *var, int con, struct fb_info *info); /* set settable parameters */ int (*fb_set_var)(struct fb_var_screeninfo *var, int con, struct fb_info *info); /* get colormap */ int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); /* set colormap */ int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); /* pan display (optional) */ int (*fb_pan_display)(struct fb_var_screeninfo *var, int con, struct fb_info *info); /* perform fb specific ioctl (optional) */ int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info); /* perform fb specific mmap */ int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma); /* switch to/from raster image mode */ int (*fb_rasterimg)(struct fb_info *info, int start); };
描述设备无关的颜色映射信息。能够经过FBIOGETCMAP 和 FBIOPUTCMAP 对应的ioctl操做设定或获取颜色映射信息。
struct fb_cmap {
__u32 start; /* First entry */ __u32 len; /* Number of entries */ __u16 *red; /* Red values */ __u16 *green; __u16 *blue; __u16 *transp; /* transparency, can be NULL */ };
定义当显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个fb_ops指针,指向驱动设备工做所需的函数集。
struct fb_info {
char modename[40]; /* default video mode */ kdev_t node; int flags; int open; /* Has this been open already ? */ #define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */ struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ struct fb_monspecs monspecs; /* Current Monitor specs */ struct fb_cmap cmap; /* Current cmap */ struct fb_ops *fbops; char *screen_base; /* Virtual address */ struct display *disp; /* initial display variable */ struct vc_data *display_fg; /* Console visible on this display */ char fontname[40]; /* default font name */ devfs_handle_t devfs_handle; /* Devfs handle for new name */ devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */ int (*changevar)(int); /* tell console var has changed */ int (*switch_con)(int, struct fb_info*); /* tell fb to switch consoles */ int (*updatevar)(int, struct fb_info*); /* tell fb to update the vars */ void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */ /* arg = 0: unblank */ /* arg > 0: VESA level (arg-1) */ void *pseudo_palette; /* Fake palette of 16 colors and the cursor's color for non palette mode */ /* From here on everything is device dependent */ void *par; };
#include <stdio.h>
#include <sys/stat.h> #include <sys/types.h> #include <sys/ioctl.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <stdlib.h> #include <unistd.h> #define FBDEVICE "/dev/fb0" void draw_back(unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color); void draw_line(unsigned int *pfb, unsigned int width, unsigned int height); int main(void) { int fd = -1; int ret = -1; unsigned int *pfb = NULL; struct fb_fix_screeninfo finfo; struct fb_var_screeninfo vinfo; fd = open(FBDEVICE, O_RDWR); if (fd < 0) { perror("open"); return -1; } printf("open %s success \n", FBDEVICE); ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo); if (ret < 0) { perror("ioctl"); return -1; } ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); if (ret < 0) { perror("ioctl"); return -1; } pfb = (unsigned int *)mmap(NULL, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (NULL == pfb) { perror("mmap"); return -1; } printf("pfb :0x%x \n", *pfb); draw_back(pfb, vinfo.xres_virtual, vinfo.yres_virtual, 0xffff0000); draw_line(pfb, vinfo.xres_virtual, vinfo.yres_virtual); close(fd); return 0; } void draw_back(unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color) { unsigned int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { *(pfb + y * width + x) = color; } } } void draw_line(unsigned int *pfb, unsigned int width, unsigned int height) { unsigned int x, y; for (x = 50; x < width - 50; x++) { *(pfb + 50 * width + x) = 0xffffff00; } for (y = 50; y < height -50; y++) { *(pfb + y * width + 50) = 0xffffff00; } }