1. 程式人生 > >android display(sufaceflinger & overlay)

android display(sufaceflinger & overlay)

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 中。

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

4 、 SurfaceFlinger 的處理過程

瞭解了 Flinger 和客戶端的互動,我們再來仔細看看 SurfaceFlinger 的處理過程,前面已經說過了 SurfaceFlinger 這個服務在建立的時候會啟動一個監聽的執行緒,這個執行緒負責每次視窗更新時候的處理,下面我們來仔細看看這個執行緒的事件的處理,大致就是下面的這個圖:


先大致講一下 Android 組合各個視窗的原理 : Android 實際上是通過計算每一個視窗的可見區域,就是我們在螢幕上可見的視窗區域 ( 用 Android 的詞彙來說就是 visibleRegionScreen ) ,然後將各個視窗的可見區域畫到一個主 layer 的相應部分,最後就拼接成了一個完整的螢幕,然後將主 layer 輸送到 FB 顯示。在將各個視窗可見區域畫到主 layer 過程中涉及到一個硬體實現和一個軟體實現的問題,如果是軟體實現則通過 Opengl 重新畫圖,其中還包括存在透明度的 alpha 計算;如果實現了 copybit hal 的話,可以直接將視窗的這部分資料 直接拷貝過來,並完成可能的旋轉,翻轉,以及 alhpa 計算等。

下面來看看 Android 組合各個 layer 並送到 FB 顯示的具體過程:

4.1 、 handleConsoleEvent

當接收到 signal 或者 singalEvent 事件以後,執行緒就停止等待開始對 Client 的請求進行處理,第一個步驟是 handleConsoleEvent ,這個步驟我看了下和 /dev/console 這個裝置有關,它會取得螢幕或者釋放螢幕,只有取得螢幕的時候才能夠在螢幕上畫圖。

4.2 、 handleTransaction

前面提到過,視窗狀態的改變只能在一個 Transaction 中進行。因為視窗狀態的改變可能造成本視窗和其他視窗的可見區域變化,所以就必須重新來計算視窗的可見區域。在這個處理子過程中 Android 會根據標誌位來對所有 layer 進行遍歷,一旦發現哪個視窗的狀態發生了變化就設定標誌位以在將來重新計算這個視窗的可見區域。在完成所有子 layer 的遍歷以後, Android 還會根據標誌位來處理主 layer ,舉個例子,比如說感測器感應到手機橫過來了,會將視窗橫向顯示,此時就要重新設定主 layer 的方向。

4.3 、 handlePageFlip

    這裡會處理每個視窗 surface buffer 之間的翻轉,根據 layer_state_t 的 swapsate 來決定是否要翻轉,當 swapsate 的值是 eNextFlipPending 是就會翻轉。處理完翻轉以後它會重新計算每個 layer 的可見區域,這個重新計算的過程我還沒看太明白,但大致是一個這麼的過程:

從 Z 值最大的 layer 開始計算,也就是說從最上層的 layer 計算,去掉本身的透明區域和覆蓋在它上面的不透明區域,得到的就是這個 layer 的可見區域。然後這個 layer 的不透明區域就會累加到不透明覆蓋區域,這個 layer 的可見區域會放入到主 layer 的可見區域,然後計算下一個 layer ,直到計算完所有的 layer 的可見區域。這中間的計算是通過定義在 skia 中的一種與或非的圖形邏輯運算實現的,類似我們數學中的與或非邏輯圖。

4.4 、 handleRepaint

計算出每個 layer 的可見區域以後,這一步就是將所有可見區域的內容畫到主 layer 的相應部分了,也就是說將各個 surface buffer 裡面相應的內容拷貝到主 layer 相應的 buffer ,其中可能還涉及到 alpha 運算,畫素的翻轉,旋轉等等操作,這裡就像我前面說的可以用硬體來實現也可以用軟體來實現。在使用軟體的 opengl 做計算的過程中還會用到 PixFlinger 來做畫素的合成,這部分內容我還沒時間來細看。

4.5 、 postFrameBuffer

最後的任務就是翻轉主 layer 的兩個 buffer ,將剛剛寫入的內容放入 FB 內顯示了。