linux驅動由淺入深系列:顯示子系統之一(通過FrameBuffer在螢幕上畫出圖形)
阿新 • • 發佈:2019-01-10
顯示子系統對應用層提供的介面叫做framebuffer,一般位於/dev/fb0(下文示例運行於adroid的平臺位於/dev/graphics/fb0,不過它們都是一樣的),它為上層提供了統一的對顯示卡的描述。首先要明確的是lcd顯示子系統雖然複雜,但其任然是基本的字元裝置,fb0就是其裝置節點,主裝置號29。不同之處在於,可以通過mmap(mmap將一個檔案或者其它物件對映進記憶體。)對其進行地址對映,將核心中的視訊記憶體空間直接對映到使用者空間,這樣使用者空間填入需要顯示的資料就能直接顯示在lcd上。其餘的引數查詢與設定通過ioctl都可以完成。
我們先從第一個應用層測試開始講起:
1, 保持螢幕上有一幀畫面,進入fb0對應的目錄(/dev/ 或/dev/graphics/)執行:
cat fb0 > fb_test
這樣就可以對framebuffer的一幀原始資料進行暫存
2, 切換一幀螢幕畫面,執行
cat fb_test > fb0
可以看到之前暫存的一幀畫面重新出現了。adroid有自身的重新整理頻率,所以我們刷入的一幀畫面會很快被覆蓋,看到的現象可能是一閃即逝。
從上面的測試我們理解了fb0的基本作用,下面我們寫一個測試程式畫一個自己的圖形:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> int main() { int fbfd=0;//framebuffer 檔案控制代碼 struct fb_var_screeninfo vinfo; unsigned long screen_size=0; char *fbp=0;//framebuffer 在使用者空間對映的虛擬地址指標 int x=0,y=0,i=0; fbfd=open("/dev/graphics/fb0",O_RDWR); //開啟framebuffer 檔案節點 if(!fbfd){ printf("error\n"); exit(1); } if(ioctl(fbfd,FBIOGET_VSCREENINFO,&vinfo)){ //獲取螢幕可變引數 printf("error\n"); exit(1); } //列印螢幕可變引數:x軸畫素個數,y軸畫素個數,每個畫素點數 printf("%dx%d,%dbpp\n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel); screen_size=vinfo.xres*vinfo.yres*12; //framebuffer大小 fbp=(char *)mmap(0,screen_size,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0);//對映 if((int)fbp==-1){ printf("error\n"); exit(4); } for(i = 0; i < screen_size/2; i++) { unsigned short rgb; rgb=(31<<11)|(0<<5)|0; *((unsigned short *)(fbp+i*2))=rgb; } munmap(fbp,screen_size); close(fbfd); return 0; }
分析:
上述程式比較簡潔,先打開了fb0節點,獲取了相關引數,然後進行framebuffer地址對映。之後直接向framebuffer中寫入資料,畫面就會出現在螢幕上。
其中framebuffer的大小是從驅動程式中獲知的,下一篇文章將會就驅動層展開分析。
framebuffer中資料格式有rgb565、rgb888,上面示例為rgb565。執行後全屏為紅色。