大家都知道Unix/Linux系統是由指令驅動的。那么最基本的系統是指令行的(就是想DOS一樣的介面)。XWindowSystemUnix/Linux上的圖形系統,它是通過XServer來控制硬體的。但有一些Linux的發行版在啟動的時候就會在螢幕上出現圖形,這時的圖形是不可能由X來完成的,那是什么機制呢?答案是FrameBuffer


FrameBuffer不是一個圖形系統,更不是視窗系統。它比X要低級,簡單來說FrameBuffer就是一種機制的實現。這種機制是把螢幕上的每個點對映成一段線性記憶體空間,程式可以簡單的改變這段記憶體的值來改變螢幕上某一點的色彩。X的高度可攜式性就是來自于這種機制,不管是在那種圖形環境下,只要有這種機制的實現就可以執行X。所以在几乎所有的平台上都有相應的X版本的移植。


好了,閑話少說,下面我們來看看可以利用FrameBuffer來干點什么。首先看看你是否有了相應的驅動:找一下在/dev/下是否有fb*這個裝置檔案,這是個字元類的特殊檔案。






ls -l /dev/fb0 (Enter)


crw-rw---- 1 root video 29, 0 Jan 27 15:32 /dev/fb0

如果沒有這個檔案也可以找找其他的比如:/dev/fb1,/dev/fb2...如果找不到這些檔案,那就得重新編譯核心了。下面假設存在這個檔案/dev/fb0,這就是FrameBuffer的裝置檔案。


有了這個我們可以play with FrameBuffer了。(一下的作業不一定要在X下,可以在啟動了FrameBuffer的虛擬主控台下)




cat /dev/fb0 > sreensnap




ls -l sreensnap




-rw-r--r-- 1 wsw wsw 6291456 Jan 27 21:30 sreensnap
我們得到了一個恰好6M的檔案,再做下面的作業:




clear /*清楚螢幕的匯出*/


cat sreensnap > /dev/fb0
是不是奇怪的事情發生了?好像是中了病毒一般?螢幕又回復了以前的狀態?不用着急,






clear
這樣螢幕就正常了。




通過以上的作業,我想你也猜到了。檔案/dev/fb0就是控制螢幕上的每一點的色彩的檔案。我們可以寫程式來改變這個檔案的內容,就可以方便的在螢幕上畫圖了:-)




我下面就來寫一個小程式,探測一下螢幕的屬性。






#include


#include


#include


#include


#include




int main () {


int fp=0;


struct fb_var_screeninfo vinfo;


struct fb_fix_screeninfo finfo;


fp = open ("/dev/fb0",O_RDWR);




if (fp < 0){


printf("Error : Can not open framebuffer device\n");


exit(1);


}




if (ioctl(fp,FBIOGET_FSCREENINFO,&finfo)){


printf("Error reading fixed information\n");


exit(2);


}



if (ioctl(fp,FBIOGET_VSCREENINFO,&vinfo)){


printf("Error reading variable information\n");


exit(3);


}




printf("The mem is :%d\n",finfo.smem_len);


printf("The line_length is :%d\n",finfo.line_length);


printf("The xres is :%d\n",vinfo.xres);


printf("The yres is :%d\n",vinfo.yres);


printf("bits_per_pixel is :%d\n",vinfo.bits_per_pixel);


close (fp);


}

struct fb_var_screeninfo
struct fb_fix_screeninfo 兩個資料架構是在/usr/include/linux/fb.h中定義的,裡面有些有趣的值:(都是無象徵式32位的整數)


fb_fix_screeninfo中有


__u32 smem_len 是這個/dev/fb0的大小,也就是記憶體大小。


__u32 line_length 是螢幕上一行的點在記憶體中占有的空間,不是一行上的點數。


fb_var_screeninfo 中有


__u32 xres __u32 yres xy方向的解析度,就是兩個方向上的點數。


