国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Android Display System --- Surface Flinger
 

AndroidDisplay System --- SurfaceFlinger

    SurfaceFlingerAndroid multimedia的一個部分,在Android的實現(xiàn)中它是一個service,提供系統(tǒng)范圍內(nèi)的surface composer功能,它能夠?qū)⒏鞣N應用程序的2D、3D surface進行組合。在具體講SurfaceFlinger之前,我們先來看一下有關(guān)顯示方面的一些基礎(chǔ)知識。

 

1、原理分析

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


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

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

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

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

   對于第一個問題,我們需要一個結(jié)構(gòu)來記錄應用程序界面的位置,大小,以及一個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。

 

2、OverLay

   因為硬件merge內(nèi)容相對簡單,我們首先來看overlay。Overlay實現(xiàn)的方式有很多,但都需要硬件的支持。以IMX51為例子,當IPU向內(nèi)核申請FB的時候它會申請3FB,一個是主屏的,還一個是副屏的,還一個就是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ū)動中直接把這些信息送到OverlayBuffer,而不需要走上層的Android。Fsl現(xiàn)在的Camerapreview就是采用的這種方式,而且我粗略看了r3補丁的內(nèi)容,應該在opencore的視頻播放這塊也實現(xiàn)了Overlay。

 

3、SurfaceFlinger

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

 

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

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


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

因為SurfaceFlinger要管理多個應用程序的多個窗口界面,為了進行管理它提供了一個Client類,每個來請求服務的應用程序就對應了一個Client。因為surface是在SurfaceFlinger創(chuàng)建的,必須返回一個結(jié)構(gòu)讓應用程序知道自己申請的surface信息,因此SurfaceFlingerClient創(chuàng)建的控制結(jié)構(gòu)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。不得不說再說Android起的亂七八糟的名字,LayerBuffer很容易讓人理解成是LayerBuffer,它實際上是一種Layer類型。各個Layer的效果大家可以參考Surface.java里面的描述:/frameworks/base/core/java/android/view/surface.java。這里要重點說一下兩種Layer,一個是Layer (norm layer),另一個是LayerBuffer

Norm LayerAndroid種使用最多的一種Layer,一般的應用程序在創(chuàng)建surface的時候都是采用的這樣的layer,了解Normal Layer可以讓我們知道Android進行display過程中的一些基礎(chǔ)原理。Normal Layer為每個Surface分配兩個bufferfront bufferback 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),最后寫入FBmain 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<SurfaceComposerClient> client = new SurfaceComposerClient();

//然后向Surfaceflinger申請一個Surfacesurface類型為PushBuffers

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

           PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);

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

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

 

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

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

sp<Overlay> 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中畫圖了,這里就面對著兩個問題了,一個是怎么知道在哪個buffer上來畫圖,還一個就是畫圖以后如何通知SurfaceFlinger來進行flip。除了畫圖之外,如果我們移動窗口以及改變窗口大小的時候,如何告訴SurfaceFlinger來進行處理呢?在明白這些問題之前,首先我們要了解SurfaceFlinger這個服務是如何運作的:

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

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

了解了SurfaceFlinger的事件機制我們再回頭看看前面提到的問題了。首先在對Surface進行畫圖之前必須鎖定Surfacelayer,實際上就是鎖定了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()鎖定layerswapstate,并獲得畫圖的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í)行Windowsmanager的指令,由Windows manager來決定什么是偶改變大小,位置,設置透明度,以及如何調(diào)整layer之間的順序,SurfaceFlinger僅僅只是執(zhí)行它的指令。PSWindows Managerjava層的一個服務,提供對所有窗口的管理功能,這部分的內(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.1handleConsoleEvent

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

 

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_tswapsate來決定是否要翻轉(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)顯示了。


本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android
GUI系統(tǒng)之SurfaceFlinger(7)應用程序的典型繪圖流程
【轉(zhuǎn)】Android display架構(gòu)分析
Android Graphic 架構(gòu)
Android GUI更新過程
Android應用程序UI硬件加速渲染技術(shù)簡要介紹和學習計劃
更多類似文章 >>
生活服務
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服