轉(zhuǎn)自:https://source.android.com/devices/graphics/?hl=zh-cn
SurfaceFlinger 和 Hardware Composer
擁有圖形數(shù)據(jù)緩沖區(qū)的確不錯(cuò)刑桑,如果還能在設(shè)備屏幕上查看它們就更是錦上添花了。這正是 SurfaceFlinger 和 Hardware Composer HAL 的用武之地善茎。
SurfaceFlinger
SurfaceFlinger 的作用是接受來自多個(gè)來源的數(shù)據(jù)緩沖區(qū)硬梁,對(duì)它們進(jìn)行合成佩憾,然后發(fā)送到顯示設(shè)備度陆。以前亮蒋,該過程通過軟件到硬件幀緩沖區(qū)(例如/dev/graphics/fb0)的位塊傳輸來實(shí)現(xiàn),但是這樣的日子已經(jīng)遠(yuǎn)去负甸。
當(dāng)應(yīng)用進(jìn)入前臺(tái)時(shí)流强,WindowManager 服務(wù)會(huì)向 SurfaceFlinger 請(qǐng)求一個(gè)繪圖 Surface。SurfaceFlinger 會(huì)創(chuàng)建一個(gè)其主要組件為 BufferQueue 的層呻待,而 SurfaceFlinger 是其消耗方打月。生產(chǎn)方端的 Binder 對(duì)象通過 WindowManager 傳遞到應(yīng)用,然后應(yīng)用可以開始直接將幀發(fā)送到 SurfaceFlinger蚕捉。
注意:盡管本部分使用 SurfaceFlinger 術(shù)語奏篙,但 WindowManager 會(huì)使用術(shù)語“窗口”(而不是“層”)…而將“層”用來表示其他內(nèi)容。(有人認(rèn)為 SurfaceFlinger 實(shí)際上應(yīng)稱為 LayerFlinger迫淹。)
大多數(shù)應(yīng)用通常在屏幕上有三個(gè)層:屏幕頂部的狀態(tài)欄秘通、底部或側(cè)面的導(dǎo)航欄以及應(yīng)用的界面。有些應(yīng)用會(huì)擁有更多或更少的層(例如敛熬,默認(rèn)主屏幕應(yīng)用有一個(gè)單獨(dú)的壁紙層肺稀,而全屏游戲可能會(huì)隱藏狀態(tài)欄)。每個(gè)層都可以單獨(dú)更新应民。狀態(tài)欄和導(dǎo)航欄由系統(tǒng)進(jìn)程渲染盹靴,而應(yīng)用層由應(yīng)用渲染,兩者之間不進(jìn)行協(xié)調(diào)瑞妇。
設(shè)備顯示會(huì)按一定速率刷新稿静,在手機(jī)和平板電腦上通常為每秒 60 幀。如果顯示內(nèi)容在刷新期間更新辕狰,則會(huì)出現(xiàn)撕裂現(xiàn)象改备;因此,請(qǐng)務(wù)必只在周期之間更新內(nèi)容蔓倍。在可以安全更新內(nèi)容時(shí)悬钳,系統(tǒng)便會(huì)收到來自顯示設(shè)備的信號(hào)盐捷。由于歷史原因,我們將該信號(hào)稱為 VSYNC 信號(hào)默勾。
刷新率可能會(huì)隨時(shí)間而變化碉渡,例如,一些移動(dòng)設(shè)備的刷新率范圍在 58 fps 到 62 fps 之間母剥,具體要視當(dāng)前條件而定滞诺。對(duì)于連接了 HDMI 的電視,刷新率在理論上可以下降到 24 Hz 或 48 Hz环疼,以便與視頻相匹配习霹。由于每個(gè)刷新周期只能更新屏幕一次,因此以 200 fps 的刷新率為顯示設(shè)備提交緩沖區(qū)只是在做無用功炫隶,因?yàn)榇蠖鄶?shù)幀永遠(yuǎn)不會(huì)被看到淋叶。SurfaceFlinger 不會(huì)在應(yīng)用提交緩沖區(qū)時(shí)執(zhí)行操作,而是在顯示設(shè)備準(zhǔn)備好接收新的緩沖區(qū)時(shí)才會(huì)喚醒伪阶。
當(dāng) VSYNC 信號(hào)到達(dá)時(shí)煞檩,SurfaceFlinger 會(huì)遍歷它的層列表,以尋找新的緩沖區(qū)栅贴。如果找到新的緩沖區(qū)斟湃,它會(huì)獲取該緩沖區(qū);否則筹误,它會(huì)繼續(xù)使用以前獲取的緩沖區(qū)。SurfaceFlinger 總是需要可顯示的內(nèi)容癣缅,因此它會(huì)保留一個(gè)緩沖區(qū)厨剪。如果在某個(gè)層上沒有提交緩沖區(qū),則該層會(huì)被忽略友存。
SurfaceFlinger 在收集可見層的所有緩沖區(qū)之后祷膳,便會(huì)詢問 Hardware Composer 應(yīng)如何進(jìn)行合成。
Hardware Composer
Hardware Composer HAL (HWC) 是在 Android 3.0 中推出的屡立,并且多年來一直都在不斷演進(jìn)直晨。它主要是用來確定通過可用硬件來合成緩沖區(qū)的最有效方法。作為 HAL膨俐,其實(shí)現(xiàn)是特定于設(shè)備的勇皇,而且通常由顯示設(shè)備硬件原始設(shè)備制造商 (OEM) 完成。
當(dāng)考慮疊加平面時(shí)焚刺,很容易發(fā)現(xiàn)這種方法的好處敛摘。它的目的是在顯示硬件(而不是 GPU)中將多個(gè)緩沖區(qū)合成在一起。例如乳愉,假設(shè)有一部處于縱向模式的普通 Android 手機(jī)兄淫,其狀態(tài)欄在頂部屯远,導(dǎo)航欄在底部,其他地方為應(yīng)用內(nèi)容捕虽。每個(gè)層的內(nèi)容都在單獨(dú)的緩沖區(qū)中慨丐。您可以使用以下任一方法處理合成:
將應(yīng)用內(nèi)容渲染到暫存緩沖區(qū)中,然后在其上渲染狀態(tài)欄泄私,再在其上渲染導(dǎo)航欄房揭,最后將暫存緩沖區(qū)傳送到顯示硬件。
將三個(gè)緩沖區(qū)全部傳送到顯示硬件挖滤,并告知它從不同的緩沖區(qū)讀取屏幕不同部分的數(shù)據(jù)崩溪。
后一種方法可以顯著提高效率。
顯示處理器功能差異很大斩松。疊加層的數(shù)量(無論層是否可以旋轉(zhuǎn)或混合)以及對(duì)定位和疊加的限制很難通過 API 表達(dá)伶唯。HWC 會(huì)嘗試通過一系列決策來適應(yīng)這種多樣性:
SurfaceFlinger 向 HWC 提供一個(gè)完整的層列表,并詢問“您希望如何處理這些層惧盹?”
HWC 的響應(yīng)方式是將每個(gè)層標(biāo)記為疊加層或 GLES 合成乳幸。
SurfaceFlinger 會(huì)處理所有 GLES 合成,將輸出緩沖區(qū)傳送到 HWC钧椰,并讓 HWC 處理其余部分粹断。
由于硬件供應(yīng)商可以定制決策代碼,因此可以在每臺(tái)設(shè)備上實(shí)現(xiàn)最佳性能嫡霞。
當(dāng)屏幕上的內(nèi)容沒有變化時(shí)瓶埋,疊加平面的效率可能會(huì)低于 GL 合成。當(dāng)疊加層內(nèi)容具有透明像素且疊加層混合在一起時(shí)诊沪,尤其如此养筒。在此類情況下,HWC 可以選擇為部分或全部層請(qǐng)求 GLES 合成端姚,并保留合成的緩沖區(qū)晕粪。如果 SurfaceFlinger 返回要求合成同一組緩沖區(qū),HWC 可以繼續(xù)顯示先前合成的暫存緩沖區(qū)渐裸。這可以延長閑置設(shè)備的電池續(xù)航時(shí)間巫湘。
運(yùn)行 Android 4.4 或更高版本的設(shè)備通常支持 4 個(gè)疊加平面。嘗試合成多于疊加層的層會(huì)導(dǎo)致系統(tǒng)對(duì)其中一些層使用 GLES 合成昏鹃,這意味著應(yīng)用使用的層數(shù)會(huì)對(duì)功耗和性能產(chǎn)生重大影響尚氛。
虛擬顯示設(shè)備
SurfaceFlinger 支持一個(gè)主要顯示設(shè)備(即內(nèi)置在手機(jī)或平板電腦中的顯示屏)、一個(gè)外部顯示設(shè)備(如通過 HDMI 連接的電視)以及一個(gè)或多個(gè)令合成的輸出在系統(tǒng)中可用的虛擬顯示設(shè)備洞渤。虛擬顯示設(shè)備可用于記錄屏幕或通過網(wǎng)絡(luò)發(fā)送屏幕怠褐。
虛擬顯示設(shè)備可以與主顯示設(shè)備共享相同的一組層(層堆疊),也可擁有自己的一組層您宪。虛擬顯示設(shè)備沒有 VSYNC奈懒,因此主顯示設(shè)備的 VSYNC 用于為所有顯示設(shè)備觸發(fā)合成奠涌。
在舊版本的 Android 中,虛擬顯示設(shè)備總是通過 GLES 合成磷杏,而 Hardware Composer 管理的合成僅用于主要顯示設(shè)備溜畅。在 Android 4.4 中,Hardware Composer 能夠參與虛擬顯示設(shè)備合成极祸。
正如您所預(yù)期的慈格,為虛擬顯示設(shè)備生成的幀會(huì)寫入 BufferQueue。
案例研究:screenrecord
screenrecord 命令可讓您將屏幕上顯示的所有內(nèi)容作為一個(gè) .mp4 文件記錄在磁盤上遥金。為此浴捆,我們必須從 SurfaceFlinger 接收合成的幀,將它們寫入視頻編碼器稿械,然后將已編碼的視頻數(shù)據(jù)寫入一個(gè)文件选泻。視頻編解碼器由單獨(dú)的進(jìn)程 (mediaserver) 進(jìn)行管理,因此我們必須在系統(tǒng)中移動(dòng)大量圖形緩沖區(qū)美莫。為了使其更具挑戰(zhàn)性页眯,我們嘗試以全分辨率錄制 60 fps 的視頻。高效完成這項(xiàng)工作的關(guān)鍵是 BufferQueue厢呵。
MediaCodec 類允許應(yīng)用以緩沖區(qū)中的原始字節(jié)或通過Surface來提供數(shù)據(jù)窝撵。當(dāng) screenrecord 請(qǐng)求訪問視頻編碼器時(shí),mediaserver 會(huì)創(chuàng)建一個(gè) BufferQueue襟铭,將其自身連接到消耗方端碌奉,然后將生產(chǎn)方端作為 Surface 傳回到 screenrecord。
然后寒砖,screenrecord 命令要求 SurfaceFlinger 創(chuàng)建一個(gè)鏡像主顯示設(shè)備的虛擬顯示設(shè)備(即赐劣,它具有完全相同的層),并指示它將輸出發(fā)送到來自 mediaserver 的 Surface入撒。在這種情況下隆豹,SurfaceFlinger 是緩沖區(qū)的生產(chǎn)方椭岩,而不是消耗方茅逮。
配置完成后,screenrecord 會(huì)等待顯示編碼數(shù)據(jù)判哥。在應(yīng)用繪制時(shí)献雅,其緩沖區(qū)會(huì)前往 SurfaceFlinger,SurfaceFlinger 將它們合成為單個(gè)緩沖區(qū)塌计,然后直接發(fā)送到 mediaserver 中的視頻編碼器挺身。screenrecord 進(jìn)程甚至從未看到過完整的幀。在內(nèi)部锌仅,mediaserver 具有自己的移動(dòng)緩沖區(qū)的方式章钾,這種方式還通過句柄傳遞數(shù)據(jù)墙贱,從而最大限度地降低開銷。
案例研究:模擬輔助顯示設(shè)備
WindowManager 可以要求 SurfaceFlinger 創(chuàng)建一個(gè)可見層贱傀,將 SurfaceFlinger 作為其 BufferQueue 消耗方惨撇。也可以要求 SurfaceFlinger 創(chuàng)建一個(gè)虛擬顯示設(shè)備,同樣以 SurfaceFlinger 作為其 BufferQueue 生產(chǎn)方府寒。如果連接它們并配置渲染到可見層的虛擬顯示設(shè)備魁衙,會(huì)出現(xiàn)什么情況?
創(chuàng)建一個(gè)閉合循環(huán)株搔,其中合成的屏幕顯示在窗口中剖淀。該窗口現(xiàn)在是合成輸出的一部分,因此在下一次刷新時(shí)纤房,該窗口中的合成圖像也會(huì)顯示窗口內(nèi)容(然后一直循環(huán)下去)纵隔。要實(shí)際查看該過程,請(qǐng)?jiān)谠O(shè)置中啟用開發(fā)者選項(xiàng)帆卓,選擇模擬輔助顯示設(shè)備巨朦,然后啟用一個(gè)窗口。另外有個(gè)好處是剑令,可使用 screenrecord 捕獲啟用顯示設(shè)備的操作糊啡,然后逐幀播放。
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 3.0 License, and code samples are licensed under theApache 2.0 License. For details, see ourSite Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 九月 13, 2017.