Android圖形系統分析與移植--六、framebuffer研究


1  FrameBuffer的發展歷史

計算機研究者從很早開始已經開始討論理論上FrameBuffer的優點,但卻一直苦於沒有能力生產一台擁有足夠內存的計算機。1969年,貝爾實驗室的JoanMiller試驗了第一個已知的FrameBuffer。該設備顯示了一幅3位位深的圖片。然而,直到20世紀70年代,集成電路的內存芯片上的進展才使得制造一個可以顯示標准視頻圖像的FrameBuffer成為可能。

1972年,Richard Shoup在施樂帕洛阿爾托研究所里設計了SuperPaint系統,該系統擁有311,040字節的內存,並能存儲640*480像素8位位深的圖片。這些內存分散在16個回路電板上,每個電板上裝有多個2千比特的片選芯片。要使得整個系統可以正常工作,Richard Shoup的設計必須保證整個FrameBuffer實現為307,200字節的片選注冊芯片並保證能和電視信號同步。這種設計最初的缺點已經顯露出來,即內存不能隨機訪問。當然,指定位置的內存在要求的掃描線開始掃描的時候可以訪問。這樣使得該系統存在着極大的潛在缺陷,導致寫入數據到FrameBuffer時有33毫秒的延遲。

同時,Richard Shoup可以用SuperPaint系統制造一個早期的數字視頻捕獲系統。通過將輸出信號同步到輸入信號,Richard Shoup可以重寫每個像素點的數據。Richard Shoup還曾經試驗用色彩表來修改輸出信號,這些色彩表允許SuperPaint系統產生多種多樣的超出8位數據所包含色彩限制之外的顏色。這種體制在不久的將來成為計算機幀緩沖區中司空見慣的體制。

1974年,Evans和Sutherland發布了第一個商業版的FrameBuffer,花費15,000美元。它能夠在8位灰度級模式下產生512*512個像素點的分辨率,並成為那些沒有資源為自己建立FrameBuffer的研究者們的福利。不久的將來,美國紐約理工大學用3個Evans和Sutherland的系統制造了第一個24位的色彩系統,每一個FrameBuffer被連接到一個RGB色彩輸出,用一個微型計算機控制三個設備作為一個設備。

20世紀70年代末,集成電路技術的飛速發展使得家庭計算機包含低色彩FrameBuffer成為可能。雖然相比在某些計算機中使用的類似於Atari 400這種更加精確的圖形設備,低色彩FrameBuffer因其差勁的表現總是被嘲笑,FrameBuffer卻因此在個人計算機中成為一種標准。今天,幾乎所有有圖形處理能力的計算機都利用FrameBuffer來產生視頻信號。

80年代,FrameBuffer在高端智能終端開始流行。SGI公司,Sun公司,HP公司,DEC公司,IBM公司都為他們的計算機發布了FrameBuffer版本,這些FrameBuffer通常情況下比大部分家庭計算機具有更高的質量,應用於電視,印刷,計算機建模和3D圖形技術等。

Amiga計算機由於其在圖形處理方面的出色能力,創造了一個基於圖形卡的廣闊的FrameBuffer市場。值得一提的是,在Amiga A2500 Unix計算機中使用的圖形卡,它是1991年出現的第一台實現以X11服務器作為圖形環境和Open Look GUI高分辨率(1024*1024或1024*768,256色)圖形界面的宿主機服務器的計算機。這塊被裝在A2500 Unix上的圖形卡被稱作A2400,它是以德州儀器公司TMS34010圖形處理器為基礎的圖形板,時鍾頻率為50MHz,是一個完全只能的協處理器。A2410圖形卡是Amiga公司和Lowell大學共同研發的。其他值得一提的是,Amiga的FrameBuffer是基於GVP公司的一個很有趣的視頻集成系列中的Impact Vision IV24圖形卡實現的,它有能力將同步鎖信號、色度和電視信號混合到24位的FrameBuffer中,直到今天,它還一直在市場中活躍着,如圖形卡視頻捕獲系統DCTV,32位圖形卡Firecracker,Harlequin卡等等一直還在使用它。