__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記憶體長度恰好是6M,每行占有4M的空間,解析度是1024x768,色彩深度是32位。細心的你可能已經發現有些不對。螢幕上的點有1024x768786432個,每個點占有32位元。螢幕一共的占有記憶體數為32x78643225165824 就是3145728位元組,恰好是3M但是上面的程式告訴我們有6M的儲存空間。這是因為在現代的圖形系統中大多有緩衝技朮,顯存中存有兩頁螢幕資料,這是方便快速的改變螢幕內容實現動畫之類比對高的要求。關于這種緩衝技朮有點複雜,我們目前先不討論。對于我們來說只有這3M記憶體來存放這一個螢幕的色彩資料。


好了,現在你應該對FrameBuffer有一個大概的了解了吧。那么接下來你一定會想在螢幕上畫一些東西,讓我們先從畫一個點開始吧。先說說我的想法:在類Unix系統中,一切東西都是檔案。我們對螢幕的讀寫就可以轉換成對/dev/fb0的讀寫。那么就把/dev/fb0open開啟,再用lseek定位要讀寫的位置,最后呼叫read或者write來作業。通過這么一大段的作業我們才完成了對一個點的讀或者寫。這種方法開銷太大了。還有一種方法,我們把/dev/fb0對映到程式程式的記憶體空間中來,然后得到一個指向這段儲存空間的指標,這樣就可以方便的讀寫了。但是我們要知道能對映多少和該對映多少,這能很方便的從上面一個程式得出的參數來決定。


下面是程式程式碼:




#include


#include


#include


#include


#include




int main () {


int fp=0;


struct fb_var_screeninfo vinfo;


struct fb_fix_screeninfo finfo;


long screensize=0;


char *fbp = 0;


int x = 0, y = 0;


long location = 0;


fp = open ("/dev/fb0",O_RDWR);




if (fp < 0){


printf("Error : Can not open framebuffer device\n");


exit(1);


}




if (ioctl(fp,FBIOGET_FSCREENINFO,&finfo)){


printf("Error reading fixed information\n");


exit(2);


}



if (ioctl(fp,FBIOGET_VSCREENINFO,&vinfo)){


printf("Error reading variable information\n");


exit(3);


}




screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;


/*這就是把fp所指的檔案中從開始到screensize大小的內容給對映出來,得到一個指向這塊空間的指標*/


fbp =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);


if ((int) fbp == -1)


{


printf ("Error: failed to map framebuffer device to memory.\n");


exit (4);


}


/*這是你想畫的點的位置座標,(00)點在螢幕左上角*/


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; /* 是否透通*/


munmap (fbp, screensize); /*解除對映*/


close (fp); /*關閉檔案*/


return 0;




}






因為這是對線性儲存空間的讀寫,所以程式碼有點不清晰,不易理解。但是有了這個基本的程式碼實現,我們可以很容易寫一些DrawPoint之類的函數去包裝一下低層的對線性儲存空間的讀寫。但是有了畫點的程式,再寫出畫線畫圓的函數就不是非常困難了。




重要結構


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


};



struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */


};



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;


};



struct fbgen_hwswitch {
void (*detect)(void);
int (*encode_fix)(struct fb_fix_screeninfo *fix, const void *par,
struct fb_info_gen *info);
int (*decode_var)(const struct fb_var_screeninfo *var, void *par,
struct fb_info_gen *info);
int (*encode_var)(struct fb_var_screeninfo *var, const void *par,
struct fb_info_gen *info);
void (*get_par)(void *par, struct fb_info_gen *info);
void (*set_par)(const void *par, struct fb_info_gen *info);
int (*getcolreg)(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp, struct fb_info *info);
int (*setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);
int (*pan_display)(const struct fb_var_screeninfo *var,
struct fb_info_gen *info);
int (*blank)(int blank_mode, struct fb_info_gen *info);
void (*set_disp)(const void *par, struct display *disp,
struct fb_info_gen *info);


};



struct fb_info_gen {
struct fb_info info;
/* Entries for a generic frame buffer device */
/* Yes, this starts looking like C++ */
u_int parsize;
struct fbgen_hwswitch *fbhw;
/* From here on everything is device dependent */
};


 



 






轉貼自


http://www.linuxsir.org/bbs/showthread.php?t=241071



arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()