圖形系統(tǒng)是Android中非常重要的子系統(tǒng)暑竟,與其他子系統(tǒng)相互協(xié)作敬扛,完成圖形界面的渲染和顯示辙培。
概述
官方提供了一個(gè)圖形系統(tǒng)的關(guān)鍵組件協(xié)作圖,如下所示:
這幅圖大致描述了圖形數(shù)據(jù)的流轉(zhuǎn):OpenGL ES崭庸、MediaPlayer等生產(chǎn)者生產(chǎn)圖形數(shù)據(jù)到Surface怀浆,Surface通過
IGraphicBufferProducer
把GraphicBuffer
跨進(jìn)程傳輸給消費(fèi)者SurfaceFlinger
,SurfaceFlinger
根據(jù)WMS
提供的窗口信息合成所有的Layer
(對應(yīng)于Surface)怕享,具體的合成策略由hwcomposer
HAL模塊決定并實(shí)施执赡,最后也是由該模塊送顯到Display,而Gralloc
模塊則負(fù)責(zé)分配圖形緩沖區(qū)熬粗。不過該圖缺乏層次感搀玖,通過下圖我們詳細(xì)分析整個(gè)流程。大體上驻呐,應(yīng)用開發(fā)者可以通過兩種方式將圖像繪制到屏幕上:
- Canvas
- OpenGL ES
Canvas
是一個(gè)2D圖形API灌诅,是Android View樹實(shí)際的渲染者。Canvas
又可分為Skia
軟件繪制和hwui
硬件加速繪制含末。
Android4.0之前默認(rèn)是Skia
繪制猜拾,該方式完全通過CPU完成繪圖指令,并且全部在主線程操作佣盒,在復(fù)雜場景下單幀容易超過16ms導(dǎo)致卡頓挎袜。
從Android4.0開始,默認(rèn)開啟硬件加速渲染,而且5.0開始把渲染操作拆分到了兩個(gè)線程:主線程和渲染線程盯仪,主線程負(fù)責(zé)記錄渲染指令紊搪,渲染線程負(fù)責(zé)通過OpenGL ES
完成渲染,兩個(gè)線程可以并發(fā)執(zhí)行全景。
除了Canvas
耀石,開發(fā)者還可以在異步線程直接通過OpenGL ES
進(jìn)行渲染,一般適用于游戲爸黄、視頻播放等獨(dú)立場景滞伟。
從應(yīng)用側(cè)來看,不管是Canvas
炕贵,還是OpenGL ES
梆奈,最終渲染到的目標(biāo)都是Surface,現(xiàn)在比較流行的跨平臺UI框架Flutter
在Android平臺上也是直接渲染到Surface称开。Surface是一個(gè)窗口亩钟,例如:一個(gè)Activity是一個(gè)Surface、一個(gè)Dialog也是一個(gè)Surface钥弯,承載了上層的圖形數(shù)據(jù)径荔,與SurfaceFlinger側(cè)的Layer相對應(yīng)。
Native層Surface實(shí)現(xiàn)了ANativeWindow
結(jié)構(gòu)體脆霎,在構(gòu)造函數(shù)中持有一個(gè)IGraphicBufferProducer
总处,用于和BufferQueue
進(jìn)行交互。BufferQueue
是連接Surface和Layer的紐帶睛蛛,當(dāng)上層圖形數(shù)據(jù)渲染到Surface時(shí)鹦马,實(shí)際是渲染到了BufferQueue
中的一個(gè)GraphicBuffer
,然后通過IGraphicBufferProducer
把GraphicBuffer
提交到BufferQueue
忆肾,讓SurfaceFlinger進(jìn)行后續(xù)的合成顯示工作荸频。
SurfaceFlinger負(fù)責(zé)合成所有的Layer并送顯到Display,這些Layer主要有兩種合成方式:
-
OpenGL ES
:把這些圖層合成到FrameBuffer客冈,然后把FrameBuffer提交給hwcomposer
完成剩余合成和顯示工作旭从。 -
hwcomposer
:通過HWC
模塊合成部分圖層和FrameBuffer,并顯示到Display场仲。
BufferQueue
Android圖形系統(tǒng)包含了兩對生產(chǎn)者和消費(fèi)者模型和悦,它們都通過BufferQueue進(jìn)行連接:
-
Canvas
和OpenGL ES
生產(chǎn)圖形數(shù)據(jù),SurfaceFlinger
消費(fèi)圖形數(shù)據(jù)渠缕。 -
SurfaceFlinger
合成所有圖層的圖形數(shù)據(jù)鸽素,Display顯示合成結(jié)果。
Surface屬于APP進(jìn)程亦鳞,Layer屬于系統(tǒng)進(jìn)程馍忽,如果它們之間只用一個(gè)Buffer棒坏,那么必然存在顯示和性能問題,所以圖形系統(tǒng)引入了BufferQueue
遭笋,一個(gè)Buffer用于繪制坝冕,一個(gè)Buffer用于顯示,雙方處理完之后坐梯,交換一下Buffer徽诲,這樣效率就高很多了。BufferQueue
的通信流程如下所示:
- 生產(chǎn)者從BufferQueue出隊(duì)一個(gè)空閑GraphicBuffer吵血,交給上層填充圖形數(shù)據(jù);
- 數(shù)據(jù)填充后偷溺,生產(chǎn)者把裝載圖形數(shù)據(jù)的GraphicBuffer入隊(duì)到BufferQueue蹋辅,也可以丟棄這塊Buffer,直接cancelBuffer送回到BufferQueue挫掏;
- 消費(fèi)者通過
acquireBuffer
獲取一個(gè)有效緩存侦另; - 完成內(nèi)容消費(fèi)后(比如上屏),消費(fèi)者調(diào)用
releaseBuffer
把Buffer交還給BufferQueue尉共。 -
GraphicBuffer
代表的圖形緩沖區(qū)是由Gralloc
模塊分配的褒傅,并且可以跨進(jìn)程傳輸(實(shí)際傳輸?shù)闹皇且粋€(gè)指針)。 - 通常而言袄友,APP端使用的是BufferQueue的
IGraphicBufferProducer
接口(在Surface類里面)殿托,用于生產(chǎn);SurfaceFlinger端使用的是BufferQueue的IGraphicBufferConsumer
接口(在GLConsumer類里面)剧蚣,用于消費(fèi)支竹。
Surface與SurfaceFlinger
Surface
表示APP進(jìn)程的一個(gè)窗口,承載了窗口的圖形數(shù)據(jù)鸠按,SurfaceFlinger
是系統(tǒng)進(jìn)程合成所有窗口(Layer)的系統(tǒng)服務(wù)礼搁,負(fù)責(zé)合成所有Surface提供的圖形數(shù)據(jù),然后送顯到屏幕目尖。SurfaceFlinger
既是上層應(yīng)用的消費(fèi)者馒吴,又是Display的生產(chǎn)者,起到了承上啟下的作用瑟曲。官方提供了一個(gè)架構(gòu)圖饮戳,如下所示:
該圖可能較抽象,我們通過一個(gè)實(shí)例理解下這層關(guān)系测蹲,下圖是微信添加朋友的彈窗界面:
<img src="https://ltlovezh.oss-cn-beijing.aliyuncs.com/graphics/%E5%BE%AE%E4%BF%A1.png" width="300" />
我們可以通過adb shell dumpsys SurfaceFlinger
查看該界面包含幾個(gè)窗口(Surface):
從
SurfaceFlinger
的dump信息可以看到:
-
com.tencent.mm/com.tencent.mm.ui.LauncherUI#0
是微信的主窗口莹捡,并且鋪滿了整個(gè)屏幕(0,0,1080,2340)
。 -
PopupWindow:7020633#0
是彈起的PopupWindow
扣甲,它是一個(gè)獨(dú)立的窗口(Surface)篮赢,屏幕坐標(biāo)范圍是(599,210,1058,983)
齿椅。 -
StatusBar#0
表示系統(tǒng)狀態(tài)欄,由系統(tǒng)進(jìn)程負(fù)責(zé)繪制启泣,屏幕坐標(biāo)范圍是(0,0,1080,80)
涣脚,即此狀態(tài)欄高80像素。 -
NavigationBar#0
表示系統(tǒng)導(dǎo)航欄寥茫,由系統(tǒng)進(jìn)程負(fù)責(zé)繪制遣蚀,屏幕坐標(biāo)范圍是(0,2214,1080,2340)
,即此導(dǎo)航欄高126像素纱耻。 - 最后兩個(gè)窗口也是系統(tǒng)窗口芭梯,具體作用不知。
- 上述所有圖層的合成類型都是
Device
弄喘,即HWC
硬件模塊負(fù)責(zé)合成這些Layer玖喘。 -
SurfaceFlinger
會合成上述所有圖層(Layer),并送顯到內(nèi)嵌的Display 0
蘑志。
總結(jié)
本篇文章從上到下簡述了Android圖形系統(tǒng)的流轉(zhuǎn)流程累奈,以及承載圖形數(shù)據(jù)流轉(zhuǎn)的重要結(jié)構(gòu):BufferQueue
,最后通過dump信息論證了多Surface實(shí)例急但。