2  FrameBuffer相關概念

FrameBuffer中文譯名為幀緩沖驅動,它是出現在2.2.xx內核中的一種驅動程序接口。

Linux是工作在保護模式下,所以用戶態進程是無法象DOS那樣使用顯卡BIOS里提供的中斷調用來實現直接寫屏,Linux抽象出FrameBuffer這個設備來供用戶態進程實現直接寫屏。FrameBuffer機制模仿顯卡的功能,將顯卡硬件結構抽象掉,可以通過FrameBuffer的讀寫直接對顯存進行操作。用戶可以將FrameBuffer看成是顯示內存的一個映像,將其映射到進程地址空間之后,就可以直接進行讀寫操作,而寫操作可以立即反應在屏幕上。這種操作是抽象的,統一的。用戶不必關心物理顯存的位置、換頁機制等等具體細節,這些都是由FrameBuffer設備驅動來完成的。

但FrameBuffer本身不具備任何運算數據的能力,就只好比是一個暫時存放水的水池。CPU將運算后的結果放到這個水池,水池再將結果流到顯示器,中間不會對數據做處理。應用程序也可以直接讀寫這個水池的內容在這種機制下,盡管FrameBuffer需要真正的顯卡驅動的支持,但所有顯示任務都有CPU完成,因此CPU負擔很重。

幀緩沖驅動應用廣泛,在 linux 的桌面系統中,X window 服務器就是利用幀緩沖進行窗口的繪制。尤其是通過幀緩沖可顯示漢字點陣,成為Linux 漢化的唯一可行方案。

在開發者看來,FrameBuffer 本質上是一塊顯示緩存,往顯示緩存中寫入特定格式的數據就意味着向屏幕輸出內容。所以說FrameBuffer就是一塊白板。例如對於初始化為16位色的FrameBuffer來說,FrameBuffer 中的兩個字節代表屏幕上一個點,從上到下,從左至右,屏幕位置與內存地址是順序的線性關系。

幀緩存可以在系統存儲器(內存)的任意位置,視頻控制器通過訪問幀緩存來刷新屏幕。幀緩存也叫刷新緩存FrameBuffer或RefreshBuffer,這里的幀(frame)是指整個屏幕范圍。

幀緩存有個地址,是在內存里。我們通過不停的向 FrameBuffer 中寫入數據, 顯示控制器就自動的從FrameBuffer中取數據並顯示出來。全部的圖形都共享內存中同一個幀緩存。

CPU 指定顯示控制器工作,則顯示控制器根據CPU的控制到指定的地方去取數據和指令,目前的數據一般是從顯存里取,如果顯存里存不下,則從內存里取, 內存也放不下,則從硬盤里取,當然也不是內存放不下,而是為了節省內存的話, 可以放在硬盤里,然后通過指令控制顯示控制器去取。幀緩存 FrameBuffer里面存儲的東西是一幀一幀的, 顯卡會不停的刷新 FrameBuffer, 這每一幀如果不捕獲的話,則會被丟棄,也就是說是實時的。這每一幀不管是保存在內存還是顯存里, 都是一個顯性的信息,這每一幀假設是800x600的分辨率,則保存的是800x600個像素點和顏色值。

3  FrameBuffer使用基礎

framebuffer的設備文件一般是 /dev/fb0、/dev/fb1 等等。

可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕。

如果顯示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕;

用命令: #dd if=/dev/fb of=fbfile 可以將fb中的內容保存下來;

可以重新寫回屏幕: #dd if=fbfile of=/dev/fb;

在使用Framebuffer時,Linux是將顯卡置於圖形模式下的。

在應用程序中,一般通過將 FrameBuffer 設備映射到進程地址空間的方式使用,比如下面的程序就打開 /dev/fb0 設備,並通過 mmap 系統調用進行地址映射,隨后用memset 將屏幕清空(這里假設顯示模式是 1024x768-8 位色模式,線性內存模式):

