Android Display System --- Surface Flinger

 轉: http://blog.csdn.net/yili_xie/article/details/4803527


Android
 
Display System --- Surface Flinger

     SurfaceFlinger Android multimedia 的一個部分,在Android 的實現中它是一個service ,提供系統 範圍內的surface composer 功能,它能夠將各種應用 程序的2D 、3D surface 進行組合。在具體講SurfaceFlinger 之前,我們先來看一下有關顯示方面的一些基礎 知識 

 

1 原理 分析

讓我們首先看一下下面的屏幕簡略圖:

 

 

 

每個應用程序可能對應着一個或者多個圖形界面,而每個界面我們就稱之爲一個surface ,或者說是window ,在上面的圖中我們能看到4 個surface ,一個是home 界面,還有就是紅、綠、藍分別代表的3 個surface ,而兩個button 實際是home surface 裏面的內容。在這裏我們能看到我們進行圖形顯示所需要解決 的問題:

    a 、首先每個surface 在屏幕上有它的位置,以及大小,然後每個surface 裏面還有要顯示的內容,內容,大小,位置 這些元素 在我們改變應用程序的時候都可能會改變,改變時應該如何處理 

b 、然後就各個surface 之間可能有重疊,比如說在上面的簡略圖中,綠色覆蓋了藍色,而紅色又覆蓋了綠色和藍色以及下面的home ,而且還具有一定透明度。這種層之間的關係應該如何描述?      

我們首先來看第二個問題,我們可以想象在屏幕平面的垂直方向還有一個Z 軸,所有的surface 根據在Z 軸上的座標來確定前後,這樣就可以描述各個surface 之間的上下覆蓋關係了,而這個在Z 軸上的順序,圖形上有個專業術語叫Z-order 。  

    對於第一個問題,我們需要一個結構來記錄應用程序界面的位置,大小,以及一個buffer 來記錄需要顯示的內容,所以這就是我們surface 的概念,surface 實際我們可以把它理解成一個容器,這個容器記錄着應用程序界面的控制信息,比如說大小啊,位置啊,而它還有buffer 來專門存儲需要顯示的內容。

    在這裏還存在一個問題,那就是當存在圖形重合的時候應該如何處理呢,而且可能有些surface 還帶有透明信息,這裏就是我們SurfaceFlinger 需要解決問題,它要把各個surface 組合(compose/merge) 成一個main Surface ,最後將Main Surface 的內容發送給FB/V4l2 Output ,這樣屏幕上就能看到我們想要的效果。

    在實際中對這些Surface 進行merge 可以採用兩種方式,一種就是採用軟件的形式來merge ,還一種就是採用硬件的方式,軟件的方式就是我們的SurfaceFlinger ,而硬件的方式就是Overlay 。

 

2 OverLay

     因爲硬件merge 內容相對簡單,我們首先來看overlay  Overlay 實現的方式有很多,但都需要硬件的支持。以IMX51 爲例子,當IPU 向內核申請FB 的時候它會申請3 個FB ,一個是主屏的,還一個是副屏的,還一個就是Overlay 的。 簡單地來說,Overlay就是我們將硬件所能接受的格式數據 和控制信息送到這個Overlay FrameBuffer,由硬件驅動來負責merge Overlay buffer和主屏buffer中的內容。

    一般來說現在的硬件都只支持一個Overlay,主要用在視頻播放以及camera preview上,因爲視頻內容的不斷變化用硬件Merge比用軟件Merge要有效率得多,下面就是使用Overlay和不使用Overlay的過程:

 

    

 

    SurfaceFlinger中加入了Overlay hal,只要實現這個Overlay hal可以使用overlay的功能,這個頭文件 在:/hardware/libhardware/include/harware/Overlay.h,可以使用FB或者V4L2 output來實現,這個可能是我們將來工作的內容。實現Overlay hal以後,使用Overlay接口的sequence就在 /frameworks/base/libs/surfaceflinger/tests/overlays/Overlays.cpp,這個sequnce是很重要的,後面我們會講到。

    不 過在實際中我們不一定需要實現Overlay hal,如果瞭解硬件的話,可以在驅動中直接把這些信息送到Overlay Buffer,而不需要走上層的Android。Fsl現在的Camera preview就是採用的這種方式,而且我粗略看了r3補丁的內容,應該在opencore的視頻播放這塊也實現了Overlay。

 

