SurfaceFlinger 和 Hardware Composer
擁有圖形數(shù)據(jù)緩沖區(qū)是很精彩的,但是當你在你的設(shè)備屏幕上看到它們時生活甚至更美好。那就是 SurfaceFlinger 和 Hardware Composer HAL 做的事情。
SurfaceFlinger
SurfaceFlinger 的角色是接收來自于多個源的數(shù)據(jù)緩沖區(qū),組合它們,并將它們發(fā)送給顯示設(shè)備。曾經(jīng)一段時期這是通過軟將數(shù)據(jù)塊傳送到硬件 framebuffer (比如 /dev/graphics/fb0) 完成的,但那些日子已經(jīng)過去許久了。
當一個應(yīng)用來到前臺,WindowManager 服務(wù)向 SurfaceFlinger 請求一塊繪制 surface。SurfaceFlinger 創(chuàng)建一個 layer(其主要的組件是一個 BufferQueue),而
SurfaceFlinger 將作為其消費者。生產(chǎn)者端的 Binder 對象通過 WindowManager 被傳遞給應(yīng)用,然后它可以開始直接向 SurfaceFlinger 發(fā)送幀。
注意:這一節(jié)使用 SurfaceFlinger 術(shù)語,WindowManager 使用術(shù)語 window 而不是 layer. . . 并使用 layer 表示其它一些東西。( 可以認為 SurfaceFlinger 應(yīng)該被稱為LayerFlinger。)
大多數(shù)應(yīng)用于任何時間在屏幕上具有三個 layers:屏幕頂部的狀態(tài)欄,底部或側(cè)面的導(dǎo)航欄,以及應(yīng)用程序 UI。一些應(yīng)用具有更多,一些更少(比如默認的 home 應(yīng)用有一個單獨的壁紙 layer,而全屏游戲可能會隱藏狀態(tài)欄)。每個 layer 可以被獨立地更新。狀態(tài)欄和導(dǎo)航欄由一個系統(tǒng)進程渲染,而應(yīng)用 layers 有應(yīng)用渲染,兩者之間沒有協(xié)調(diào)。
設(shè)備顯示器以一定頻率刷新,在手機和平板上典型的是每秒鐘 60 幀。如果顯示的內(nèi)容在刷新中間更新,則將看到花屏;因此只在周期中間更新內(nèi)容很重要。當可以安全更新內(nèi)容時,系統(tǒng)收到來自于顯示器的信號。出于歷史原因我們稱它為 VSYNC 信號。
刷新頻率可能會隨著時間而改變,比如依賴于當前的條件,一些設(shè)備的范圍在 58 到 62fps。對于 HDMI 連接的電視機,理論上可以下降到 24 或 48Hz 來匹配視頻。由于每個刷新周期我們只能更新屏幕一次,以 200 fps 提交緩沖區(qū)來顯示將是巨大的浪費,因為大多數(shù)幀將從不會被看到。
不是在應(yīng)用提交緩沖區(qū)時采取行動,SurfaceFlinger 而是在顯示器為顯示一些新東西做好準備時才喚醒。
當 VSYNC 信號到達時,SurfaceFlinger 遍歷它的 layers 列表尋找新的緩沖區(qū)。如果它找到了一個新的,它獲取它;如果沒有,它繼續(xù)使用之前獲取的緩沖區(qū)。SurfaceFlinger 總是想要一些東西來顯示,因此它會掛在一個緩沖區(qū)上。如果沒有緩沖區(qū)已經(jīng)提交給一個 layer,則該 layer 被忽略。
在 SurfaceFlinger 收集了所有可見的 layers 的緩沖區(qū)之后,它詢問 Hardware Composer 應(yīng)該如何執(zhí)行組合。
Hardware Composer
Hardware Composer HAL (HWC) 在 Android 3.0 中被引入,并已經(jīng)穩(wěn)定發(fā)展多年。它的主要目標是通過可用硬件確定組合緩沖區(qū)的最有效方式。作為 HAL,其實現(xiàn)是特定于設(shè)備的,且通常由顯示設(shè)備硬件 OEM 完成。
當考慮 覆蓋平面(overlay planes) 時,這種方法的價值很容易識別,其目的是在顯示硬件而不是 GPU 中將多個緩沖區(qū)組合在一起。比如,考慮一個典型的豎直方向的 Android 手機,其狀態(tài)欄在頂部,導(dǎo)航欄在底部,應(yīng)用內(nèi)容在其余的地方。每個 layers 的內(nèi)容在單獨的緩沖區(qū)中。你可以使用下列方法中的一種處理組合:
-
將應(yīng)用內(nèi)容渲染到暫存緩沖區(qū)中,然后將狀態(tài)欄渲染在它的上面,導(dǎo)航欄位于其上,最后將暫存緩沖區(qū)傳遞給顯示硬件。
-
將所有三個緩沖區(qū)傳遞給顯示硬件,并告訴它從不同的緩沖區(qū)為不同的屏幕部分讀取數(shù)據(jù)。
后一種方法可以顯著提高效率。
顯示處理器功能差異很大。overlays 的數(shù)量,layers 是否可以旋轉(zhuǎn)或混合,以及位置和重疊上的限制,可能非常難以通過一個 API 來描述。HWC 試圖通過一系列的決定容納這些多樣性:
SurfaceFlinger 為 HWC 提供完整的 layers 的列表并詢問,“你想要如何處理它?”。
HWC 通過將每個 layer 標記為 overlay 或 GLES composition 來進行響應(yīng)。
SurfaceFlinger 關(guān)心任何 GLES composition,并把輸出緩沖區(qū)傳給 HWC,讓 HWC 處理其余的事情。
由于硬件供應(yīng)商可以定制或裁剪決定作出的代碼,因此可以從每個設(shè)備中獲得最佳性能。
當屏幕上的東西沒有改變時,overlay 平面可能比 GL composition 更低效。當 overlay 內(nèi)容具有透明像素且覆蓋的 layers 被混合在一起時尤其如此。在這種情況下,HWC 可以選擇為一些或所有 layers 請求 GLES composition 并保留組合的緩沖區(qū)。如果 SurfaceFlinger 回來請求組合相同的緩沖區(qū)集合,HWC 可以繼續(xù)展示之前組合好的臨時緩沖區(qū)。這可以提升空閑的設(shè)備的電池續(xù)航能力。
運行 Android 4.4 及更新版本的設(shè)備典型地支持四個 overlay 平面。試圖組合比 overlays 更多的 layers 會導(dǎo)致系統(tǒng)為它們中的一些使用 GLES composition,這意味著一個應(yīng)用使用的 layers 的數(shù)量可能對電源消耗和性能有著重大的影響。
虛擬顯示器
SurfaceFlinger 支持一個主顯示器(比如手機或平板內(nèi)置的東西),一個外部顯示器(比如通過 HDMI 連接的電視機),以及一個或多個使組合后的輸出在系統(tǒng)中可用的虛擬顯示器。虛擬顯示器可用于記錄屏幕或通過網(wǎng)絡(luò)發(fā)送。
虛擬顯示器可以共享主顯示器相同的 layers 集合(layer 棧)或擁有它們自己的集合。虛擬顯示器沒有 VSYNC,因此主顯示器的 VSYNC 用于觸發(fā)所有顯示器的組合
(composition) 。
在老版本的 Android 中,虛擬顯示器總是通過 GLES 組合,而 Hardware Composer 只管理主顯示器的組合。在 Android 4.4 中,Hardware Composer 獲得了參與虛擬顯示器組合的能力。
如你期待的那樣,為一個虛擬顯示器產(chǎn)生的幀被寫入 BufferQueue。
案例研究:screenrecord
screenrecord 命令 允許你將屏幕上出現(xiàn)的所有東西記錄為磁盤上的 .mp4 文件。為了實現(xiàn)它,我們不得不從 SurfaceFlinger 接收組合之后的幀,將它們寫入視頻編碼器,然后將編碼的視頻數(shù)據(jù)寫入一個文件。視頻編解碼由一個單獨的進程 (mediaserver) 管理,因此我們不得不在系統(tǒng)中移動巨大的圖形緩沖區(qū)。使這件事情更具挑戰(zhàn)性的是,我們還要試圖以全解析度記錄 60fps 的視頻。使這件事情高效工作的關(guān)鍵是 BufferQueue。
MediaCodec 類允許一個應(yīng)用以緩沖區(qū)中的原始字節(jié)提供數(shù)據(jù),或通過一個 Surface。當 screenrecord 請求訪問一個視頻編碼器時,mediaserver 創(chuàng)建一個 BufferQueue,將它自己與消費者一端相連,然后將生產(chǎn)者端作為一個 Surface 傳回給 screenrecord。
screenrecord 命令然后請求 SurfaceFlinger 創(chuàng)建一個鏡像主顯示器的虛擬顯示器 (比如它具有所有相同的 layers),然后指示它將輸出發(fā)送給來自于 mediaserver 的 Surface。在這種情況下,SurfaceFlinger 是緩沖區(qū)的生產(chǎn)者而不是消費者。
配置完成之后,screenrecord 等待編碼的數(shù)據(jù)出現(xiàn)。隨著應(yīng)用的繪制,它們的緩沖區(qū)進入 SurfaceFlinger,SurfaceFlinger 將它們組合為一個單獨的緩沖區(qū)并直接發(fā)送給 mediaserver 中的視頻編碼器。screenrecord 進程甚至從來不會看到完整的幀。在內(nèi)部,mediaserver 有著它自己的移動緩沖區(qū)的方式,即通過句柄傳遞數(shù)據(jù),以最小化開銷。
案例研究:模擬二次顯示
WindowManager 可以請求 SurfaceFlinger 創(chuàng)建一個可見的 layer,其中 SurfaceFlinger 作為 BufferQueue 的消費者。它還可以請求 SurfaceFlinger 創(chuàng)建一個虛擬顯示器,其中 SurfaceFlinger 作為 BufferQueue 的生產(chǎn)者。如果你將它們連接到一起會如何呢,配置一個虛擬顯示器顯示渲染到一個可見 layer 的東西?
你創(chuàng)建了一個閉環(huán),其中組合后的屏幕出現(xiàn)在一個窗口中。然后窗口現(xiàn)在是組合后的輸出的一部分了,因此在下一次刷新窗口內(nèi)組合后的圖像將也顯示窗口的內(nèi)容(然后 海龜下面還是海龜一路下來)。為了看到這種行為,啟用設(shè)置中的 Developer options,選擇 Simulate secondary displays,并啟用一個窗口。為了加分,請使用 screenrecord 捕獲啟用顯示的行為,然后逐幀播放。
原文
總結(jié)
以上是生活随笔為你收集整理的SurfaceFlinger 和 Hardware Composer的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HiKey960 开发板 android
- 下一篇: EGLSurfaces 和 OpenGL