int fb;

unsigned char*fb_mem;

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

fb_mem = mmap(NULL, 1024*768,                                                                                                            PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);

memset (fb_mem,0, 1024*768); //這個命令應該只有在root可以執

FrameBuffer 設備還提供了若干 ioctl 命令,通過這些命令,可以獲得顯示設備的一些固定信息(比如顯示內存大小)、與顯示模式相關的可變信息(比如分辨率、象素結構、每掃描線的字節寬度),以及偽彩色模式下的調色板信息等等。

通過 FrameBuffer 設備,還可以獲得當前內核所支持的加速顯示卡的類型(通過固定信息得到),這種類型通常是和特定顯示芯片相關的。比如目前最新的內核(2.4.9)中,就包含有對 S3、Matrox、nVidia、3Dfx 等等流行顯示芯片的加速支持。在獲得了加速芯片類型之后,應用程序就可以將 PCI 設備的內存I/O(memio)映射到進程的地址空間。這些 memio 一般是用來控制顯示卡的寄存器,通過對這些寄存器的操作,應用程序就可以控制特定顯卡的加速功能。

PCI 設備可以將自己的控制寄存器映射到物理內存空間,而后,對這些控制寄存器的訪問,給變成了對物理內存的訪問。因此,這些寄存器又被稱為"memio"。一旦被映射到物理內存,Linux 的普通進程就可以通過mmap 將這些內存 I/O 映射到進程地址空間,這樣就可以直接訪問這些寄存器了。

當然,因為不同的顯示芯片具有不同的加速能力,對memio 的使用和定義也各自不同,這時,就需要針對加速芯片的不同類型來編寫實現不同的加速功能。比如大多數芯片都提供了對矩形填充的硬件加速支持,但不同的芯片實現方式不同,這時,就需要針對不同的芯片類型編寫不同的用來完成填充矩形的函數。

FrameBuffer 只是一個提供顯示內存和顯示芯片寄存器從物理內存映射到進程地址空間中的設備。所以,對於應用程序而言,如果希望在 FrameBuffer 之上進行圖形編程,還需要自己動手完成其他許多工作。

Framebuffer的具體操作流程如下:

1)打開/dev/fb設備文件;

2)用ioctrl操作取得當前顯示屏幕的參數,如屏幕分辨率,每個像素點的比特數。根據屏幕參數可計算屏幕緩沖區的大小。

3)將屏幕緩沖區映射到用戶空間。

4)映射后就可以直接讀寫屏幕緩沖區,進行繪圖和圖片顯示了。

4  FrmaeBuffer內部結構

FrameBuffer設備驅動基於如下兩個文件:

1)linux/include/linux/fb.h

2)linux/drivers/video/fbmem.c

下面分析這兩個文件。

1.       fb.h

幾乎主要的結構都是在這個中文件定義的。這些結構包括:

1)fb_var_screeninfo

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

2)fb_fix_screeninfon

這個結構在顯卡被設定模式后創建,它描述顯示卡的屬性,並且系統運行時不能被修改;比如FrameBuffer內存的起始地址。它依賴於被設定的模式,當一個模式被設定后,內存信息由顯示卡硬件給出,內存的位置等信息就不可以修改。

3) fb_cmap

描述設備無關的顏色映射信息。可以通過FBIOGETCMAP 和 FBIOPUTCMAP 對應的ioctl操作設定或獲取顏色映射信息。

4) fb_info

定義當顯卡的當前狀態;fb_info結構僅在內核中可見,在這個結構中有一個fb_ops指針, 指向驅動設備工作所需的函數集。

5) struct fb_ops

用戶應用可以使用ioctl()系統調用來操作設備,這個結構就是用一支持ioctl()的這些操作的。

6) structfbgen_hwswitch

這個結構 fbgen_hwswitch抽象了硬件的操作.雖然它不是必需的,但有時候很有用。

2.       fbmem.c

