Linux 下framebuffer 幀緩衝的使用

framebuffer 幀緩衝

幀緩衝(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當作是一塊內存,既能夠向內存中寫數據,也能夠讀數據。fb的顯示緩衝區位於內核空間,應用程序能夠把此空間映射到本身的用戶空間,在進行操做。ide

(1)    在應用程序中,操做/dev/fbn的通常步驟以下:
打開/dev/fbn設備文件。函數

(2)    用ioctl()操做取得當前顯示屏幕的參數,如屏幕分辨率、每一個像素點的比特數。根據屏幕參數可計算屏幕緩衝區的大小。ui

(3)    用mmap()函數,將屏幕緩衝區映射到用戶空間。this

(4)    映射後就能夠直接讀/寫屏幕緩衝區,進行繪圖和圖片顯示了。spa

(5)    使用完幀緩衝設備後須要將其釋放。3d

(6)    關閉文件。

 

fb的控制

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:像素深度

虛擬畫面通常會被默認設爲(不必定的)可視畫面的兩倍,這種結構被稱之爲「雙緩衝機制」,這樣作的好處是能夠一邊顯示,一邊緩衝下一幅畫面 。

 

相關結構體

相關結構體及其關係爲:

 

fb_var_screeninfo

這個結構描述了顯示卡的特性。

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 */ };

fb_fix_screeninfon

這個結構在顯卡被設定模式後建立,它描述顯示卡的屬性,而且系統運行時不能被修改;好比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 */ };

fb_ops

用戶應用可使用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); };

fb_cmap

描述設備無關的顏色映射信息。能夠經過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_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; } }
相關文章
相關標籤/搜索