對FrameBuffer的一夜hack

來源:互聯網
上載者:User

大家都知道Unix/Linux系統是由命令驅動的。那麼最基本的系統是命令列的(就是想DOS一樣的介面)。X-Window-System是Unix/Linux上的圖形系統,它是通過X-Server來控制硬體的。但有一些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 <unistd.h>#include <stdio.h>#include <fcntl.h>#include <linux/fb.h>#include <sys/mman.h>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 是x和y方向的解析度,就是兩個方向上的點數。
__u32 bits_per_pixel 是每一點佔有的記憶體空間。

把上面的程式編譯以後運行,在我的機器上的結果如下:代碼:

The mem is :6291456The line_length is :4096The xres is :1024The yres is :768bits_per_pixel is :32

記憶體長度恰好是6M,每行佔有4M的空間,解析度是1024x768,色彩深度是32位。細心的你可能已經發現有些不對。螢幕上的點有1024x768=786432個,每個點佔有32位元。螢幕一共的佔有記憶體數為32x786432=25165824 就是3145728位元組,恰好是3M但是上面的程式告訴我們有6M的儲存空間。這是因為在現代的圖形系統中大多有緩衝技術,顯存中存有兩頁螢幕資料,這是方便快速的改變螢幕內容實現動畫之類比較高的要求。關於這種緩衝技術有點複雜,我們目前先不討論。對於我們來說只有這3M記憶體來存放這一個螢幕的顏色資料。
好了,現在你應該對FrameBuffer有一個大概的瞭解了吧。那麼接下來你一定會想在螢幕上畫一些東西,讓我們先從畫一個點開始吧。先說說我的想法:在類Unix系統中,一切東西都是檔案。我們對螢幕的讀寫就可以轉換成對/dev/fb0的讀寫。那麼就把/dev/fb0用open開啟,再用lseek定位要讀寫的位置,最後調用read或者write來操作。通過這麼一大段的操作我們才完成了對一個點的讀或者寫。這種方法開銷太大了。還有一種方法,我們把/dev/fb0映射到程式進程的記憶體空間中來,然後得到一個指向這段儲存空間的指標,這樣就可以方便的讀寫了。但是我們要知道能映射多少和該映射多少,這能很方便的從上面一個程式得出的參數來決定。
下面是程式碼:代碼:

#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <linux/fb.h>#include <sys/mman.h>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);    }/*這是你想畫的點的位置座標,(0,0)點在螢幕左上方*/ 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之類的函數去封裝一下低層的對線性儲存空間的讀寫。但是有了畫點的程式,再寫出畫線畫圓的函數就不是非常困難了。

這些就是我對FrameBuffer的初步研究,匆忙之間寫些東西不成文章,以後要寫些更進階一點的函數的實現。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.