fbmem.c 處於FrameBuffer設備驅動技術的中心位置。它為上層應用程序提供系統調用也為下一層的特定硬件驅動提供接口;那些底層硬件驅動需要用到這兒的接口來向系統內核注冊它們自己。fbmem.c 為所有支持FrameBuffer的設備驅動提供了通用的接口,避免重復工作。

1) 全局變量

struct fb_info*registered_fb[FB_MAX];

intnum_registered_fb;

這兩變量記錄了所有fb_info 結構的實例,fb_info 結構描述顯卡的當前狀態,所有設備對應的fb_info 結構都保存在這個數組中,當一個FrameBuffer設備驅動向系統注冊自己時,其對應的fb_info 結構就會添加到這個結構中,同時num_registered_fb 為自動加1。

2)fbmem.c 實現了如下函數

register_framebuffer(structfb_info *fb_info);

unregister_framebuffer(structfb_info *fb_info);

這兩個是提供給下層FrameBuffer設備驅動的接口,設備驅動通過這兩函數向系統注冊或注銷自己。幾乎底層設備驅動所要做的所有事情就是填充fb_info結構然后向系統注冊或注銷它。

5  雙緩沖機制

最早解釋多緩沖區如何工作的方式,是通過一個現實生活中的實例來解釋的。在一個陽光明媚的日子,你想將水池里的水換掉,而又找不到水管的時候,你就只能用木桶來灌滿水池。當木桶被水龍頭注滿的,關掉水龍頭,走到水池旁邊,將水到進去,然后走回到水龍頭旁邊繼續重復上述工作,如此往復直到將水池灌滿。這就類似單緩沖工作過程。當你想將木桶里的水倒出的時候,你必須關掉水龍頭。

現在假設你用兩個木桶來做上面的工作。你會注滿第一個木桶然后將第二個木桶換到水龍頭下面,這樣,在第二個水桶注滿的時間內,你就可以將第一個木桶里面的水倒進水池里面,當你回來的時候,你只需要再將第一個木桶換下第二個注滿水木桶,當第一個木桶開始注水的時候你就將第二個木桶里面的水倒進水池里面。重復這個過程直到水池被注滿。很容易看得到用這種技術注滿水池將會更快,同時也節省了很多等待木桶被注滿的時間,而這段時間里你什么也做不了,而水龍頭也就不用等待從木桶被注滿到你回來的這段時間了。

當你雇佣另外一個人來搬運一個被注滿的木桶時,這就有點類似於三個緩沖區的工作原理。如果將搬運木桶的的時間很長,你可以用更多的木桶,雇佣更多的人,這樣水龍頭就會一直開着注滿木桶了。

在計算機圖形學中,雙緩沖是一種畫圖技術,使用這種技術可以使得畫圖沒有(至少是減少)閃爍、撕裂等不良效果,並減少等待時間。

雙緩沖機制的原理大概是:所有畫圖操作將它們畫圖的結果保存在一塊系統內存區域中,這塊區域通常被稱作“后緩沖區(back buffer)”,當所有的繪圖操作結束之后,將整塊區域復制到顯示內存中,這個復制操作通常要跟顯示器的光棧束同步,以避免撕裂。雙緩沖機制必須要求有比單緩沖更多的顯示內存和CPU消耗時間,因為“后緩沖區”需要顯示內存,而復制操作和等待同步需要CPU時間。

基於雙緩沖機制可以實現頁交換。

頁交換初始狀態如圖所示:

如上圖所示,此時由於處於初始狀態,畫圖操作的結果都在后緩沖區中,而屏幕上顯示的則是前緩沖區中的內容。此時畫圖操作尚未完成。

畫圖操作完成之后,頁轉換操作開始執行,示意圖如圖所示:


如上圖所示,畫圖操作結束,下一個畫圖操作的結果保存對象指向前緩沖區,屏幕的顯示對象指向后緩沖區,此時前緩沖區變成實際意義上的后緩沖區,后緩沖區變成實際意義上的前緩沖去,即實現“頁交換”操作。

有時候也在頁交換鏈中設置多個“后緩沖區”,這是就需要多緩沖區機制的支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM