江 帆,賀也平,周啟明
(中國科學(xué)院 軟件研究所 基礎(chǔ)軟件國家工程研究中心,北京 100190)
SurfaceFlinger在X Window系統(tǒng)環(huán)境下的運行方案①
江 帆,賀也平,周啟明
(中國科學(xué)院 軟件研究所 基礎(chǔ)軟件國家工程研究中心,北京 100190)
本文給出一種將Android圖形系統(tǒng)SurfaceFlinger移植到桌面Linux發(fā)行版的X Window系統(tǒng)環(huán)境下運行的方案.在X Window系統(tǒng)環(huán)境下運行的SurfaceFlinger可使Android運行環(huán)境中以本地進(jìn)程形式的Android應(yīng)用進(jìn)程的UI界面顯示到X Window的窗口中.使用Mesa作為OpenGL ES實現(xiàn)并使Mesa EGL兼容Android的本地窗口ANativeWindow,同時借助Androidx86的gralloc.drm.so模塊,實現(xiàn)了Android應(yīng)用程序的UI渲染過程SurfaceFlinger的圖像合成過程能夠使用GPU進(jìn)行硬件加速.另外,用X11的DRI2擴(kuò)展協(xié)調(diào) SurfaceFlinger的窗口和X Server的DDX驅(qū)動,使合成后的圖像能高效地更新到窗口中,避免了SurfaceFlinger的圖像緩存由獨立顯存到系統(tǒng)內(nèi)存的拷貝過程.經(jīng)實驗,在本移植方案下,第三方3D基準(zhǔn)測試軟件San-Angeles能達(dá)到60FPS的幀率.相比于已有方案,本方案的架構(gòu)更加簡潔高效,且支持硬件加速.
Android圖形系統(tǒng); SurfaceFlinger; X Window系統(tǒng); 移植; 兼容環(huán)境
Android運行環(huán)境可以使數(shù)量眾多的Android應(yīng)用程序不經(jīng)修改即可在桌面Linux系統(tǒng)上以本地進(jìn)程的形式運行,這對于原本應(yīng)用資源匱乏的桌面Linux系統(tǒng)來說是一個很好的補(bǔ)充[1].而使Android的圖形系統(tǒng)SurfaceFlinger在桌面Linux系統(tǒng)上運行是構(gòu)建Android運行環(huán)境的重要環(huán)節(jié).SurfaceFlinger的主要功能是將應(yīng)用窗口和系統(tǒng)窗口合成一幀完整畫面并提交到屏幕顯示.張超等[2]成功地實現(xiàn)SurfaceFlinger在桌面Linux的X Window環(huán)境下運行.其主要方法是利用軟件渲染的方法方式將SurfaceFlinger合成的圖像寫入共享內(nèi)存,再由一個桌面圖形程序輸出畫面.該方法的不足是使用軟件渲染而沒有調(diào)用GPU實現(xiàn)硬件加速,造成占用大CPU時間,并且畫面輸出過程需要不斷調(diào)用IPC,在處理3D圖形時只有個位數(shù)的幀數(shù),性能十分低下.
提高圖形系統(tǒng)性能的思路是使用GPU進(jìn)行硬件渲染而非使用CPU進(jìn)行軟件渲染.arm架構(gòu)和x86架構(gòu)在圖形系統(tǒng)方面存在較大差異.具體表現(xiàn)為arm架構(gòu)下的GPU沒有獨立顯存,所有程序的圖像緩存都位于系統(tǒng)內(nèi)存,而在x86的Linux內(nèi)核之上,需要使用DRI框架來調(diào)用GPU,并且GPU有自己的獨立顯存[3].而面向arm架構(gòu)設(shè)計的SurfaceFlinger的源碼即使能面向x86架構(gòu)編譯,也不能直接在x86架構(gòu)的Linux內(nèi)核之上運行.另一方面,SurfaceFlinger在自己的圖像緩存上合成好的畫面幀需要提交到X Window的窗口中顯示.因此,要實現(xiàn)SurfaceFlinger在X Window系統(tǒng)環(huán)境下運行,需要解決的問題主要有兩個:1)使Android應(yīng)用程序的UI渲染過程和SurfaceFlinger的圖像合成過程能夠在x86架構(gòu)的Linux內(nèi)核之上進(jìn)行硬件加速;2)使SurfaceFlinger的圖像緩存能夠顯示在X Window的窗口中.
從OpenGL ES的角度來看Android應(yīng)用程序的UI渲染過程和SurfaceFlinger的圖像合成過程,Android應(yīng)用程序和SurfaceFlinger都可以看作是OpenGL ES的應(yīng)用程序.因此首先需要一種能在x86 架構(gòu)下使用的OpenGL ES的實現(xiàn)作為GPU驅(qū)動.Androidx86項目在讓Android系統(tǒng)在x86架構(gòu)的PC上運行做出了重要貢獻(xiàn)[4].該項目使用Mesa[5]作為OpenGL ES實現(xiàn),并基DRM[6]和GEM[7]實現(xiàn)了gralloc.drm.so模塊,成功地使SurfaceFlinger在x86架構(gòu)下運行并實現(xiàn)硬件加速.但是該項目的目標(biāo)是在x86架構(gòu)下運行完整的Android系統(tǒng),因此其運行時會占用整個顯示屏,并不能實現(xiàn)在桌面Linux的圖形系統(tǒng)X Window的環(huán)境下獨立運行SurfaceFlinger程序.本文以Mesa作為OpenGL ES實現(xiàn),借用Androidx86的擴(kuò)展的Mesa EGL的DRI驅(qū)動實現(xiàn)對Android本地窗口ANativeWindow的支持,并使用gralloc.drm.so進(jìn)行圖像緩存的申請,成功實現(xiàn)了基于硬件加速的Android應(yīng)用程序UI渲染.對于SurfaceFlinger將畫面提交到窗口顯示的過程,首先SuracefFlinger需要有自己的窗口.其次使用gralloc.drm.so直接通過內(nèi)核DRM模塊申請的顯存無法和Surface-Flinger的窗口進(jìn)行內(nèi)在綁定.本文使用X11的DRI2擴(kuò)展協(xié)調(diào)SurfaceFlinger的圖像緩存和窗口,有效避免了SurfaceFlinger圖像緩存由GPU獨立顯存到系統(tǒng)內(nèi)存的拷貝,使得SurfaceFlinger的窗口畫面更新過程更加流暢.
本文余下章節(jié)的結(jié)構(gòu)如下.第1節(jié),以Android應(yīng)用程序UI渲染到SurfaceFlinger合成的畫面在窗口中顯示的過程為線索,分析整體架構(gòu)的運作流程.第2節(jié),為更好地理解系統(tǒng)架構(gòu)的原理,分析Android應(yīng)用程序UI渲染過程中涉及到的關(guān)鍵組件.第3節(jié),在不考慮X Window系統(tǒng)的情況下,討論Android應(yīng)用程序和SurfaceFlinger如何在x86的架構(gòu)下運行并支持硬件加速.第4節(jié),給出SurfaceFlinger和X Window系統(tǒng)兼容的關(guān)鍵技術(shù)和進(jìn)一步的優(yōu)化方案.第5節(jié),給出并分析移植方案在各型GPU上運行的實驗結(jié)果.第6節(jié),結(jié)語.
圖1描述了SurfaceFlinger移植到X Window環(huán)境下的架構(gòu).序號1至19描述了從Actitity的UI渲染到畫面最終提交到窗口的完整過程.整個系統(tǒng)運行于開啟了Binder驅(qū)動的x86架構(gòu)的Linux內(nèi)核之上./dev/binder和/dev/dri/card0分別為Binder IPC和DRM內(nèi)核子系統(tǒng)的設(shè)備文件.
App的UI使用硬件渲染路徑(1~6).軟件渲染調(diào)用CPU在系統(tǒng)內(nèi)存上進(jìn)行計算,這樣會占用大量CPU時間,性能低下.因此從OpenGL ES的角度來看,所有App都是OpenGL ES的應(yīng)用程序.App的圖像緩存通過EGL向Surface申請.Android的本地窗口是BufferQueue(由 producer和 consumer組成)的 wrapper,因此Surface拿到的圖像緩存是從BufferQueue申請的GraphicBuffer.GraphicBuffer包含的圖像緩存的實際句柄則是通過gralloc.drm.so調(diào)用libdrm向內(nèi)核的GEM模塊申請的.
SurfaceFlinger同樣擁有自己的Surface,但是它的圖像緩存則是通過xwindow.default.so調(diào)用X11的DRI2擴(kuò)展向X Server的DDX驅(qū)動申請的,而非直接調(diào)用libdrm向內(nèi)核申請.這樣可使SurfaceFlinger圖像緩存的GEM句柄和SurfaceFlinger自己的窗口在X Server端產(chǎn)生內(nèi)在綁定.
圖1 系統(tǒng)架構(gòu)
當(dāng)一個Activity的一幀畫面渲染好以后,就通過BufferQueue經(jīng)Binder IPC機(jī)制將GraphicBuffer提交到SurfaceFlinger中(7~8).GraphicBuffer支持序列化,因此可以通過Binder傳遞.每個Surface對應(yīng)Surface-Flinger中的一個Layer.當(dāng)一個由EventThread發(fā)處的VSync同步信號到來時,SurfaceFlinger就會調(diào)用OpenGL ES將這些Layer合成為一幀畫面(9~10).SurfaceFlinger同樣需要有自己的本地窗口Surface來承載這一幀合成好的圖像.在INVALIDATE_ON_VSYNC宏置為1時,在Surface緩存更新的同時發(fā)起一個畫面更新.
因為桌面上沒有硬件HWComposer,因此Surface-Flinger的畫面合成過程是基于OpenGL ES完成的,而hwcomposer.x86.so只是一個符合HWComposer 1.0 接口標(biāo)準(zhǔn)的軟件實現(xiàn),并不是硬件HWComposer的驅(qū)動程序.它的set()接口僅調(diào)用了EGL層的eglSwapBuffers()函數(shù)進(jìn)行前后臺圖像緩存更新,eglSwapBuffers()再調(diào)用Surface的queueBuffer()將一個GraphicBuffer通過BufferQueuer傳給了同位于SurfaceFlinger進(jìn)程中的作為consumer的 FrameBufferSurface對象(11~14).FrameBufferSurface接下來通過gralloc.drm.so將這個渲染好的GraphicBuffer提交到窗口.
在HAL層中基于Xlib和X11的DRI2擴(kuò)展實現(xiàn)了xwindow.default.so模塊.SurfaceFlinger通過該模塊和X Server通信,并創(chuàng)建屬于SurfaceFlinger自己的窗口.gralloc.drm.so將這個渲染好的GraphicBuffer提交到窗口的過程由xwindow.default.so調(diào)用X11的DRI2擴(kuò)展的pageflip功能完成(15~19).
本項目基于源碼分支android-5.1.1_r9開發(fā).后續(xù)章節(jié)中關(guān)于Android圖形系統(tǒng)的分析以該版本為基準(zhǔn).
為理解移植后的系統(tǒng)架構(gòu)如何運作,我們以Android應(yīng)用程序UI渲染到圖像呈現(xiàn)在屏幕的過程為線索,分析該過程中涉及的一些Android圖形系統(tǒng)的關(guān)鍵組件.
要讓SurfaceFlinger在X Window環(huán)境下運行,我們首先需要了解在arm架構(gòu)下Android系統(tǒng)中App的UI是如何渲染和顯示到屏幕的以及SurfaceFlinger在這個過程起到的作用.App的UI界面的渲染方式分為2D和3D兩種.進(jìn)行2D渲染的方式包括:1)調(diào)用Canvas的drawRect(),drawText()等方法將像素點繪制到一個Bitmap; 2)View的子類繪制Button、List等空間; 3)或一個定制的View類實現(xiàn)開發(fā)者自己定義的行為等.2D渲染有兩條路徑,一是使用hwui的基于OpenGL ES2.0的硬件渲染,一種是使用Skia軟件渲染引擎的軟件渲染.Android的UI繪制也支持硬件加速,這時Activity會創(chuàng)建一個GLSurfaceView并且使用OpenGL ES的Java綁定接口(android.opengl.*)進(jìn)行畫面渲染.AOSP中提供的libEGL.so、libGLESv1_CM.so、libGLESv2.so、libGLESv3.so只是EGL和OpenGL ES實現(xiàn)的wrapper,底下真正調(diào)用的是由供應(yīng)商提供的閉源專屬GPU驅(qū)動或Android自己實現(xiàn)的軟件GPU模擬PixelFlinger.但是不論是2D渲染還是3D渲染,最終的渲染結(jié)果的所有像素點都位于該Activity的Surface之上.
SurfaceFlinger是Android的窗口合成器.它和App的Surface構(gòu)成了C/S架構(gòu).一個完整的屏幕界面實際上是由多個窗口(包括導(dǎo)航條、狀態(tài)條和應(yīng)用UI)合成后的結(jié)果.每個窗口分別屬于不同的進(jìn)程,由這些進(jìn)程獨立渲染在自己的Surface之上.每個Surface對應(yīng)SurfaceFlinger中的一個Layer,這些Layer通過z軸順序排列起來.SurfaceFlinger基于OpenGL ES的API將這些Layer合成一幀完整的畫面.
Surface和SurfaceFlinger構(gòu)成C/S架構(gòu).Buffer-Queue是Surface和SurfaceFlinger之間進(jìn)行Graphic-Buffer交換的通道.App從Surface獲取新的Graphic-Buffer并將繪制好的GraphicBuffer通過Buffer-Queue傳遞給 SurfaceFlinger,而 SurfaceFlinger從BufferQueue接收渲染好的GraphicBuffer用于下一幀的畫面合成,同時將新的GraphicBuffer放入BufferQueue傳遞給App的Surface.
gralloc是Android HAL層定義的圖形緩存分配器.在BufferQueue中傳遞的GraphicBuffer對象通過gralloc獲取實際的圖像緩存描述句柄.gralloc的圖形緩存申請接口alloc()接收width,height,pixel format以及usage flags等參數(shù).App和SurfaceFlinger使用圖像緩存的目的不同,App是為了渲染UI畫面并傳遞給SurfaceFlinger進(jìn)行圖形合成,而SurfaceFlinger要在自己的圖像緩存上合成最終畫面并提交到屏幕顯示.因此它們申請圖像緩存的類型也不一樣,具體表現(xiàn)為usage flags參數(shù)的區(qū)別.SurfaceFlinger是GRALLOC_-USAGE_HW_FB,而App的則是其他類型.因此,需要在App和SurfaceFlinger之間傳遞的App的圖像緩存是從Ashmem申請的共享內(nèi)存,而SurfaceFlinger的圖像緩存則是Framebuffer.但在arm架構(gòu)下,兩者實際上都位于系統(tǒng)內(nèi)存之上.App的畫面渲染完成時會通過Ashmem共享內(nèi)存換地給SurfaceFlinger,而Surface-Flinger在畫面合成完畢時會調(diào)用Framebuffer的pageflip機(jī)制將新生成的畫面更新到屏幕顯示.
本地窗口是EGL中的概念,EGL為了保證OpenGL ES的平臺獨立性,需要適應(yīng)各種操作系統(tǒng)下的本地窗口.ANativeWindow是Android系統(tǒng)定義的本地窗口,也是EGL的Android平臺適配窗口,其中定義了獲取和釋放圖像緩存的接口.圖像緩存用ANative-WindowBuffer其定義,它描述了窗口的基本信息如寬度、高度、像素格式等基本信息.實際圖像緩存的地址和句柄buffer_handle_t結(jié)構(gòu)體描述.Surface是應(yīng)用層次的本地窗口,不論是App還是SurfaceFlinger,Android上的所有圖形程序都需要有自己的Surface,而Surface的作用就是給EGL層提供ANativeWindow的接口.上層應(yīng)用即可通過這些接口獲取和釋放圖像緩存.
要讓SurfaceFlinger能在X Window的環(huán)境下運行,首先要解決的問題是如何讓SurfaceFlinger在x86架構(gòu)的Linux內(nèi)核之上運行.Androidx86項目很好地解決了SurfaceFlinger在x86架構(gòu)下運行的問題.Android系統(tǒng)主要是為arm架構(gòu)設(shè)計的,arm架構(gòu)下的GPU沒有自己的獨立顯存,SurfaceFlinger通過Surface申請的的Framebuffer硬件緩存仍然是系統(tǒng)內(nèi)存的一部分.而x86架構(gòu)下,GPU有自己的專屬獨立圖顯存.SurfaceFlinger本身基于OpenGL ES實現(xiàn),要使用x86架構(gòu)的GPU進(jìn)行硬件加速,就需要有可以在x86架構(gòu)下運行的OpenGL ES實現(xiàn).因此Androidx86項目在圖形系統(tǒng)方面的主要工作有兩點:1)使用Mesa作為OpenGLES實現(xiàn); 2)實現(xiàn)了gralloc.drm.so.
DRI是一個使應(yīng)用程序在X Window系統(tǒng)的環(huán)境下直接發(fā)訪問圖形硬件的框架.其實現(xiàn)分散在X Server和它的客戶端共享庫Xlib、Mesa以及DRM內(nèi)核子系統(tǒng)中[8].Mesa在DRI框架中扮演了GPU驅(qū)動的角色,因此Androidx86選擇Mesa作為OpenGL ES的實現(xiàn).但是Mesa默認(rèn)只支持X Window系統(tǒng)的本地窗口,而不支持Android的本地窗口ANativeWindow.在Mesa的架構(gòu)中,EGL是OpenGL ES和本地窗口之間的一個中間層,其作用之一是保證OpenGL ES的平臺獨立性.因此Androidx86在Mesa EGL中添加了對ANative-Window的支持(platform_android.c),使得Mesa可以通過Surface獲取ANativeWindow.因此本文中借用Android對Mesa EGL的擴(kuò)展實現(xiàn)對Android本地窗口的支持.
在X Window環(huán)境下,一個桌面OpenGL ES程序的圖像緩存是由Mesa EGL的DRI驅(qū)動(platform_x11.c)借用X11的DRI2擴(kuò)展通過X Server的DDX驅(qū)動向內(nèi)核申請的.而在Android系統(tǒng)中,實際圖像緩存申請操作是由GraphicBuffer類調(diào)用HAL層的gralloc完成的.在arm架構(gòu)下,gralloc為應(yīng)用申請的圖像緩存來自Ashmem共享內(nèi)存,而為SurfaceFlinger申請的圖像緩存來自Framebuffer,這些圖像緩存本身都位于系統(tǒng)內(nèi)存,而Mesa無法基于系統(tǒng)內(nèi)存調(diào)用GPU進(jìn)行硬件加速.這一點也從側(cè)面說明文獻(xiàn)[2]中的移植方法不支持硬件加速.gralloc.drm.so基于libdrm,實現(xiàn)了從x86架構(gòu)的獨立顯存為應(yīng)用程序和SurfaceFlinger申請圖像緩存.libdrm是內(nèi)核DRM子系統(tǒng)的用戶態(tài)共享庫,應(yīng)用程序可以通過libdrm調(diào)用內(nèi)核的GEM模塊來創(chuàng)建圖像緩存對象,在用戶態(tài)使用一個GEM句柄(本質(zhì)是一個整數(shù))作為圖像緩存的引用.因此在arm架構(gòu)下,buffer_handle_t包含的是圖像緩存的首地址,而在x86架構(gòu)下包含的則是GEM句柄.這時,在Androidx86系統(tǒng)中,不論是App還是SurfaceFlinger,通過graloc.drm.so申請圖像緩存的過程是一樣的,并不會因為alloc()接口的usage flags參數(shù)不同而不同.另一方面,在Androidx86環(huán)境下,SurfaceFlinger會占用整個屏幕作為其畫面輸出的目標(biāo).這樣無法和桌面Linux發(fā)行版的X Window系統(tǒng)兼容.因此,要讓SurfaceFlinger的合成畫面在X Window系統(tǒng)的窗口中顯示,就需要將SurfaceFlinger的角色由Android窗口合成器降級為X Window系統(tǒng)的應(yīng)用程序.
X Window系統(tǒng)是桌面Linux系統(tǒng)的標(biāo)準(zhǔn)圖形系統(tǒng)[9].它采用C/S架構(gòu),客戶端程序基于Xlib和X Server通過TCP連接通信,如果客戶端程序和X Server位于統(tǒng)一系統(tǒng)上,則使用IPC通信.因為X Window系統(tǒng)為分布式環(huán)境而設(shè)計,客戶端程序通過Xlib向X Server申請的資源(例如一個窗口)位于X Server中,客戶端程序只能拿到該資源的一個整數(shù)ID作為引用.
在Androidx86中,SurfaceFlinger在初始化時直接作為DRM Master,進(jìn)行KMS設(shè)置,這樣會與X Server發(fā)生沖突.因為在一個桌面Linux系統(tǒng)中只允許有一個DRM Master.在畫面需要更新到屏幕是直接調(diào)用drm的pageflip機(jī)制進(jìn)行屏幕畫面刷新,并且Surface-Flinger合成的畫面會顯示到整個屏幕上.現(xiàn)在我們要讓SurfaceFlinger在X Window系統(tǒng)的環(huán)境下運行,具體而言是讓SurfaceFlinger將更新后的圖像緩存提交到一個窗口中顯示.
首先SurfaceFlinger需要有自己的窗口,此時SurfaceFlinger需要調(diào)用X Window的客戶端共享庫,而采用NDK編譯的SurfaceFlinger的ELF文件無法使用桌面Linux的默認(rèn)動態(tài)鏈接器和已安裝的Xlib共享庫[1].因此需要將Xlib的源碼轉(zhuǎn)換為Android項目并使用NDK進(jìn)行編譯,并基于移植的Xlib在HAL實現(xiàn)了xwindow.default.so模塊.SurfaceFlinger即可使用xwindow.default.so模塊創(chuàng)建自己的窗口.
當(dāng)SurfaceFlinger需要將自己的Surface中的最新的GraphicBuffer提交窗口時,在SurfaceFlinger進(jìn)程中已有兩個資源,一是通過GraphicBuffer的buffer_handle_t中獲取的圖像緩存標(biāo)識GEM句柄,一是標(biāo)識窗口的整數(shù)ID.一個直觀的方法是利用libdrm將GEM句柄描述的圖像緩存映射到系統(tǒng)內(nèi)存空間,將這段空間封裝成XImage最后通過Xlib提交到X Server顯示.
XImage和Pixmap的區(qū)別是前者位于客戶端進(jìn)程而后者位于X Server進(jìn)程.XImage是一個結(jié)構(gòu)體,包含了位圖的各種格式、大小等信息,同時還有一個指針指向像素數(shù)據(jù)所在的內(nèi)存地址.所以我們可以根據(jù)圖像緩存在系統(tǒng)內(nèi)存空間的映射來構(gòu)造這個XImage,然后讓這個XImage顯示在SurfaceFlinger的窗口中.這個XImage最終要通過Xlib傳給X Server,由X Server顯示出來.但不論是TCP連接還是IPC機(jī)制,傳遞大塊內(nèi)存的效率較低.所以我們使用了X11的共享內(nèi)存擴(kuò)展MIT-SHM[10].這樣,XImage就可以通過共享內(nèi)存?zhèn)鬟f給X Server.相比于文獻(xiàn)[2]的架構(gòu),本架構(gòu)下畫面更新頻率由HWComposer中用于模擬硬件VSync信號的VSyncThread的信號頻率決定(一般為60FPS,和顯示屏刷新率保持一致),而不需要額外的同步信號控制,也不需要額外的圖像顯示進(jìn)程,因此總體架構(gòu)更為簡潔.
在各種GPU上測試時發(fā)現(xiàn),只有在Intel集成顯卡上畫面刷新頻率能達(dá)到60FPS,而Nvidia和AMD獨立顯卡上畫面十分卡頓.在上述移植方案中,App和SurfaceFlinger從Surface獲取的圖像緩存都是通過libdrm向內(nèi)核的GEM模塊申請的,因此基于Mesa的App的UI渲染過程和SurfaceFlinger的畫面合成過程是使用GPU進(jìn)行硬件加速的.問題在于將GEM句柄標(biāo)識的圖像緩存映射到系統(tǒng)內(nèi)存空間并封裝到XImage的過程需要將圖像緩存從獨立顯存讀取到系統(tǒng)內(nèi)存,這個過程的延遲較大.在該方法下,每次畫面更新都需要拷貝一次,因此拖慢了畫面刷新頻率.
優(yōu)化的思路來自于對桌面上基于Mesa的圖形程序架構(gòu)的思考.基于X Window系統(tǒng)的圖形程序申請圖像緩存是由X Server端的DDX驅(qū)動完成的,本質(zhì)仍然是通過libdrm調(diào)用GEM內(nèi)核模塊創(chuàng)建顯存對象.而桌面上基于Mesa的圖形程序調(diào)用eglSwapBuffers()進(jìn)行畫面更新時,EGL的DRI驅(qū)動并沒有將圖像緩存拷貝到系統(tǒng)內(nèi)存,但是畫面仍然能在一個由X Window系統(tǒng)創(chuàng)建的窗口中更新.因此桌面Linux上基于Mesa的圖形程序的圖像緩存的申請和更新是由Mesa和X Window協(xié)同完成的.其原理在于,在DRI架構(gòu)中,X Server提供X11協(xié)議的DRI2擴(kuò)展,用于DRI客戶端進(jìn)行窗口系統(tǒng)和DDX驅(qū)動的協(xié)調(diào)[8,11].因此,在上文移植方案的基礎(chǔ)上需要做兩點改進(jìn):1)在gralloc.drm.so中區(qū)分App和SurfaceFlinger圖像緩存申請方式,App直接使用libdrm向內(nèi)核GEM模塊申請,而Surface-Flinger使用DRI2擴(kuò)展接口通過DDX驅(qū)動申請; 2)SurfaceFlinger進(jìn)行畫面更新時不再直接使用DRM的pageflip接口,而使用DRI2擴(kuò)展的緩存交換接口.這樣就不需要將SurfaceFlinger的圖像緩存拷貝到系統(tǒng)內(nèi)存了,因此是一種完全支持硬件加速的架構(gòu).
系統(tǒng)性能測試方法是運行一個以Surface為本地窗口的Android OpenGL ES圖形程序,測量其在一段時間內(nèi)的平均幀率(FPS).同時測量該程序的CPU負(fù)載.采用San Angeles Observation作為基準(zhǔn)測試軟件,后文簡稱Angeles.Angeles基于OpenGL ES1.0實現(xiàn),每次運行約109秒,結(jié)束后會自動給出該時間內(nèi)的總幀數(shù)和幀率.系統(tǒng)部署平臺選取了三臺GPU分別由Intel、Nvidia和AMD制造的PC.三臺PC均運行Linux Mint 17.3操作系統(tǒng),并使用開啟了Binder驅(qū)動的版本號為4.2.6的Linux內(nèi)核.各PC的關(guān)鍵硬件參數(shù)如表1所示.實驗方案是以800*480、1280*720 兩種分辨率大小的窗口,分別在各PC以優(yōu)化前和優(yōu)化兩種架構(gòu)運行Angeles程序,并采集運行期間Surface-Flinger和Angeles的CPU占用情況.
表1 測試主機(jī)關(guān)鍵參數(shù)
從表2和表3可以看出,不論是在哪種分辨率下,優(yōu)化前只有PC1的幀率能到達(dá)60FPS的速度,PC2和PC3的幀率均小于30FPS.幀率低于30FPS時人眼便能覺察到畫面的卡頓感.原因在于Intel集顯沒有獨立顯存,而是共享系統(tǒng)內(nèi)存,因此每次將顯存拷貝是由系統(tǒng)內(nèi)存的一個地址拷貝到另一個地址,該過程的速度很快,不會拖慢圖像更新頻率.而在PC2和PC3上,顯存的拷貝需要從GPU獨顯拷貝到系統(tǒng)內(nèi)存,此過程耗時較長,拖慢了SurfaceFlinger的畫面更新速率.另一方面,觀察兩種分辨率下的優(yōu)化前的PC2和PC3的幀率變化,發(fā)現(xiàn)分辨率越大,幀率越小,其原因在于分辨率越大,需要拷貝的顯存越大,拷貝時間越長.
表2 圖形性能測試結(jié)果(800*480)
表3 圖形性能測試結(jié)果(1280*720)
優(yōu)化后,在800*480分辨率時,三臺PC均能達(dá)到60FPS幀率,畫面十分流暢.只有在1280*720時,PC2的幀率低于60FPS,其原因是PC2的GPU性能較弱.優(yōu)化后的運行幀率和CPU負(fù)載均優(yōu)于張超等人[2]的實驗結(jié)果.
從SurfaceFlinger(S)和Angeles(A)的CPU負(fù)載的變化情況分析,不論在哪種分辨率下,優(yōu)化后相較于優(yōu)化前,SurfaceFlinger的CPU負(fù)載降低且均低于2%,而Angeles的CPU負(fù)載升高.原因在于,優(yōu)化前,Surface-Flinger的顯存拷貝過程需要占用大量CPU時間,拖慢了畫面更新速率.在BufferQueue另一端的Angeles程序需要等待SurfaceFlinger交出空閑的GraphicBuffer才能進(jìn)行下一幀的渲染,CPU負(fù)責(zé)也較低.優(yōu)化后,SurfaceFlinger的畫面更新時沒有了圖像緩存的拷貝過程,SurfaceFlinger本身不再是瓶頸,而Angeles在渲染完一幀畫面后可以立即從BufferQueue獲取一個空閑的GraphicBuffer.因此造成這種變化.
使Android的圖形系統(tǒng)SurfaceFlinger能夠在桌面Linux發(fā)行版的X Window系統(tǒng)的環(huán)境下運行,是構(gòu)建Android桌面運行環(huán)境的重要環(huán)節(jié).本文給出了一種簡潔高效的移植方案.使用Mesa作為OpenGL ES實現(xiàn),并借助gralloc.drm.so模塊,實現(xiàn)了Android應(yīng)用程序的UI渲染過程和SurfaceFlinger的圖像合成過程能夠使用GPU進(jìn)行硬件加速.同時,使用X11的DRI2擴(kuò)展協(xié)調(diào)SurfaceFlinger的窗口和X Server的DDX驅(qū)動,實現(xiàn)了窗口畫面的快速更新,且避免了SurfaceFlinger圖像緩存由獨立顯存到系統(tǒng)內(nèi)存的拷貝過程.經(jīng)實驗,本移植方案能基于各型GPU進(jìn)行硬件加速,圖形性能相較于已有方案有顯著提升.
1張超.面向桌面Linux的Android運行環(huán)境構(gòu)建[碩士學(xué)位論文].長沙:國防科學(xué)技術(shù)大學(xué),2012.
2張超,易曉東,戴華東.Android圖形系統(tǒng)向桌面Linux的移植.2012全國計算機(jī)體系結(jié)構(gòu)學(xué)術(shù)年會論文集.西安,中國.2012.209–213.
3Inki Dae Software Platform Lab.DRM driver development for embedded systems.http://elinux.org/images/7/71/Elce11_dae.pdf.[2011].
4Android-x86-porting android to x86.http://www.androidx86.org/.
5The mesa 3D graphics library.http://www.mesa3d.org/.
6Direct rendering manager (DRM).https://dri.freedesktop.org/wiki/DRM.
7Packard K.Gem-the graphics execution manager.2008.https://lwn.net/Articles/283798/.
8Direct rendering infrastructure.https://en.wikipedia.org/wiki/Direct_Rendering_Infrastructure.
9Scheifler RW,Gettys J.The X Window system.ACM Trans.on Graphics,1986,5(2):79–109.
10Corbet J.MIT-SHM-the MIT shared memory extension.https://www.x.org/Releases/X11R7.7/doc/xextproto/shm.html.[1991].
11H?gsberg K.The DRI2 extension.https://www.x.org/releases/X11R7.7/doc/dri2proto/dri2proto.txt.[2008].
Method to Run SurfaceFlinger on X Window System
JIANG Fan,HE Ye-Ping,ZHOU Qi-Ming
(National Engineering Research Center of Fundamental Software,Institue of Sofware,Chinese Academy of Sciences,Beijing 100190,China)
This paper presents a method to transplant Android’s graphic system,SurfaceFlinger,to run on desktop Linux distribution’s X Window System.SurfaceFlinger running on X can make UI of the Android applications,running as native processes in the desktop Android runtime,show in a window of X.Using Mesa as the OpenGL ES implementation and making Mesa EGL compatible with Android’s native window,together with gralloc.drm.so module,the Android UI rendering process and SurfaceFlinger’s graphic compositing process can be implemented by using the GPU for hardware acceleration.In addition,using X11’s DRI2 extension to coordinate window of SurfaceFlinger with X Server’s DDX driver,can avoid graphic buffer coping from GPU’s dedicated memory to the system memory.In our experiment,the third-party 3D benchmark software San-Angeles can achieve 60FPS on variety GPUs.Compared with the existing method,the architecture of our method is more concise,efficient,and supportive of hardware acceleration.
Android graphic system; SurfaceFlinger; X Window system; transplant; compatibility environment
江帆,賀也平,周啟明.SurfaceFlinger在X Window系統(tǒng)環(huán)境下的運行方案.計算機(jī)系統(tǒng)應(yīng)用,2017,26(10):95–101.http://www.c-sa.org.cn/1003-3254/6012.html
國家科技重大專項(2012ZX01039-004)
2017-01-17; 采用時間:2017-02-23