葉炳發(fā),孟小華
(暨南大學(xué)計(jì)算機(jī)系 廣州 510632)
Android作為第一個(gè)完整、開(kāi)放、免費(fèi)的手機(jī)平臺(tái),自推出以來(lái)就是業(yè)界的熱門(mén)話題,由于擁有良好的可移植性和強(qiáng)大的功能,在嵌入式設(shè)備方面的應(yīng)用表現(xiàn)出良好的勢(shì)頭。在圖形顯示方面,Android建立在Linux上,但并沒(méi)有像一些桌面 Linux使用GTK(GIMP Toolkit)組建XWindows(一個(gè)多平臺(tái)的圖形用戶接口),也沒(méi)有使用Cairo向量圖形鏈接庫(kù)實(shí)現(xiàn)圖形顯示,而是使用了專為Android而改良的一種2D向量圖形處理函數(shù)庫(kù)Skia。在3D圖形方面是基于嵌入式3D圖形算法標(biāo)準(zhǔn)OpenGL/ES實(shí)現(xiàn)的,該庫(kù)可以使用硬件加速。然而,雖然Google開(kāi)放了Android的源代碼,但相關(guān)技術(shù)文檔很少,而且圖形系統(tǒng)的實(shí)現(xiàn)原理比較復(fù)雜,所以本文集中對(duì)Android圖形系統(tǒng)的底層原理進(jìn)行研究。
Android SDK的圖形包主要包括android.graphics、android.view、android.widget和 android.opengl,前 3 個(gè)是用于 2D的圖形開(kāi)發(fā),基于 SGL(Skia graphics library)。android.opengl是用于3D的圖形開(kāi)發(fā),基于OpenGL/ES。
Skia是一個(gè)開(kāi)放源碼的2D向量圖形處理函數(shù)庫(kù),包含字型、坐標(biāo)轉(zhuǎn)換以及點(diǎn)陣圖,有著高效能且簡(jiǎn)潔的表現(xiàn),在Android平臺(tái)中搭配OpenGL/ES與特定的硬件特征強(qiáng)化了顯示效果。OpenGL/ES是OpenGL的一個(gè)子集,是一個(gè)跨平臺(tái)圖形庫(kù),是專門(mén)為嵌入式系統(tǒng)而設(shè)計(jì)的。
Android圖形系統(tǒng)的組成如圖1所示。上層應(yīng)用調(diào)用2D和3D圖形庫(kù)對(duì)Surface Manager提供的Surface進(jìn)行繪制,通過(guò)Surface Manager的合成器SurfaceFlinger對(duì)各個(gè)Surface進(jìn)行合成,并由EGL接口實(shí)現(xiàn)在Framebuffer設(shè)備上的顯示。
在Android的圖形系統(tǒng)中,Surface Manager是一個(gè)重要組成,Surface Manager對(duì)上層提供Surface給應(yīng)用進(jìn)行繪制,管理對(duì)顯示子系統(tǒng)的訪問(wèn),對(duì)來(lái)自多個(gè)應(yīng)用的2D和3D圖像進(jìn)行無(wú)縫的合成后傳給底層的EGL進(jìn)行處理,Surface Manager的工作原理如圖2所示。
Surface Manager為Application準(zhǔn)備一個(gè)或多個(gè)Surface后,把Surface傳給 Application,讓 Application可以在上面作圖形處理。應(yīng)用程序先通過(guò)調(diào)用圖形庫(kù)提供基礎(chǔ)的繪制圖形原語(yǔ)和JNI函數(shù),然后又通過(guò)Native Method的繪制圖形原語(yǔ)調(diào)用2D和3D的圖形庫(kù)對(duì)Surface進(jìn)行繪制。
在Android平臺(tái)下,每個(gè)Surface都有一個(gè)Front Buffer和一個(gè)Back Buffer,每個(gè)窗口都以一個(gè)Surface對(duì)象作為基礎(chǔ)。每個(gè)Surface又對(duì)應(yīng)一個(gè)Layer,SurfaceFlinger將各個(gè)Layer的Front Buffer合成后繪制到Frame Buffer上。
關(guān)于SurfaceFlinger,在Surface Manager中用于管理邏輯上眾多的Surface,其功能特點(diǎn)如下:
·SurfaceFlinger在一個(gè)系統(tǒng)范圍內(nèi)合成Surface的功能,并把合成后的顯示內(nèi)容傳給幀緩沖設(shè)備;
·SurfaceFlinger能一起合成來(lái)自多個(gè)程序的2D或3D顯示的Surface;
·Surface通過(guò)Android的IPC機(jī)制Binder以緩沖的形式進(jìn)行遞交。
從Surface Manager工作原理分析,可以理解Application與Surface Manager是以C/S的模式進(jìn)行交互的,Application處理Surface的部分是客戶端,而Surface Manager提供服務(wù),它們之間通過(guò)Android的IPC機(jī)制Binder來(lái)協(xié)助完成,如圖3所示。
在Binder中,主要包括兩個(gè)方面:本地(native),如BnSurfaceFlingerClient,這是一個(gè)需要被繼承和實(shí)現(xiàn)的類(lèi);代理(proxy),如 BpSurfaceFlingerClient,這是一個(gè)在接口框架中被實(shí)現(xiàn),但是在接口中沒(méi)有體現(xiàn)的類(lèi)。在客戶端中,BpSurfaceFlingerClient被調(diào)用,通過(guò)與BnSurfaceFlinger-Client通信,而 BpSurfaceFlingerClient和 BnSurfaceFlinger-Client派生自 ISurfaceFlingerClient,BClient派生自 BnSurface-FlingerClient。
在客戶端中通過(guò)類(lèi)SurfaceComposerClient,調(diào)用BnSurfaceComposer和BnSurface來(lái)響應(yīng)服務(wù)端BpSurface-Composer和BpSurface,并通過(guò)調(diào)用 BpSurfaceFlingerClient來(lái)調(diào)用服務(wù)端的BnSurfaceFlingerClient,由此完成了客戶端和服務(wù)端的交互。在交互中的3個(gè)接口分別介紹如下。
ISurfaceFlingerClient:派生出BpSurfaceFlingerClient和BnSurfaceFlingerClient,由 BClient實(shí)現(xiàn),通過(guò)調(diào)用createSurface函數(shù)創(chuàng)建一個(gè)Surface供Application應(yīng)用。
ISurface:派生出BpSurface和BnSurface,主要完成對(duì)Surface的處理,在 Surface(派生自 BnSurface)的函數(shù) lock、unlockAndPost等,實(shí)現(xiàn)了Surface在雙緩沖的處理,SurfaceBuffer(派生自Surface)實(shí)現(xiàn)了Layer上的處理。
IS urfaceComposer:派生出BpSurfaceComposer和BnSurfaceComposer,SurfaceFlinger(派生自BnSurface Composer)主要為合成器SurfaceFlinger(Surface Manager的組成部分)對(duì)Surface合成的相關(guān)處理提供實(shí)現(xiàn)方法。
在Android平臺(tái)中,雙緩沖技術(shù)分別在Surface的處理和底層Framebuffer的處理中使用到,在對(duì)Framebuffer處理的雙緩沖技術(shù)根據(jù)OpenGL的標(biāo)準(zhǔn)實(shí)現(xiàn),而對(duì)Surface處理的雙緩沖技術(shù)則有所不同,下面將對(duì)兩種雙緩沖技術(shù)進(jìn)行比較。
在OpenGL中利用雙緩沖技術(shù),分配兩個(gè)幀緩沖區(qū),在連續(xù)顯示三維曲面時(shí),一個(gè)幀緩沖區(qū)中的數(shù)據(jù)執(zhí)行繪制曲面命令的同時(shí),另一個(gè)幀緩沖區(qū)中的數(shù)據(jù)進(jìn)行圖形顯示。當(dāng)前可見(jiàn)視頻緩沖稱為前臺(tái)視頻緩沖,不可見(jiàn)的、正在繪圖的視頻緩沖稱為后臺(tái)視頻緩沖。當(dāng)后臺(tái)視頻幀緩沖中的數(shù)據(jù)要求顯示時(shí),OpenGL就將它拷貝到前臺(tái)視頻幀緩沖,顯示硬件不斷地讀可見(jiàn)視頻緩沖中的內(nèi)容,并把結(jié)果顯示在屏幕上。應(yīng)用雙緩沖,每一幀三維曲面只在繪制完成后才顯示出來(lái),所以觀察者可以看到每一幀完整三維曲面,而不是曲面的繪制過(guò)程。
每個(gè)Surface中都帶有兩個(gè)幀緩沖區(qū),分別稱為Front Buffer和Back Buffer,與OpenGL中雙緩沖技術(shù)有所不同,當(dāng)繪制Back Buffer后需要顯示時(shí),并沒(méi)有將Back Buffer中的數(shù)據(jù)拷貝到Front Buffer中,而是直接顯示Back Buffer中的數(shù)據(jù)到屏幕中,從而最大限度地減少了數(shù)據(jù)的復(fù)制。
圖4是使用Canvas繪制Surface的原理,具體過(guò)程如下:
·創(chuàng)建一個(gè)bitmap與Canvas關(guān)聯(lián)起來(lái);
·把準(zhǔn)備顯示的圖形提交到Canvas上;
· lockCanvas,鎖定 Canvas;
·drawCanvas,把bitmap中的數(shù)據(jù)寫(xiě)入到Back Buffer中;
· unlockCanvasAndPost,解鎖 Canvas,Back Buffer替換Front Buffer,替換后Back Buffer作為前臺(tái)緩沖,F(xiàn)ront Buffer作為后臺(tái)緩沖。
OpenGL/ES為附加功能和可能的平臺(tái)特性開(kāi)發(fā)了擴(kuò)展機(jī)制,但仍然需要一個(gè)可以讓OpenGL/ES和本地視窗系統(tǒng)交互且平臺(tái)無(wú)關(guān)的層。EGL是OpenGL/ES和底層Native平臺(tái)視窗系統(tǒng)之間的接口,是為OpenGL/ES提供平臺(tái)獨(dú)立性而設(shè)計(jì)。OpenGL/ES本質(zhì)上是一個(gè)圖形渲染管線的狀態(tài)機(jī),而EGL則是用于監(jiān)控這些狀態(tài)以及維護(hù)Frame Buffer和其他渲染Surface的外部層。
在Android的底層源代碼中,egl_native_window_t是一個(gè)提供了對(duì)本地窗口的所有定義以及用于EGL操作本地窗口的所有方法的類(lèi)。EGLNativeSurface派生自egl_native_window_t,EGLDisplaySurface派生自 EGLNativeSurface。EGLDisplay-Surface通過(guò)函數(shù) mapFrameBuffer打開(kāi) Framebuffer設(shè)備,并創(chuàng)建兩個(gè)緩沖區(qū),函數(shù)swapBuffer把后臺(tái)視頻緩沖區(qū)復(fù)制到前臺(tái)視頻緩沖區(qū)。DisplayHardware類(lèi)中初始化了EGL,SurfaceFlinger使用了DisplayHardware去和本地窗口打交道。
Android是基于Linux的,但在Linux的幀緩沖驅(qū)動(dòng)中并沒(méi)有直接支持雙緩沖,修改驅(qū)動(dòng)包括兩個(gè)方面:一是劃分兩個(gè)緩沖區(qū);二是添加緩沖區(qū)的切換功能。本文是在PXA270上進(jìn)行研究的,對(duì)應(yīng)的驅(qū)動(dòng)文件是/drivers/video/pxafb.c。
在Android中,double buffer設(shè)計(jì)成上下兩個(gè)buffer的模式,在函數(shù) pxafb_setmode()“var->yres_virtual=var->yres”修改為“var->yres_virtual=var->yres*2”,在檢查參數(shù)的函數(shù)pxafb_check_var()中“var->yres_virtual=max(var->yres_virtual,var->yres)”修 改 為 “var->yres_virtual=max(var->yres_virtual,var->yres*2)”。相對(duì)應(yīng)的緩沖長(zhǎng)度也要修改為默認(rèn)的兩邊,即在函數(shù)pxafb_decode_mode_info()中添加“smemlen*=2;”。
當(dāng)一個(gè)緩沖區(qū)已寫(xiě)好,在切換時(shí)就需要調(diào)用到pan函數(shù),該函數(shù)將一個(gè)新的yoffset傳給LCD控制器。在結(jié)構(gòu)體fb_ops pxafb_ops中添加pan函數(shù),即插入“.fb_pan_display=pxafb_pan_display,”到fb_ops pxafb_ops中。在初始化幀緩沖的函數(shù)pxafb_init_fbinfo()中,將“fbi->fb.fix.ypanstep=0;”修改為“fbi->fb.fix.ypanstep=1;”,這里是說(shuō)明驅(qū)動(dòng)需要用到pan函數(shù)。以下是需要添加或修改的函數(shù)。
對(duì)Android的應(yīng)用開(kāi)發(fā)來(lái)說(shuō),圖形開(kāi)發(fā)是其中一個(gè)主要工作,了解Android圖形系統(tǒng)的工作原理可以對(duì)應(yīng)用程序性能上的提供有所幫助。在Android移植到其他嵌入式設(shè)備中,Android圖形系統(tǒng)的底層驅(qū)動(dòng)移植是其中一個(gè)關(guān)鍵部分,通過(guò)對(duì)底層圖形接口以及對(duì)幀緩沖驅(qū)動(dòng)移植的研究,將更有效地實(shí)現(xiàn)Android在其他嵌入式設(shè)備上的移植。
1 宋寶華.Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)詳解.北京:人民郵電出版社,2008
2 姚昱旻,劉衛(wèi)國(guó).Android的架構(gòu)與應(yīng)用開(kāi)發(fā)研究.計(jì)算機(jī)系統(tǒng)應(yīng)用,2008(11)
3 Patrick Brady.Anatomy&Physiology of an Android.http://sites.google.com/site/io/anatomy--physiology-of-an-android
4 David Blythe,Affie Munshi.OpenGL ES 1.0.02 Specification.http://www.khronos.org/registry/gles/specs/1.0/opengles_spec_1_0.pdf