在Android4.1之后增加了Choreographer機(jī)制,用于同Vsync機(jī)制配合,統(tǒng)一動(dòng)畫(huà)、輸入和繪制時(shí)機(jī)。本文以繪制為例來(lái)簡(jiǎn)單學(xué)習(xí)下Choreographer。
只為您設(shè)計(jì)更接底氣、較有營(yíng)銷(xiāo)力的好網(wǎng)站,將營(yíng)銷(xiāo)策劃與網(wǎng)頁(yè)設(shè)計(jì)互相結(jié)合的專業(yè)機(jī)構(gòu),全網(wǎng)整合營(yíng)銷(xiāo)推廣公司中較早掌握html5技術(shù)的機(jī)構(gòu)。一個(gè)好的品牌網(wǎng)站建設(shè),不能只是一張名片,茫茫網(wǎng)海,想要快速吸引到您客戶的眼球,必須全方位的展現(xiàn)出企業(yè)突出的優(yōu)勢(shì),以求達(dá)到主動(dòng)營(yíng)銷(xiāo)的效果,最終促成成交!
ViewRootImpl的requestLayout開(kāi)啟繪制流程:
這里主要關(guān)注兩點(diǎn):
postSyncBarrier : Handler 的同步屏障。它的作用是可以攔截 Looper 對(duì)同步消息的獲取和分發(fā),加入同步屏障之后,Looper 只會(huì)獲取和處理異步消息,如果沒(méi)有異步消息那么就會(huì)進(jìn)入阻塞狀態(tài)。也就是說(shuō),對(duì)View繪制渲染的處理操作可以優(yōu)先處理(設(shè)置為異步消息)。
Choreographer : 編舞者。統(tǒng)一動(dòng)畫(huà)、輸入和繪制時(shí)機(jī)。也是這章需要重點(diǎn)分析的內(nèi)容。
frameworks\base\core\java\android\view\Choreographer.java
每一個(gè)Looper線程都有自己的Choreographer,其他線程發(fā)送的回調(diào)只能運(yùn)行在對(duì)應(yīng)Choreographer所屬的Looper線程上
Choreographer類(lèi)中有一個(gè)Looper和一個(gè)FrameHandler變量。變量USE_VSYNC用于表示系統(tǒng)是否是用了Vsync同步機(jī)制,該值是通過(guò)讀取系統(tǒng)屬性debug.choreographer.vsync來(lái)獲取的。如果系統(tǒng)使用了Vsync同步機(jī)制,則創(chuàng)建一個(gè)FrameDisplayEventReceiver對(duì)象用于請(qǐng)求并接收Vsync事件,最后Choreographer創(chuàng)建了一個(gè)大小為3的CallbackQueue隊(duì)列數(shù)組,用于保存不同類(lèi)型的Callback。
這里,不同類(lèi)型的Callback包括如下4種:
CallbackQueue是一個(gè)容量為4的數(shù)組,每一個(gè)元素作為頭指針,引出對(duì)應(yīng)類(lèi)型的鏈表,4種事件就是通過(guò)這4個(gè)鏈表來(lái)維護(hù)的。
而FrameHandler中主要處理三類(lèi)消息:
Choreographer提供了兩類(lèi)添加回調(diào)的方式:postCallback 與 postFrameCallback,當(dāng)然對(duì)應(yīng)類(lèi)型也包含delay的方法,算上其實(shí)有4個(gè)方法。
postCallback對(duì)應(yīng)的:
postFrameCallback對(duì)應(yīng)的:
相比之下postCallback更靈活一點(diǎn)。兩者最終都會(huì)調(diào)到:postCallbackDelayedInternal
mCallbackQueues先把對(duì)應(yīng)的callback添加到鏈表上來(lái),然后判斷是否有延遲,如果沒(méi)有則會(huì)馬上執(zhí)行scheduleFrameLocked,如果有,則發(fā)送一個(gè)what為MSG_DO_SCHEDULE_CALLBACK類(lèi)型的定時(shí)消息,等時(shí)間到了再處理,其最終處理也是執(zhí)行scheduleFrameLocked(long now)方法。
這里首先判斷USE_VSYNC,如果使用了VSYNC:走scheduleVsyncLocked,即請(qǐng)求VSYNC信號(hào),最終調(diào)用doFrame,如果沒(méi)使用VSYNC,則通過(guò)消息執(zhí)行doFrame。
那么我們先簡(jiǎn)單了解下請(qǐng)求VSYNC信號(hào)的流程:
mDisplayEventReceiver 對(duì)應(yīng)的是FrameDisplayEventReceiver,它繼承自 DisplayEventReceiver , 主要是用來(lái)接收同步脈沖信號(hào) VSYNC。scheduleVsync()方法通過(guò)底層nativeScheduleVsync()向SurfaceFlinger 服務(wù)注冊(cè),即在下一次脈沖接收后會(huì)調(diào)用 DisplayEventReceiver的dispatchVsync()方法。這里類(lèi)似于訂閱者模式,但是每次調(diào)用nativeScheduleVsync()方法都有且只有一次dispatchVsync()方法回調(diào)。
然后再看看接收VSYNC信號(hào):
底層向應(yīng)用層發(fā)送VSYNC信號(hào),java層通過(guò)dispatchVsync()接收,最后回調(diào)在FrameDisplayEventReceiver的onVsync
可見(jiàn)onVsync()過(guò)程是通過(guò)FrameHandler向主線程Looper發(fā)送了一個(gè)自帶callback的消息 callback為FrameDisplayEventReceiver。 當(dāng)主線程Looper執(zhí)行到該消息時(shí),則調(diào)用FrameDisplayEventReceiver.run()方法,緊接著便是調(diào)用doFrame。
當(dāng)Vsync事件到來(lái)時(shí),順序執(zhí)行4種事件對(duì)應(yīng)CallbackQueue隊(duì)列中注冊(cè)的回調(diào)。
按時(shí)間順序先后執(zhí)行CallbackRecord對(duì)應(yīng)的run方法
接開(kāi)篇講的
mTraversalRunnable對(duì)應(yīng):
run方法被執(zhí)行,所以doTraversal()被執(zhí)行,開(kāi)啟View的繪制流程。
所以整個(gè)繪制過(guò)程總的流程如下所示:
簡(jiǎn)單總結(jié):
參考
本文將從三個(gè)方面介紹Android 圖形系統(tǒng)。
圖形系統(tǒng)提供繪圖和圖形處理支持。
Android 框架提供了各種用于 2D 和 3D 圖形渲染的 API、圖片解碼庫(kù),以及各種Driver支持。
? 繪圖API:2D引擎 Skia,3D引擎 OpenGL ES,RenderScript,OpenCV和Vulkan。
? 圖片解碼庫(kù):jpg,png,gif等。
應(yīng)用開(kāi)發(fā)者可通過(guò)三種方式將圖像繪制到屏幕:
? Canvas : 2D圖形API,Android View樹(shù)實(shí)際的繪制者。
? OpenGL ES : 嵌入式設(shè)備的OpenGL 三維圖形API子集。
? Vulkan :跨平臺(tái)的2D和3D繪圖引擎,Android 7.0后支持,NDK。
整個(gè)圖形系統(tǒng)架構(gòu)是一個(gè)生產(chǎn)者和消費(fèi)者模式,五層依次介紹:
2D繪制:Canvas api / view 的子類(lèi) (button ,list)/自定義view
3D繪制:應(yīng)用直接使用OpenGL 接口繪制圖形(PixelFlinger對(duì)應(yīng)的是openGl 1.0 ,GUP driver 對(duì)應(yīng)的是2.0和3.0)
所有情況下的繪圖都渲染到一個(gè)包含 GraphicBuffer的Surface上,當(dāng)一塊 Surface 顯示在屏幕上時(shí),就是用戶所看到的窗口。
? Canvas:畫(huà)布,2D圖形API,Android View樹(shù)實(shí)際的渲染者。
? Skia繪制:Android4.0之前默認(rèn)使用,主線程通過(guò)CPU完成繪圖指令操作,在復(fù)雜場(chǎng)景下單幀容易超過(guò)16ms導(dǎo)致卡頓。
WindowManagerService(WMS)窗口管理服務(wù),管理系統(tǒng)中所有的窗口。
? 管理window (view的容器)
? Window與surface對(duì)應(yīng),一塊顯示區(qū)域。添加一個(gè)window,就是 WMS 為其分配一塊 Surface 的過(guò)程。
Google 在Android source官網(wǎng)提示:
這里就對(duì)這些控件進(jìn)行簡(jiǎn)單介紹:
Surface : Handle onto a raw buffer that is being managed by the screen compositor.
Surface 對(duì)應(yīng)一塊屏幕緩沖區(qū)。生產(chǎn)者是: SurfaceTexture、MediaRecorder 等,消費(fèi)者是: OpenGL、MediaPlayer 或 CameraDevice等。每個(gè)window對(duì)應(yīng)一個(gè)Surface。Canvas或OpenGL ES等最終都渲染到Surface上。
? Flutter在Android平臺(tái)上也是直接渲染到Surface。例如:一個(gè)Activity/Dialog都是一個(gè)Surface,它承載了上層的圖形數(shù)據(jù),與SurfaceFlinger側(cè)的Layer相對(duì)應(yīng)。
Canvas(畫(huà)布)實(shí)現(xiàn)由 Skia 圖形庫(kù)提供。為了確保兩個(gè)客戶端不會(huì)同時(shí)更新某個(gè)緩沖區(qū),使用以下命令處理畫(huà)布鎖:
使用雙緩沖機(jī)制,有自己的 surface,View只是一個(gè)透明的占位符,Surface可以在后臺(tái)線程中繪制。雙緩沖機(jī)制提高渲染效率,獨(dú)立線程
繪制,提升流暢性。適合一些場(chǎng)景:需要界面迅速更新、UI繪制時(shí)間長(zhǎng)、對(duì)幀率要求較高的情況。
提供訪問(wèn)和控制Surface 相關(guān)的方法 。通過(guò)SurfaceView的getHolder()函數(shù)可以獲取SurfaceHolder對(duì)象,Surface 就在SurfaceHolder對(duì)象內(nèi)。
addCallback(SurfaceHolder.Callbackcallback) /Canvas lockCanvas() /unlockCanvasAndPost(Canvascanvas)
SurfaceTexture: Surface 和 OpenGL ES (GLES) 紋理(Texture)的組合。將圖像流轉(zhuǎn)為 OpenGL 外部紋理。
TextureView:持有 SurfaceTexture,將圖像處理為 OpenGL 紋理更新到 HardwareLayer。
GLSurfaceView:加入 EGL 管理,自帶 GL 上下文和 GL 渲染線程
這些View通常涉及到Android音視頻相關(guān),需要高效的渲染能力。如下面的SurfaceTexture在camera中的應(yīng)用。
簡(jiǎn)稱Buffer, 一個(gè)Buffer包含一幀圖像,Buffer由gralloc分配和回收。Buffer 屬性包含:width, height, format, usage等
BufferQueue 的引入是為了解決顯示和性能問(wèn)題。
? Surface屬于APP進(jìn)程,Layer屬于系統(tǒng)進(jìn)程,如果它們之間只用一個(gè)Buffer,會(huì)存在顯示和性能問(wèn)題。
? 一些Buffer用于繪制,一些Buffer用于顯示,雙方處理完之后,交換一下Buffer,提高效率。
? BufferQueue中包含多個(gè)Buffer對(duì)象。
Android圖形系統(tǒng)包含了兩對(duì)生產(chǎn)者和消費(fèi)者模型,它們都通過(guò)BufferQueue進(jìn)行連接:
1.Canvas和OpenGL ES生產(chǎn)圖形數(shù)據(jù),SurfaceFlinger消費(fèi)圖形數(shù)據(jù)。
2.SurfaceFlinger合成所有圖層的圖形數(shù)據(jù),Display顯示合成結(jié)果。
code:frameworks/native/services/surfaceflinger
? Surface表示APP進(jìn)程的一個(gè)窗口,承載了窗口的圖形數(shù)據(jù)。
? SurfaceFlinger是系統(tǒng)進(jìn)程合成所有窗口的系統(tǒng)服務(wù),負(fù)責(zé)合成所有Surface提供的圖形數(shù)據(jù),然后送顯到屏幕。
? SurfaceFlinger既是上層應(yīng)用的消費(fèi)者,又是Display的生產(chǎn)者,起到了承上啟下的作用。
數(shù)據(jù)流:
合成示意圖:
在介紹Vsync機(jī)制之前先介紹兩個(gè)重要概念:
屏幕刷新率:屏幕每秒鐘可以刷新多少次。60HZ刷新率,16.7ms刷新一次。(120HZ/8.3ms),硬件指標(biāo)。
GPU 繪制幀率:GPU 每秒能夠合成繪制多少幀。
軟件層觸發(fā) View 繪制的時(shí)機(jī)是隨機(jī)的,當(dāng)下一次屏幕刷新時(shí),屏幕從 Frame Buffer 中拿到的數(shù)據(jù)還是“幀1”的數(shù)據(jù),導(dǎo)致“丟幀”。
每隔 16ms 硬件層發(fā)出 vsync 信號(hào),應(yīng)用層接收到此信號(hào)后會(huì)觸發(fā)UI 的渲染流程,同時(shí) vsync 信號(hào)也會(huì)觸發(fā) SurfaceFlinger 讀取Buffer 中的數(shù)據(jù),進(jìn)行合成顯示到屏幕上。
總結(jié):Vsync機(jī)制將 CPU 和 GPU 的開(kāi)始時(shí)間與屏幕刷新強(qiáng)行拖拽到同一起跑線
Android提供的Graphics流程相對(duì)比較復(fù)雜對(duì)其進(jìn)行具象后的流程如下兩張圖所示:
對(duì)于Android開(kāi)發(fā)者來(lái)說(shuō),我們或多或少有了解過(guò)Android圖像顯示的知識(shí)點(diǎn),剛剛學(xué)習(xí)Android開(kāi)發(fā)的人會(huì)知道,在Actvity的onCreate方法中設(shè)置我們的View后,再經(jīng)過(guò)onMeasure,onLayout,onDraw的流程,界面就顯示出來(lái)了;對(duì)Android比較熟悉的開(kāi)發(fā)者會(huì)知道,onDraw流程分為軟件繪制和硬件繪制兩種模式,軟繪是通過(guò)調(diào)用Skia來(lái)操作,硬繪是通過(guò)調(diào)用Opengl ES來(lái)操作;對(duì)Android非常熟悉的開(kāi)發(fā)者會(huì)知道繪制出來(lái)的圖形數(shù)據(jù)最終都通過(guò)GraphiBuffer內(nèi)共享內(nèi)存?zhèn)鬟f給SurfaceFlinger去做圖層混合,圖層混合完成后將圖形數(shù)據(jù)送到幀緩沖區(qū),于是,圖形就在我們的屏幕顯示出來(lái)了。
但我們所知道的Activity或者是應(yīng)用App界面的顯示,只屬于Android圖形顯示的一部分。同樣可以在Android系統(tǒng)上展示圖像的WebView,F(xiàn)lutter,或者是通過(guò)Unity開(kāi)發(fā)的3D游戲,他們的界面又是如何被繪制和顯現(xiàn)出來(lái)的呢?他們和我們所熟悉的Acitvity的界面顯示又有什么異同點(diǎn)呢?我們可以不借助Activity的setView或者InflateView機(jī)制來(lái)實(shí)現(xiàn)在屏幕上顯示出我們想要的界面嗎?Android系統(tǒng)顯示界面的方式又和IOS,或者Windows等系統(tǒng)有什么區(qū)別呢?……
去探究這些問(wèn)題,比僅僅知道Acitvity的界面是如何顯示出來(lái)更加的有價(jià)值,因?yàn)橄胍卮疬@些問(wèn)題,就需要我們真正的掌握Android圖像顯示的底層原理,當(dāng)我們掌握了底層的顯示原理后,我們會(huì)發(fā)現(xiàn)WebView,F(xiàn)lutter或者未來(lái)會(huì)出現(xiàn)的各種新的圖形顯示技術(shù),原來(lái)都是大同小異。
我會(huì)花三篇文章的篇幅,去深入的講解Android圖形顯示的原理,OpenGL ES和Skia的繪制圖像的方式,他們?nèi)绾问褂?,以及他們?cè)贏ndroid中的使用場(chǎng)景,如開(kāi)機(jī)動(dòng)畫(huà),Activity界面的軟件繪制和硬件繪制,以及Flutter的界面繪制。那么,我們開(kāi)始對(duì)Android圖像顯示原理的探索吧。
在講解Android圖像的顯示之前,我會(huì)先講一下屏幕圖像的顯示原理,畢竟我們圖像,最終都是在手機(jī)屏幕上顯示出來(lái)的,了解這一塊的知識(shí)會(huì)讓我們更容易的理解Android在圖像顯示上的機(jī)制。
圖像顯示的完整過(guò)程,分為下面幾個(gè)階段:
圖像數(shù)據(jù)→CPU→顯卡驅(qū)動(dòng)→顯卡(GPU)→顯存(幀緩沖)→顯示器
我詳細(xì)介紹一下這幾個(gè)階段:
實(shí)際上顯卡驅(qū)動(dòng),顯卡和顯存,包括數(shù)模轉(zhuǎn)換模塊都是屬于顯卡的模塊。但為了能能詳細(xì)的講解經(jīng)歷的步驟,這里做了拆分。
當(dāng)顯存中有數(shù)據(jù)后,顯示器又是怎么根據(jù)顯存里面的數(shù)據(jù)來(lái)進(jìn)行界面的顯示的呢?這里以LCD液晶屏為例,顯卡會(huì)將顯存里的數(shù)據(jù),按照從左至右,從上到下的順序同步到屏幕上的每一個(gè)像素晶體管,一個(gè)像素晶體管就代表了一個(gè)像素。
如果我們的屏幕分辨率是1080x1920像素,就表示有1080x1920個(gè)像素像素晶體管,每個(gè)橡素點(diǎn)的顏色越豐富,描述這個(gè)像素的數(shù)據(jù)就越大,比如單色,每個(gè)像素只需要1bit,16色時(shí),只需要4bit,256色時(shí),就需要一個(gè)字節(jié)。那么1080x1920的分辨率的屏幕下,如果要以256色顯示,顯卡至少需要1080x1920個(gè)字節(jié),也就是2M的大小。
剛剛說(shuō)了,屏幕上的像素?cái)?shù)據(jù)是從左到右,從上到下進(jìn)行同步的,當(dāng)這個(gè)過(guò)程完成了,就表示一幀繪制完成了,于是會(huì)開(kāi)始下一幀的繪制,大部分的顯示屏都是以60HZ的頻率在屏幕上繪制完一幀,也就是16ms,并且每次繪制新的一幀時(shí),都會(huì)發(fā)出一個(gè)垂直同步信號(hào)(VSync)。我們已經(jīng)知道,圖像數(shù)據(jù)都是放在幀緩沖中的,如果幀緩沖的緩沖區(qū)只有一個(gè),那么屏幕在繪制這一幀的時(shí)候,圖像數(shù)據(jù)便沒(méi)法放入幀緩沖中了,只能等待這一幀繪制完成,在這種情況下,會(huì)有很大了效率問(wèn)題。所以為了解決這一問(wèn)題,幀緩沖引入兩個(gè)緩沖區(qū),即 雙緩沖機(jī)制 。雙緩沖雖然能解決效率問(wèn)題,但會(huì)引入一個(gè)新的問(wèn)題。當(dāng)屏幕這一幀還沒(méi)繪制完成時(shí),即屏幕內(nèi)容剛顯示一半時(shí),GPU 將新的一幀內(nèi)容提交到幀緩沖區(qū)并把兩個(gè)緩沖區(qū)進(jìn)行交換后,顯卡的像素同步模塊就會(huì)把新的一幀數(shù)據(jù)的下半段顯示到屏幕上,造成畫(huà)面撕裂現(xiàn)象。
為了解決撕裂問(wèn)題,就需要在收到垂直同步的時(shí)候才將幀緩沖中的兩個(gè)緩沖區(qū)進(jìn)行交換。Android4.1黃油計(jì)劃中有一個(gè)優(yōu)化點(diǎn),就是CPU和GPU都只有收到垂直同步的信號(hào)時(shí),才會(huì)開(kāi)始進(jìn)行圖像的繪制操作,以及緩沖區(qū)的交換工作。
我們已經(jīng)了解了屏幕圖像顯示的原理了,那么接著開(kāi)始對(duì)Android圖像顯示的學(xué)習(xí)。
從上一章已經(jīng)知道,計(jì)算機(jī)渲染界面必須要有GPU和幀緩沖。對(duì)于Linux系統(tǒng)來(lái)說(shuō),用戶進(jìn)程是沒(méi)法直接操作幀緩沖的,但我們想要顯示圖像就必須要操作幀緩沖,所以Linux系統(tǒng)設(shè)計(jì)了一個(gè)虛擬設(shè)備文件,來(lái)作為對(duì)幀緩沖的映射,通過(guò)對(duì)該文件的I/O讀寫(xiě),我們就可以實(shí)現(xiàn)讀寫(xiě)屏操作。幀緩沖對(duì)應(yīng)的設(shè)備文件于/dev/fb* ,*表示對(duì)多個(gè)顯示設(shè)備的支持, 設(shè)備號(hào)從0到31,如/dev/fb0就表示第一塊顯示屏,/dev/fb1就表示第二塊顯示屏。對(duì)于Android系統(tǒng)來(lái)說(shuō),默認(rèn)使用/dev/fb0這一個(gè)設(shè)幀緩沖作為主屏幕,也就是我們的手機(jī)屏幕。我們Android手機(jī)屏幕上顯示的圖像數(shù)據(jù),都是存儲(chǔ)在/dev/fb0里,早期AndroidStuio中的DDMS工具實(shí)現(xiàn)截屏的原理就是直接讀取/dev/fb0設(shè)備文件。
我們知道了手機(jī)屏幕上的圖形數(shù)據(jù)都存儲(chǔ)在幀緩沖中,所以Android手機(jī)圖像界面的原理就是將我們的圖像數(shù)據(jù)寫(xiě)入到幀緩沖內(nèi)。那么,寫(xiě)入到幀緩沖的圖像數(shù)據(jù)是怎么生成的,又是怎樣加工的呢?圖形數(shù)據(jù)是怎樣送到幀緩沖去的,中間經(jīng)歷了哪些步驟和過(guò)程呢?了解了這幾個(gè)問(wèn)題,我們就了解了Android圖形渲染的原理,那么帶著這幾個(gè)疑問(wèn),接著往下看。
想要知道圖像數(shù)據(jù)是怎么產(chǎn)生的,我們需要知道 圖像生產(chǎn)者 有哪些,他們分別是如何生成圖像的,想要知道圖像數(shù)據(jù)是怎么被消費(fèi)的,我們需要知道 圖像消費(fèi)者 有哪些,他們又分別是如何消費(fèi)圖像的,想要知道中間經(jīng)歷的步驟和過(guò)程,我們需要知道 圖像緩沖區(qū) 有哪些,他們是如何被創(chuàng)建,如何分配存儲(chǔ)空間,又是如何將數(shù)據(jù)從生產(chǎn)者傳遞到消費(fèi)者的,圖像顯示是一個(gè)很經(jīng)典的消費(fèi)者生產(chǎn)者的模型,只有對(duì)這個(gè)模型各個(gè)模塊的擊破,了解他們之間的流動(dòng)關(guān)系,我們才能找到一條更容易的路徑去掌握Android圖形顯示原理。我們看看谷歌提供的官方的架構(gòu)圖是怎樣描述這一模型的模塊及關(guān)系的。
如圖, 圖像的生產(chǎn)者 主要有MediaPlayer,CameraPrevier,NDK,OpenGl ES。MediaPlayer和Camera Previer是通過(guò)直接讀取圖像源來(lái)生成圖像數(shù)據(jù),NDK(Skia),OpenGL ES是通過(guò)自身的繪制能力生產(chǎn)的圖像數(shù)據(jù); 圖像的消費(fèi)者 有SurfaceFlinger,OpenGL ES Apps,以及HAL中的Hardware Composer。OpenGl ES既可以是圖像的生產(chǎn)者,也可以是圖像的消費(fèi)者,所以它也放在了圖像消費(fèi)模塊中; 圖像緩沖區(qū) 主要有Surface以及前面提到幀緩沖。
Android圖像顯示的原理,會(huì)僅僅圍繞 圖像的生產(chǎn)者 , 圖像的消費(fèi)者 , 圖像緩沖區(qū) 來(lái)展開(kāi),在這一篇文章中,我們先看看Android系統(tǒng)中的圖像消費(fèi)者。
SurfaceFlinger是Android系統(tǒng)中最重要的一個(gè)圖像消費(fèi)者,Activity繪制的界面圖像,都會(huì)傳遞到SurfaceFlinger來(lái),SurfaceFlinger的作用主要是接收?qǐng)D像緩沖區(qū)數(shù)據(jù),然后交給HWComposer或者OpenGL做合成,合成完成后,SurfaceFlinger會(huì)把最終的數(shù)據(jù)提交給幀緩沖。
那么SurfaceFlinger是如何接收?qǐng)D像緩沖區(qū)的數(shù)據(jù)的呢?我們需要先了解一下Layer(層)的概念,一個(gè)Layer包含了一個(gè)Surface,一個(gè)Surface對(duì)應(yīng)了一塊圖形緩沖區(qū),而一個(gè)界面是由多個(gè)Surface組成的,所以他們會(huì)一一對(duì)應(yīng)到SurfaceFlinger的Layer中。SurfaceFlinger通過(guò)讀取Layer中的緩沖數(shù)據(jù),就相當(dāng)于讀取界面上Surface的圖像數(shù)據(jù)。Layer本質(zhì)上是 Surface和SurfaceControl的組合 ,Surface是圖形生產(chǎn)者和圖像消費(fèi)之間傳遞數(shù)據(jù)的緩沖區(qū),SurfaceControl是Surface的控制類(lèi)。
前面在屏幕圖像顯示原理中講到,為了防止圖像的撕裂,Android系統(tǒng)會(huì)在收到VSync垂直同步時(shí)才會(huì)開(kāi)始處理圖像的繪制和合成工作,而Surfaceflinger作為一個(gè)圖像的消費(fèi)者,同樣也是遵守這一規(guī)則,所以我們通過(guò)源碼來(lái)看看SurfaceFlinger是如何在這一規(guī)則下,消費(fèi)圖像數(shù)據(jù)的。
SurfaceFlinger專門(mén)創(chuàng)建了一個(gè)EventThread線程用來(lái)接收VSync。EventThread通過(guò)Socket將VSync信號(hào)同步到EventQueue中,而EventQueue又通過(guò)回調(diào)的方式,將VSync信號(hào)同步到SurfaceFlinger內(nèi)。我們看一下源碼實(shí)現(xiàn)。
上面主要是SurfaceFlinger初始化接收VSYNC垂直同步信號(hào)的操作,主要有這幾個(gè)過(guò)程:
經(jīng)過(guò)上面幾個(gè)步驟,我們接收VSync的初始化工作都準(zhǔn)備好了,EventThread也開(kāi)始運(yùn)轉(zhuǎn)了,接著看一下EventThread的運(yùn)轉(zhuǎn)函數(shù)threadLoop做的事情。
threadLoop主要是兩件事情
mConditon又是怎么接收VSync的呢?我們來(lái)看一下
可以看到,mCondition的VSync信號(hào)實(shí)際是DispSyncSource通過(guò)onVSyncEvent回調(diào)傳入的,但是DispSyncSource的VSync又是怎么接收的呢?在上面講到的SurfaceFlinger的init函數(shù),在創(chuàng)建EventThread的實(shí)現(xiàn)中,我們可以發(fā)現(xiàn)答案—— mPrimaryDispSync 。
DispSyncSource的構(gòu)造方法傳入了mPrimaryDispSync,mPrimaryDispSync實(shí)際是一個(gè)DispSyncThread線程,我們看看這個(gè)線程的threadLoop方法
DispSyncThread的threadLoop會(huì)通過(guò)mPeriod來(lái)判斷是否進(jìn)行阻塞或者進(jìn)行VSync回調(diào),那么mPeriod又是哪兒被設(shè)置的呢?這里又回到SurfaceFlinger了,我們可以發(fā)現(xiàn)在SurfaceFlinger的 resyncToHardwareVsync 函數(shù)中有對(duì)mPeriod的賦值。
可以看到,這里最終通過(guò)HWComposer,也就是硬件層拿到了period。終于追蹤到了VSync的最終來(lái)源了, 它從HWCompser產(chǎn)生,回調(diào)至DispSync線程,然后DispSync線程回調(diào)到DispSyncSource,DispSyncSource又回調(diào)到EventThread,EventThread再通過(guò)Socket分發(fā)到MessageQueue中 。
我們已經(jīng)知道了VSync信號(hào)來(lái)自于HWCompser,但SurfaceFlinger并不會(huì)一直監(jiān)聽(tīng)VSync信號(hào),監(jiān)聽(tīng)VSync的線程大部分時(shí)間都是休眠狀態(tài),只有需要做合成工作時(shí),才會(huì)監(jiān)聽(tīng)VSync,這樣即保證圖像合成的操作能和VSync保持一致,也節(jié)省了性能。SurfaceFlinger提供了一些主動(dòng)注冊(cè)監(jiān)聽(tīng)VSync的操作函數(shù)。
可以看到,只有當(dāng)SurfaceFlinger調(diào)用 signalTransaction 或者 signalLayerUpdate 函數(shù)時(shí),才會(huì)注冊(cè)監(jiān)聽(tīng)VSync信號(hào)。那么signalTransaction或者signalLayerUpdate什么時(shí)候被調(diào)用呢?它可以由圖像的生產(chǎn)者通知調(diào)用,也可以由SurfaceFlinger根據(jù)自己的邏輯來(lái)判斷是否調(diào)用。
現(xiàn)在假設(shè)App層已經(jīng)生成了我們界面的圖像數(shù)據(jù),并調(diào)用了 signalTransaction 通知SurfaceFlinger注冊(cè)監(jiān)聽(tīng)VSync,于是VSync信號(hào)便會(huì)傳遞到了MessageQueue中了,我們接著看看MessageQueue又是怎么處理VSync的吧。
MessageQueue收到VSync信號(hào)后,最終回調(diào)到了SurfaceFlinger的 onMessageReceived 中,當(dāng)SurfaceFlinger接收到VSync后,便開(kāi)始以一個(gè)圖像消費(fèi)者的角色來(lái)處理圖像數(shù)據(jù)了。我們接著看SurfaceFlinger是以什么樣的方式消費(fèi)圖像數(shù)據(jù)的。
VSync信號(hào)最終被SurfaceFlinger的onMessageReceived函數(shù)中的INVALIDATE模塊處理。
INVALIDATE的流程如下:
handleMessageTransaction的處理比較長(zhǎng),處理的事情也比較多,它主要做的事情有這些
handleMessageRefresh函數(shù),便是SurfaceFlinger真正處理圖層合成的地方,它主要下面五個(gè)步驟。
我會(huì)詳細(xì)介紹每一個(gè)步驟的具體操作
合成前預(yù)處理會(huì)判斷Layer是否發(fā)生變化,當(dāng)Layer中有新的待處理的Buffer幀(mQueuedFrames0),或者mSidebandStreamChanged發(fā)生了變化, 都表示Layer發(fā)生了變化,如果變化了,就調(diào)用signalLayerUpdate,注冊(cè)下一次的VSync信號(hào)。如果Layer沒(méi)有發(fā)生變化,便只會(huì)做這一次的合成工作,不會(huì)注冊(cè)下一次VSync了。
重建Layer棧會(huì)遍歷Layer,計(jì)算和存儲(chǔ)每個(gè)Layer的臟區(qū), 然后和當(dāng)前的顯示設(shè)備進(jìn)行比較,看Layer的臟區(qū)域是否在顯示設(shè)備的顯示區(qū)域內(nèi),如果在顯示區(qū)域內(nèi)的話說(shuō)明該layer是需要繪制的,則更新到顯示設(shè)備的VisibleLayersSortedByZ列表中,等待被合成
rebuildLayerStacks中最重要的一步是 computeVisibleRegions ,也就是對(duì)Layer的變化區(qū)域和非透明區(qū)域的計(jì)算,為什么要對(duì)變化區(qū)域做計(jì)算呢?我們先看看SurfaceFlinger對(duì)界面顯示區(qū)域的分類(lèi):
還是以這張圖做例子,可以看到我們的狀態(tài)欄是半透明的,所以它是一個(gè)opaqueRegion區(qū)域,微信界面和虛擬按鍵是完全不透明的,他是一個(gè)visibleRegion,除了這三個(gè)Layer外,還有一個(gè)我們看不到的Layer——壁紙,它被上方visibleRegion遮擋了,所以是coveredRegion
對(duì)這幾個(gè)區(qū)域的概念清楚了,我們就可以去了解computeVisibleRegions中做的事情了,它主要是這幾步操作:
網(wǎng)站題目:android圖形,Android圖形密碼在哪設(shè)置
標(biāo)題路徑:http://sd-ha.com/article36/phhjsg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、、網(wǎng)站建設(shè)、微信公眾號(hào)、網(wǎng)站維護(hù)、品牌網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)