1. framebuffer裝置介紹
用framebuffer裝置,你可以把你的電腦螢幕當成一個真正的圖形裝置。你可以修改解析度,重新整理率,色彩深度等。最好的一點是,你可以把像素點繪在任何你想要的地方。framebuffer裝置不是一個圖形庫,而更確切的是一個低級的通用裝置。這樣創造了巨大的靈活性,但同時也有它的缺點。想使用framebuffer裝置,你應該做以下事情:
1、判斷出你使用的裝置
2、開啟裝置
3、取回或改變螢幕設定
4、映射(Map)螢幕記憶體
通常要開啟的裝置是/dev/fb0,但是如果使用者有多個視訊卡和監視器的話,裝置也可能不同。大多數應用通過讀取環境變數FRAMEBUFFER (用getenv();)來決定該使用哪個裝置。如果該環境變數不存在,那麼就用/dev/fb0。
通過open()調用開啟裝置,讀裝置意味著讀取螢幕記憶體(可稱之為顯存)。用$cat /dev/fb0 >screenshot將螢幕記憶體匯入一個檔案,恢複剛才的螢幕則可使用:$cat screenshot >/dev/fb0。
2、裝置的基本用法
顯然,用上述方法使用螢幕記憶體並不經濟方便。在讀或寫之前持續的定址(見man lseek)將會導致很多的開銷。這就是為什麼你要映射你的螢幕記憶體。當你將螢幕記憶體映射到你的應用程式時,你將得到一個直接指向螢幕記憶體的指標。
在我們可以映射螢幕記憶體之前,我們需要知道我們能夠映射多少,以及我們需要映射多少。第一件要做的事情就是從我們新得到的framebuffer裝置取回資訊。有兩個結構包含著我們需要的資訊,第一個包含固定的螢幕資訊,這部分是由硬體和驅動的能力決定的;第二個包含著可變的螢幕資訊,這部分是由硬體的目前狀態決定的,可以由使用者空間的程式調用ioctl()來改變。
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*/
};
在這裡非常重要的域是smem_len和line-length。smem-len告訴我們framebuffer裝置的大小,第二個域告訴我們指標應該前進多少位元組去得到下一行的資料。第二個結構則要有意思的多,它給了我們可以改變的資訊。
/* more kernel header files copied shamelessly */
struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */
};
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 */
__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 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*/
};
前幾個成員決定了解析度。xres和yres 是在螢幕上可見的實際解析度,在通常的vga模式將為640和400(也許是480,by highbar)。*res-virtual決定了構建螢幕時視訊卡讀取螢幕記憶體的方式。當實際的垂直解析度為400,虛擬解析度可以是800。這意味著 800行的資料被儲存在了螢幕記憶體區中。因為只有400行可以被顯示,決定從那一行開始顯示就是你的事了。這個可以通過設定*offset來實現。給 yoffset賦0將顯示前400行,賦35將顯示第36行到第435行,如此重複。這個功能在許多情形下非常方便實用。它可以用來做雙緩衝。雙緩衝就是你的程式分配了可以填充兩個螢幕的記憶體。將offset設為0,將顯示前400行(假設是標準的vga),同時可以秘密的在400行到799行構建另一個螢幕,當構建結束時,將yoffset設為400,新的螢幕將立刻顯示出來。現在將開始在第一塊記憶體區中構建下一個螢幕的資料,如此繼續。這在動畫中十分有用。
另外一個應用就是用來平滑的滾動整個螢幕。就像在前面螢幕中一樣,在記憶體配置800行的空間。每隔10毫秒設定一個定時器(timer,見man settimer和man
signal / man sigaction),將offset設為1或是比上次更多,瞧,你看到了一個平滑滾動的螢幕。確保你的訊號(signal)不要因為最佳輸出的原因被訊號處理常式阻塞。
將 bits_per_pixel 設為1,2,4,8,16,24或32來改變色彩深度(color depth)。不是所有的視訊卡和驅動都支援全部色彩深度。當色彩深度改變,驅動將自動改變fb-bitfields。這些指出,在一個特定的顏色基準上,多少和哪些位元被哪種顏色使用。如果bits-per-pixel小於8,則fb-bitfields將無定義而且顏色映射將啟用。
在fb-var-screeninfo結構結尾的定時的設定是當你選擇一個新的解析度的時候用來設定視頻定時的。