日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網(wǎng)站首頁 編程語言 正文

Android中SurfaceFlinger工作原理_Android

作者:大海之狂 ? 更新時間: 2022-03-06 編程語言

概念

SurfaceFlinger是一個系統(tǒng)服務,如:audioflinger,audiopolicyservice等等,系統(tǒng)的主要服務通過這個文章進行了解,Android的系統(tǒng)服務一覽。這個系統(tǒng)服務主要實現(xiàn)了Surface的建立、控制、管理等功能。換種說法就是,在Android?的實現(xiàn)中它是一個service,提供系統(tǒng)范圍內(nèi)的surface composer功能,它能夠?qū)⒏鞣N應用程序的2D、3D surface進行組合。

原理分析

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

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

  • a、首先每個surface?在屏幕上有它的位置,以及大小,然后每個surface?里面還有要顯示的內(nèi)容,內(nèi)容,大小,位置?這些元素?在我們改變應用程序的時候都可能會改變,改變時應該如何處理??
  • b、然后就各個surface?之間可能有重疊,比如說在上面的簡略圖中,綠色覆蓋了藍色,而紅色又覆蓋了綠色和藍色以及下面的home?,而且還具有一定透明度。這種層之間的關系應該如何描述???????

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

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

在這里還存在一個問題,那就是當存在圖形重合的時候應該如何處理呢,而且可能有些surface?還帶有透明信息,這里就是我們SurfaceFlinger?需要解決問題,它要把各個surface?組合(compose/merge)?成一個main Surface?,最后將Main Surface?的內(nèi)容發(fā)送給FB/V4l2 Output?,這樣屏幕上就能看到我們想要的效果。??在實際中對這些Surface?進行merge?可以采用兩種方式,一種就是采用軟件的形式來merge?,還一種就是采用硬件的方式,軟件的方式就是我們的SurfaceFlinger?,而硬件的方式就是Overlay?。

OverLay

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

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

SurfaceFlinger中加入了Overlay hal,只要實現(xiàn)這個Overlay hal可以使用overlay的功能,這個頭文件在:

/hardware/libhardware/include/harware/Overlay.h

可以使用FB或者V4L2 output來實現(xiàn),這個可能是我們將來工作的內(nèi)容。實現(xiàn)Overlay hal以后,使用Overlay接口的sequence就在?:

?/frameworks/base/libs/surfaceflinger/tests/overlays/Overlays.cpp,

這個sequnce是很重要的,后面我們會講到。

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

SurfaceFlinger

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

3.1?、Surface?的創(chuàng)建過程

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

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

因為SurfaceFlinger?要管理多個應用程序的多個窗口界面,為了進行管理它提供了一個Client?類,每個來請求服務的應用程序就對應了一個Client?。因為surface?是在SurfaceFlinger?創(chuàng)建的,必須返回一個結構讓應用程序知道自己申請的surface?信息,因此SurfaceFlinger?將Client?創(chuàng)建的控制結構per_client_cblk_t?經(jīng)過BClient?的封裝以后返回SurfaceComposerClient?,并向應用程序提供了一組創(chuàng)建和銷毀surface?的操作:

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

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

Android?提供了?4?種類型的?layer?供選擇,每個?layer?對應一種類型的窗口,并對應這種窗口相應的操作:

?Layer?,?LayerBlur?,?LayerBuffer?,LayerDim?。

?LayerBuffer?很容易讓人理解成是?Layer?的?Buffer?,它實際上是一種?Layer?類型。各個?Layer的效果大家可以參考?Surface.java?里面的描述:?/frameworks/base/core/java/android/view/surface.java?。這里要重點說一下兩種?Layer?,一個是?Layer (norm layer)?,另一個是?LayerBuffer?。

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

兩個?buffer flip?的方式是?Android display?中的一個重要實現(xiàn)方式,不只是每個?Surface?這么實現(xiàn),最后寫入?FB?的?main surface?也是采用的這種方式。

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

前面幾個步驟是通用的:

//?要使用?Surfaceflinger?的服務必須先創(chuàng)建一個?client

sp?client = new SurfaceComposerClient();

//?然后向?Surfaceflinger?申請一個?Surface?,?surface?類型為?PushBuffers

sp?surface = client->createSurface(getpid(), 0, 320, 240,?PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);

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

sp?isurface = Test::getISurface(surface);

//overlay?方式下就創(chuàng)建?overlay?,然后就可以使用?overlay?的接口了

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

sp?verlay = new Overlay(ref);

//post buffer?方式下,首先要創(chuàng)建一個?buffer?,然后將?buffer?注冊到?ISurface?上

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

??????????????????????????????????????????PIXEL_FORMAT_YCbCr_420_SP,

?????????????????????????????????????????transform,

?????????????????????????????????????????0,

?????????????????????????????????????????mHardware->getPreviewHeap());

mSurface->registerBuffers(buffers);