3、SurfaceFlinger

     現 在就來看看最複雜的SurfaceFlinger,首先要明確的是SurfaceFlinger只是負責merge Surface的控制,比如說計算出兩個Surface重疊的區域,至於Surface需要顯示的內容,則通過skia,opengl和 pixflinger來計算。 所以我們在介紹SurfaceFlinger 之前先忽略裏面存儲的內容究竟是什麼,先弄清楚它對merge 的一系列控制的過程,然後再結合2D ,3D 引擎來看它的處理過程。

 

3.1 Surface 的創建過程

    前面提到了每個應用程序可能有一個或者多個Surface , 我們需要一些數據結構來存儲我們的窗口信息,我們還需要buffer 來存儲我們的窗口內容, 而且最主要的是我們應該確定一個方案 來和SurfaceFlinger 來交互這些信息,讓我們首先看看下面的Surface 創建過程的類圖 

 

 

IBinder 左邊的就是客戶端部分,也就是需要窗口顯示的應用程序,而右邊就是我們的Surface Flinger service 。 創建一個surface 分爲兩個過程,一個是在SurfaceFlinger 這邊爲每個應用程序(Client) 創建一個管理 結構,另一個就是創建存儲內容的buffer ,以及在這個buffer 上的一系列畫圖之類的操作。

因爲SurfaceFlinger 要管理多個應用程序的多個窗口界面,爲了進行管理它提供了一個Client 類,每個來請求服務的應用程序就對應了一個Client 。因爲surface是在SurfaceFlinger 創建的,必須返回一個結構讓應用程序知道自己申請的surface 信息,因此SurfaceFlinger 將Client 創建的控制結構per_client_cblk_t 經過BClient 的封裝以後返回給SurfaceComposerClient ,並嚮應用程序提供了一組創建和銷燬surface 的操作:

 

    爲應用程序創建一個 Client 以後,下面需要做的就是爲這個 Client 分配 Surface  Flinger 爲每個 Client 提供了 8M 空間 ,包括控制信息和存儲內容的 buffer 。在說創建 surface 之前首先要理解 layer 這個概念,回到我們前面看的屏幕簡略圖,實際上每個窗口就是 z 軸上的一個 layer  layer 提供了對窗口控制信息的操作,以及內容的處理 ( 調用 opengl 或者 skia) ,也就是說 SurfaceFlinger 只是控制什麼時候應該進行這些信息的處理以及處理的過程,所有實際的處理都是在 layer 中進行的,可以理解爲創建一個 Surface 就是創建一個 Layer 。不得不說 Android 這些亂七八糟的名字,讓我繞了很久……

創建 Layer 的過程,首先是由這個應用程序的 Client 根據應用程序的 pid 生成一個唯一的 layer ID ,然後根據大小,位置,格式啊之類的信息創建出 Layer 。在Layer 裏面有一個嵌套的 Surface 類,它主要包含一個 ISurfaceFlingerClient::Surface_data_t ,包含了這個 Surace 的統一標識符以及 buffer 信息等,提供給應用程序使用。最後應用程序會根據返回來的 ISurface 信息等創建自己的一個 Surface 

 

 

 

Android 提供了 4 種類型的 layer 供選擇,每個 layer 對應一種類型的窗口,並對應這種窗口相應的操作: Layer  LayerBlur  LayerBuffer  LayerDim 。不得不說再說 Android 起的亂七八糟的名字, LayerBuffer 很容易讓人理解成是 Layer  Buffer ,它實際上是一種 Layer 類型。各個 Layer 的效果大家可以參考Surface.java 裏面的描述: /frameworks/base/core/java/android/view/surface.java 。這裏要重點說一下兩種 Layer ,一個是 Layer (norm layer) ,另一個是LayerBuffer 

