天天看點

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 、原理 分析

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

Android Display System --- Surface Flinger

每個應用程式可能對應着一個或者多個圖形界面,而每個界面我們就稱之為一個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的過程:

Android Display System --- Surface Flinger

    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 建立過程的類圖 :

Android Display System --- Surface Flinger

在ibinder 左邊的就是用戶端部分,也就是需要視窗顯示的應用程式,而右邊就是我們的surface flinger service 。 建立一個surface 分為兩個過程,一個是在surfaceflinger 這邊為每個應用程式(client) 建立一個管理 結構,另一個就是建立存儲内容的buffer ,以及在這個buffer 上的一系列畫圖之類的操作。

因為surfaceflinger 要管理多個應用程式的多個視窗界面,為了進行管理它提供了一個client 類,每個來請求服務的應用程式就對應了一個client 。因為surface是在surfaceflinger 建立的,必須傳回一個結構讓應用程式知道自己申請的surface 資訊,是以surfaceflinger 将client 建立的控制結構per_client_cblk_t 經過bclient 的封裝以後傳回給surfacecomposerclient ,并向應用程式提供了一組建立和銷毀surface 的操作:

Android Display System --- Surface Flinger

    為應用程式建立一個 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 Display System --- Surface Flinger

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

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