Android Display System --- Surface Flingerphp
SurfaceFlinger 是Android multimedia 的一個部分,在Android 的實現中它是一個service ,提供系統 範圍內的surface composer功能,它可以將各類應用 程序的2D 、3D surface 進行組合。在具體講SurfaceFlinger 以前,咱們先來看一下有關顯示方面的一些基礎知識 。java
1 、原理 分析android
讓咱們首先看一下下面的屏幕簡略圖:數據結構
每一個應用程序可能對應着一個或者多個圖形界面,而每一個界面咱們就稱之爲一個surface ,或者說是window ,在上面的圖中咱們能看到4 個surface ,一個是home 界面,還有就是紅、綠、藍分別表明的3 個surface ,而兩個button 實際是home surface 裏面的內容。在這裏咱們能看到咱們進行圖形顯示所須要解決 的問題:composer
a 、首先每一個surface 在屏幕上有它的位置,以及大小,而後每一個surface 裏面還有要顯示的內容,內容,大小,位置 這些元素 在咱們改變應用程序的時候均可能會改變,改變時應該如何處理 ?ide
b 、而後就各個surface 之間可能有重疊,好比說在上面的簡略圖中,綠色覆蓋了藍色,而紅色又覆蓋了綠色和藍色以及下面的home,並且還具備必定透明度。這種層之間的關係應該如何描述? 函數
咱們首先來看第二個問題,咱們能夠想象在屏幕平面的垂直方向還有一個Z 軸,全部的surface 根據在Z 軸上的座標來肯定先後,這樣就能夠描述各個surface 之間的上下覆蓋關係了,而這個在Z 軸上的順序,圖形上有個專業術語叫Z-order 。 post
對於第一個問題,咱們須要一個結構來記錄應用程序界面的位置,大小,以及一個buffer 來記錄須要顯示的內容,因此這就是咱們surface 的概念,surface 實際咱們能夠把它理解成一個容器,這個容器記錄着應用程序界面的控制信息,好比說大小啊,位置啊,而它還有buffer 來專門存儲須要顯示的內容。ui
在這裏還存在一個問題,那就是當存在圖形重合的時候應該如何處理呢,並且可能有些surface 還帶有透明信息,這裏就是咱們SurfaceFlinger 須要解決問題,它要把各個surface 組合(compose/merge) 成一個main Surface ,最後將Main Surface 的內容發送給FB/V4l2 Output ,這樣屏幕上就能看到咱們想要的效果。spa
在實際中對這些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。
三、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);