Norm Layer  Android 種使用最多的一種 Layer ,一般的應用程序在創建 surface 的時候都是採用的這樣的 layer ,瞭解 Normal Layer 可以讓我們知道Android 進行 display 過程中的一些基礎原理。 Normal Layer 爲每個 Surface 分配兩個 buffer  front buffer  back buffer ,這個前後是相對的概念,他們是可以進行 Flip 的。 Front buffer 用於 SurfaceFlinger 進行顯示,而 Back buffer 用於應用程序進行畫圖,當 Back buffer 填滿數據 (dirty) 以後,就會 flip back buffer 就變成了 front buffer 用於顯示,而 front buffer 就變成了 back buffer 用來畫圖,這兩個 buffer 的大小是根據 surface 的大小格式動態變化的。這個動態變化的實現我沒仔細看,可以參照  /frameworks/base/lib/surfaceflinger/layer.cpp 中的 setbuffers() 

兩個 buffer flip 的方式是 Android display 中的一個重要實現方式,不只是每個 Surface 這麼實現,最後寫入 FB  main surface 也是採用的這種方式。

LayerBuffer 也是將來必定會用到的一個 Layer ,個人覺得也是最複雜的一個 layer ,它不具備 render buffer ,主要用在 camera preview / video playback上。它提供了兩種實現方式,一種就是 post buffer ,另外一種就是我們前面提到的 overlay  Overlay 的接口實際上就是在這個 layer 上實現的。不管是 overlay還是 post buffer 都是指這個 layer 的數據來源自其他地方,只是 post buffer 是通過軟件的方式最後還是將這個 layer merge 主的 FB ,而 overlay 則是通過硬件merge 的方式來實現。與這個 layer 緊密聯繫在一起的是 ISurface 這個接口,通過它來註冊數據來源,下面我舉個例子來說明這兩種方式的使用方法:

 

前面幾個步驟是通用的:

 

// 要使用 Surfaceflinger 的服務必須先創建一個 client

sp<SurfaceComposerClient> client = new SurfaceComposerClient();

// 然後向 Surfaceflinger 申請一個 Surface  surface 類型爲 PushBuffers

sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240,

            PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);

// 然後取得 ISurface 這個接口, getISurface() 這個函數的調用時具有權限限制的,必須在 Surface.h 中打開: /framewoks/base/include/ui/Surface.h

sp<ISurface> isurface = Test::getISurface(surface);

 

//overlay 方式下就創建 overlay ,然後就可以使用 overlay 的接口了

sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);

sp<Overlay> verlay = new Overlay(ref);

 

//post buffer 方式下,首先要創建一個 buffer ,然後將 buffer 註冊到 ISurface 

ISurface::BufferHeap buffers(w, h, w, h,

                                          PIXEL_FORMAT_YCbCr_420_SP,

                                         transform,

                                         0,

                                         mHardware->getPreviewHeap());

mSurface->registerBuffers(buffers);

3.2 應用 程序對窗口的控制和畫圖

Surface 創建以後,應用程序就可以在 buffer 中畫圖了,這裏就面對着兩個問題了,一個是怎麼知道在哪個 buffer 上來畫圖,還一個就是畫圖以後如何通知SurfaceFlinger 來進行 flip 。除了畫圖之外,如果我們移動窗口以及改變窗口大小的時候,如何告訴 SurfaceFlinger 來進行處理呢 ?在明白這些問題之前,首先我們要了解 SurfaceFlinger 這個服務 是如何運作的:

從類圖中可以看到 SurfaceFlinger 是一個線程類,它繼承了 Thread 類。當創建 SurfaceFlinger 這個服務的時候會啓動一個 SurfaceFlinger 監聽線程,這個線程會一直等待事件的發生,比如說需要進行 sruface flip ,或者說窗口位置大小發生了變化等等,一旦產生這些事件, SurfaceComposerClient 就會通過 IBinder 發出信號,這個線程就會結束等待處理這些事件,處理完成以後會繼續等待,如此循環。