3.2?、應用程序?qū)Υ翱诘目刂坪彤媹D

Surface 創(chuàng)建以后,應用程序就可以在?buffer?中畫圖了,這里就面對著下面幾個問題了:

  • a、是怎么知道在哪個?buffer?上來畫圖?
  • b、就是畫圖以后如何通知?SurfaceFlinger?來進行?flip ?
  • c、除了畫圖之外,如果我們移動窗口以及改變窗口大小的時候,如何告訴?SurfaceFlinger?來進行處理呢??

在明白這些問題之前,首先我們要了解?SurfaceFlinger?這個服務是如何運作的:

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

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

了解了?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.

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

一般來說畫圖的過程需要重繪?Surface?上的所有像素,因為一般情況下顯示過后的像素是不做保存的,不過也可以通過設定來保存一些像素,而只繪制部分像素,這里就涉及到像素的拷貝了,需要將?Front buffer?的內(nèi)容拷貝到?Back buffer?。在?SurfaceFlinger?服務實現(xiàn)中像素的拷貝是經(jīng)常需要進行的操作,而且還可能涉及拷貝過程的轉(zhuǎn)換,比如說屏幕的旋轉(zhuǎn),翻轉(zhuǎn)等一系列操作。因此?Android?提供了拷貝像素的?hal?,這個也可能是我們將來需要實現(xiàn)的,因為用硬件完成像素的拷貝,以及拷貝過程中可能的矩陣變換等操作,比用?memcpy?要有效率而且節(jié)省資源。這個?HAL?頭文件?在:

/hardware/libhardware/hardware/include/copybit.h

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

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

到這里應用程序客戶端的處理過程已經(jīng)說完了,基本分為兩個部分,一個就是在窗口畫圖,還一個就是窗口狀態(tài)改變的處理。

4?、?SurfaceFlinger?的處理過程

了解了?Flinger?和客戶端的交互,我們再來仔細看看?SurfaceFlinger?的處理過程,前面已經(jīng)說過了SurfaceFlinger?這個服務在創(chuàng)建的時候會啟動一個監(jiān)聽的線程,這個線程負責每次窗口更新時候的處理,下面我們來仔細看看這個線程的事件的處理,大致就是下面的這個圖:

先大致講一下?Android?組合各個窗口的原理?:?Android?實際上是通過計算每一個窗口的可見區(qū)域,就是我們在屏幕上可見的窗口區(qū)域?(?用?Android的詞匯來說就是?visibleRegionScreen )?,然后將各個窗口的可見區(qū)域畫到一個主?layer?的相應部分,最后就拼接成了一個完整的屏幕,然后將主?layer?輸送到?FB?顯示。在將各個窗口可見區(qū)域畫到主?layer?過程中涉及到一個硬件實現(xiàn)和一個軟件實現(xiàn)的問題,如果是軟件實現(xiàn)則通過?Opengl?重新畫圖,其中還包括存在透明度的?alpha?計算;如果實現(xiàn)了?copybit hal?的話,可以直接將窗口的這部分數(shù)據(jù)?直接拷貝過來,并完成可能的旋轉(zhuǎn),翻轉(zhuǎn),以及?alhpa?計算等。

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

4.1?、?handleConsoleEvent

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

4.2?、?handleTransaction

前面提到過,窗口狀態(tài)的改變只能在一個?Transaction?中進行。因為窗口狀態(tài)的改變可能造成本窗口和其他窗口的可見區(qū)域變化,所以就必須重新來計算窗口的可見區(qū)域。在這個處理子過程中?Android?會根據(jù)標志位來對所有?layer?進行遍歷,一旦發(fā)現(xiàn)哪個窗口的狀態(tài)發(fā)生了變化就設置標志位以在將來重新計算這個窗口的可見區(qū)域。在完成所有子?layer?的遍歷以后,?Android?還會根據(jù)標志位來處理主?layer?,舉個例子,比如說傳感器感應到手機橫過來了,會將窗口橫向顯示,此時就要重新設置主?layer?的方向。

4.3?、?handlePageFlip

????這里會處理每個窗口?surface buffer?之間的翻轉(zhuǎn),根據(jù)?layer_state_t?的?swapsate?來決定是否要翻轉(zhuǎn),當?swapsate?的值是?eNextFlipPending?是就會翻轉(zhuǎn)。處理完翻轉(zhuǎn)以后它會重新計算每個?layer的可見區(qū)域,這個重新計算的過程我還沒看太明白,但大致是一個這么的過程:

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

4.4?、?handleRepaint

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

4.5?、?postFrameBuffer

最后的任務就是翻轉(zhuǎn)主?layer?的兩個?buffer?,將剛剛寫入的內(nèi)容放入?FB?內(nèi)顯示了。

原文鏈接:https://blog.csdn.net/haigand/article/details/90489336

欄目分類
最近更新