SurfaceComposerClient  SurfaceFlinger 是通過 SurfaceFlingerSynchro 這個類來同步信號的,其實說穿了就是一個條件變量。監聽線程等待條件的值變成 OPEN ,一旦變成 OPEN 就結束等待並將條件置成 CLOSE 然後進行事件處理,處理完成以後再繼續等待條件的值變成 OPEN ,而 Client  Surface 一旦改變就通過 IBinder 通知SurfaceFlinger 將條件變量的值變成 OPEN ,並喚醒等待的線程,這樣就通過線程類和條件變量實現了一個動態處理機制。

瞭解了 SurfaceFlinger 的事件機制我們再回頭看看前面提到的問題了。首先在對 Surface 進行畫圖之前必須鎖定 Surface  layer ,實際上就是鎖定了 Layer_cblk_t裏的 swapstate 這個變量。 SurfaceComposerClient 通過 swapsate 的值來確定要使用哪個 buffer 畫圖,如果 swapstate 是下面的值就會阻塞 Client ,就不翻譯了直接copy 過來:

// We block the client if:

// eNextFlipPending:  we've used both buffers already, so we need to

//                    wait for one to become availlable.

// eResizeRequested:  the buffer we're going to acquire is being

//                    resized. Block until it is done.

// eFlipRequested && eBusy: the buffer we're going to acquire is

//                    currently in use by the server.

// eInvalidSurface:   this is a special case, we don't block in this

//                    case, we just return an error.

所以應用程序先調用 lockSurface() 鎖定 layer  swapstate ,並獲得畫圖的 buffer 然後就可以在上面進行畫圖了,完成以後就會調用 unlockSurfaceAndPost() 來通知 SurfaceFlinger 進行 Flip 。或者僅僅調用 unlockSurface() 而不通知 SurfaceFlinger 

一般來說畫圖的過程需要重繪 Surface 上的所有像素,因爲一般情況下顯示過後的像素是不做保存的,不過也可以通過設定來保存一些像素,而只繪製部分像素,這裏就涉及到像素的拷貝了,需要將 Front buffer 的內容拷貝到 Back buffer 。在 SurfaceFlinger 服務實現中像素的拷貝是經常需要進行的操作,而且還可能涉及拷貝過程的轉換,比如說屏幕的旋轉,翻轉等一系列操作。因此 Android 提供了拷貝像素的 hal ,這個也可能是我們將來需要實現的,因爲用硬件完成像素的拷貝,以及拷貝過程中可能的矩陣變換等操作,比用 memcpy 要有效率而且節省資源。這個 HAL 文件 在: /hardware/libhardware/hardware/include/copybit.h

窗口狀態變化的處理是一個很複雜的過程,首先要說明一下, SurfaceFlinger 只是執行 Windows manager 的指令,由 Windows manager 來決定什麼是偶改變大小,位置,設置 透明度,以及如何調整 layer 之間的順序, SurfaceFlinger 僅僅只是執行它的指令。 PS  Windows Manager  java 層的一個服務,提供對所有窗口的管理功能,這部分的內容我沒細看過,覺得是將來需要了解的內容。

窗口狀態的變化包括位置的移動,窗口大小,透明度, z-order 等等,首先我們來了解一下 SurfaceComposerClient 是如何和 SurfaceFlinger 來交互這些信息的。當應用程序需要改變窗口狀態的時候它將所有的狀態改變信息打包,然後一起發送給 SurfaceFlinger  SurfaceFlinger 改變這些狀態信息以後,就會喚醒等待的監聽線程,並設置一個標誌位告訴監聽線程窗口的狀態已經改變了,必須要進行處理,在 Android 的實現中,這個打包的過程就是一個 Transaction ,所有對窗口狀態(layer_state_t) 的改變都必須在一個 Transaction 中。

到這裏應用程序客戶端的處理過程已經說完了,基本分爲兩個部分,一個就是在窗口畫圖,還一個就是窗口狀態改變的處理。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章