前言
談到Android
的UI
繪制固额,大家可能會(huì)想到onMeasure
、onLayout
煞聪、onDraw
三大流程斗躏。但我們的View
到底是如何一步一步顯示到屏幕上的?onDraw
之后到View
顯示到屏幕上昔脯,具體又做了哪些工作?
帶著這些問(wèn)題啄糙,我們今天就深入學(xué)習(xí)一下Android
渲染的流程吧,本文主包括以下內(nèi)容:
-
Android
渲染的整體架構(gòu)是怎樣的? -
Android
渲染的生產(chǎn)者包括哪些云稚?Skia
與OpenGl
的區(qū)別是什么隧饼? - 什么是硬件加速?硬件繪制與軟件繪制的區(qū)別
-
Android
渲染緩沖區(qū)是什么静陈?什么是黃油計(jì)劃? -
Android
渲染的消費(fèi)者是什么? 什么是SurfaceFlinger
?
Android
渲染整體架構(gòu)
我們先來(lái)看一下
Android
渲染的整體架構(gòu)燕雁,具體可分為以下幾個(gè)部分
-
image stream produceers
: 渲染數(shù)據(jù)的生產(chǎn)者,如App
的draw
方法會(huì)把繪制指令通過(guò)canvas
傳遞給framework
層的RenderThread
線程鲸拥。 -
native Framework
:RenderThread
線程通過(guò)surface.dequeue
得到緩沖區(qū)graphic bufer
拐格,然后在上面通過(guò)OpenGL
來(lái)完成真正的渲染命令。在把緩沖區(qū)交還給BufferQueue
隊(duì)列中刑赶。 -
image stream consumers
:surfaceFlinger
從隊(duì)列中獲取數(shù)據(jù)捏浊,同時(shí)和HAL
完成layer
的合成工作,最終交給HAL
展示撞叨。 -
HAL
: 硬件抽象層金踪。把圖形數(shù)據(jù)展示到設(shè)備屏幕
可以看出浊洞,這其實(shí)是個(gè)很典型的生產(chǎn)者消費(fèi)者模式
- 圖像生產(chǎn)者: 也就是我們的
APP
,再深入點(diǎn)就是canvas->surface
胡岔。 - 圖像消費(fèi)者:
SurfaceFlinger
- 圖像緩沖區(qū):
BufferQueue
法希,一般是3緩沖區(qū)
下面我們就從生產(chǎn)者,消費(fèi)者靶瘸,緩沖區(qū)三個(gè)部分來(lái)詳細(xì)了解下Android
渲染的過(guò)程
圖像生產(chǎn)者
從上面的架構(gòu)圖可知铁材,圖像的生產(chǎn)者主要有MediaPlayer
,CameraPreview
奕锌,NDK(Skia)
著觉,OpenGl ES
。
其中MediaPlayer
和Camera Preview
是通過(guò)直接讀取圖像源來(lái)生成圖像數(shù)據(jù)惊暴,NDK(Skia)
饼丘,OpenGL ES
是通過(guò)自身的繪制能力生產(chǎn)的圖像數(shù)據(jù)
OpenGL
、Vulkan
辽话、Skia
的區(qū)別
-
OpenGL
: 是一種跨平臺(tái)的3D
圖形繪制規(guī)范接口肄鸽。OpenGL EL
則是專(zhuān)門(mén)針對(duì)嵌入式設(shè)備,如手機(jī)做了優(yōu)化油啤。 -
Skia
:skia
是圖像渲染庫(kù)典徘,2D
圖形繪制自己就能完成。3D
效果(依賴(lài)硬件)由OpenGL
益咬、Vulkan
逮诲、Metal
支持。它不僅支持2D
幽告、3D
梅鹦,同時(shí)支持CPU
軟件繪制和GPU
硬件加速。Android
冗锁、flutter
都是使用它來(lái)完成繪制齐唆。 -
Vulkan
:Android
引入了Vulkan
支持。VulKan
是用來(lái)替換OpenGL
的冻河。它不僅支持3D
箍邮,也支持2D
,同時(shí)更加輕量級(jí)
硬件加速
關(guān)于硬件加速叨叙,相信大家也經(jīng)常聽(tīng)到锭弊,尤其是有些API
不支持硬件加速,因此需要我們手動(dòng)關(guān)閉摔敛,那么硬件加速到底是什么呢?
CPU
與 GPU
的區(qū)別
除了屏幕廷蓉,UI
渲染還要依賴(lài)另外兩個(gè)核心的硬件:CPU
和 GPU
。
-
CPU
(Central Processing Unit
马昙,中央處理器)桃犬,是計(jì)算機(jī)系統(tǒng)的運(yùn)算和控制核心,是信息處理行楞、程序運(yùn)行的最終執(zhí)行單元攒暇; -
GPU
(Graphics Processin Unit
,圖形處理器)子房,是一種專(zhuān)門(mén)用于圖像運(yùn)算的處理器形用,在計(jì)算機(jī)系統(tǒng)中通常被稱(chēng)為 "顯卡"的核心部件就是GPU
。
UI
組件在繪制到屏幕之前证杭,都需要經(jīng)過(guò) Rasterization
(柵格化)操作田度,而柵格化又是一個(gè)非常耗時(shí)的操作。
Rasterization
柵格化是繪制那些 Button
解愤、Shape
镇饺、Path
、String
送讲、Bitmap
等顯示組件最基礎(chǔ)的操作奸笤。柵格化將這些 UI
組件拆分到顯示器的不同像素上進(jìn)行顯示。這是一個(gè)非常耗時(shí)的操作哼鬓,GPU
的引入就是為了加快柵格化监右。
硬件繪制與軟件繪制
- 從圖中可以看到,軟件繪制使用
Skia
庫(kù)异希,它是一款能在低端設(shè)備健盒,如手機(jī)呈現(xiàn)高質(zhì)量的2D
跨平臺(tái)圖形框架,類(lèi)似Chrome
称簿、Flutter
內(nèi)部使用的都是Skia
庫(kù)味榛。 - 硬件繪制的思想就是通過(guò)底層軟件代碼,將
CPU
不擅長(zhǎng)的圖形計(jì)算轉(zhuǎn)換成GPU
專(zhuān)用指令予跌,由GPU
完成繪制任務(wù)搏色。
所以說(shuō)硬件加速的本質(zhì)就是使用GPU
代替CPU
完成Graphic Buffer
繪制工作,以實(shí)現(xiàn)更好的性能券册,Android
從4.0開(kāi)始默認(rèn)開(kāi)啟了硬件加速频轿,但還有一些API
不支持硬件加速,因此需要手動(dòng)關(guān)閉硬件加速烁焙。
需要注意的是航邢,軟件繪制使用的Skia
庫(kù),但這不代表Skia
不支持硬件加速骄蝇,從Android 8
開(kāi)始膳殷,我們可以選擇使用Skia
進(jìn)行硬件加速,Android 9
開(kāi)始就默認(rèn)使用Skia
來(lái)進(jìn)行硬件加速九火。Skia
的硬件加速主要是通過(guò) copybit
模塊調(diào)用OpenGL
或者SKia
來(lái)實(shí)現(xiàn)赚窃。
圖像緩沖區(qū)
Android
中的圖像生產(chǎn)者OpenGL
册招,Skia
,Vulkan
將繪制的數(shù)據(jù)存放在圖像緩沖區(qū)中勒极,Android
中的圖像消費(fèi)SurfaceFlinger
從圖像緩沖區(qū)將數(shù)據(jù)取出是掰,進(jìn)行加工及合成
那么圖像緩沖區(qū)我們又需要注意哪些內(nèi)容呢?
黃油計(jì)劃
優(yōu)化是無(wú)止境的,Google
在 2012 年的 I/O
大會(huì)上宣布了 Project Butter
黃油計(jì)劃辱匿,并且在 Android 4.1
中正式開(kāi)啟了這個(gè)機(jī)制键痛。
VSYNC
信號(hào)
VSYNC(Vertical Synchronization)
是理解 Project Butter
的核心。對(duì)于 Android 4.0
匾七,CPU
可能會(huì)因?yàn)樵诿ζ渌氖虑樾醵蹋瑢?dǎo)致沒(méi)來(lái)得及處理 UI
繪制。
為了解決這個(gè)問(wèn)題昨忆,系統(tǒng)在收到VSync
信號(hào)后丁频,將馬上開(kāi)始下一幀的渲染。即一旦收到VSync
通知(16ms
觸發(fā)一次)扔嵌,CPU
和GPU
才立刻開(kāi)始計(jì)算然后把數(shù)據(jù)寫(xiě)入buffer
限府。如下圖
CPU/GPU
根據(jù)VSYNC
信號(hào)同步處理數(shù)據(jù),可以讓CPU/GPU
有完整的16ms時(shí)間來(lái)處理數(shù)據(jù)痢缎,減少了jank
胁勺。
一句話總結(jié),VSync
同步使得CPU/GPU
充分利用了16.6ms時(shí)間独旷,減少jank
署穗。
三緩沖機(jī)制
在Android 4.0
之前,Android
采用雙緩沖機(jī)制嵌洼,讓繪制和顯示器擁有各自的buffer
:GPU
始終將完成的一幀圖像數(shù)據(jù)寫(xiě)入到 Back Buffer
案疲,而顯示器使用 Frame Buffer
,當(dāng)屏幕刷新時(shí)麻养,Frame Buffer
并不會(huì)發(fā)生變化褐啡,當(dāng)Back buffer
準(zhǔn)備就緒后,它們才進(jìn)行交換鳖昌。
但是如果界面比較復(fù)雜备畦,CPU/GPU
的處理時(shí)間較長(zhǎng) 超過(guò)了16.6ms呢,雙緩沖機(jī)制會(huì)帶來(lái)什么問(wèn)題许昨?如下圖:
- 在第二個(gè)時(shí)間段內(nèi)懂盐,但卻因
GPU
還在處理B
幀,緩存沒(méi)能交換糕档,導(dǎo)致A
幀被重復(fù)顯示莉恼。 - 而
B
完成后,又因?yàn)槿狈?code>VSync信號(hào),它只能等待下一個(gè)signal
的來(lái)臨俐银。于是在這一過(guò)程中尿背,有一大段時(shí)間是被浪費(fèi)的。 - 當(dāng)下一個(gè)
VSync
出現(xiàn)時(shí)悉患,CPU/GPU
馬上執(zhí)行操作(A
幀)残家,且緩存交換榆俺,相應(yīng)的顯示屏對(duì)應(yīng)的就是B
售躁。這時(shí)看起來(lái)就是正常的。只不過(guò)由于執(zhí)行時(shí)間仍然超過(guò)16ms茴晋,導(dǎo)致下一次應(yīng)該執(zhí)行的緩沖區(qū)交換又被推遲了——如此循環(huán)反復(fù)陪捷,便出現(xiàn)了越來(lái)越多的“Jank”。
三緩沖就是在雙緩沖機(jī)制基礎(chǔ)上增加了一個(gè)Graphic Buffer
緩沖區(qū)诺擅,這樣可以最大限度的利用空閑時(shí)間市袖,帶來(lái)的壞處是多使用的一個(gè)Graphic Buffer
所占用的內(nèi)存。
三緩沖機(jī)制有效利用了等待vysnc的時(shí)間烁涌,可以幫助我們減少了
jank
RenderThread
經(jīng)過(guò) Android 4.1
的 Project Butter
黃油計(jì)劃之后苍碟,Android
的渲染性能有了很大的改善。不過(guò)你有沒(méi)有注意到這樣一個(gè)問(wèn)題撮执,雖然利用了 GPU
的圖形高性能運(yùn)算微峰,但是從計(jì)算 DisplayList
,到通過(guò) GPU
繪制到 Frame Buffer
抒钱,整個(gè)計(jì)算和繪制都在 UI
主線程中完成蜓肆。
UI
線程任務(wù)過(guò)于繁重。如果整個(gè)渲染過(guò)程比較耗時(shí)谋币,可能造成無(wú)法響應(yīng)用戶(hù)的操作仗扬,進(jìn)而出現(xiàn)卡頓的情況。GPU
對(duì)圖形的繪制渲染能力更勝一籌蕾额,如果使用 GPU
并在不同線程繪制渲染圖形早芭,那么整個(gè)流程會(huì)更加順暢。
正因如此诅蝶,在 Android 5.0
引入兩個(gè)比較大的改變退个。一個(gè)是引入了 RenderNode
的概念,它對(duì) DisplayList
及一些 View
顯示屬性都做了進(jìn)一步封裝秤涩。另一個(gè)是引入了 RenderThread
帜乞,所有的 GL
命令執(zhí)行都放到這個(gè)線程上,渲染線程在 RenderNode
中存有渲染幀的所有信息筐眷,可以做一些屬性動(dòng)畫(huà)黎烈,這樣即便主線程有耗時(shí)操作的時(shí)候也可以保證動(dòng)畫(huà)流程。
圖像消費(fèi)者
SurfaceFlinger
是Android
系統(tǒng)中最重要的一個(gè)圖像消費(fèi)者,Activity
繪制的界面圖像照棋,都會(huì)傳遞到SurfaceFlinger
來(lái)资溃,SurfaceFlinger
的作用主要是接收GraphicBuffer
,然后交給HWComposer
或者OpenGL
做合成烈炭,合成完成后溶锭,SurfaceFlinger
會(huì)把最終的數(shù)據(jù)提交給FrameBuffer
。
SurfaceFlinger
是圖像數(shù)據(jù)的消費(fèi)者符隙。在應(yīng)用程序請(qǐng)求創(chuàng)建surface
的時(shí)候趴捅,SurfaceFlinger
會(huì)創(chuàng)建一個(gè)Layer
。Layer
是SurfaceFlinger
操作合成的基本單元霹疫。所以拱绑,一個(gè)surface
對(duì)應(yīng)一個(gè)Layer
。
當(dāng)應(yīng)用程序把繪制好的GraphicBuffer
數(shù)據(jù)放入BufferQueue
后丽蝎,接下來(lái)的工作就是SurfaceFlinger
來(lái)完成了猎拨。
系統(tǒng)會(huì)有多個(gè)應(yīng)用程序,一個(gè)程序有多個(gè)BufferQueue
隊(duì)列屠阻。SurfaceFlinger
就是用來(lái)決定何時(shí)以及怎么去管理和顯示這些隊(duì)列的红省。
SurfaceFlinger
請(qǐng)求HAL
硬件層,來(lái)決定這些Buffer
是硬件來(lái)合成還是自己通過(guò)OpenGL
來(lái)合成国觉。
最終把合成后的buffer
數(shù)據(jù)吧恃,展示在屏幕上。
總結(jié)
總得來(lái)說(shuō)蛉加,Android
圖像渲染機(jī)制是一個(gè)生產(chǎn)者消費(fèi)者的模型蚜枢,如下圖所示:
-
onMeasure
、onLayout
計(jì)算出view
的大小和擺放的位置针饥,這都是UI
線程要做的事情厂抽,在draw
方法中進(jìn)行繪制,但此時(shí)是沒(méi)有真正去繪制丁眼。而是把繪制的指令封裝為displayList
,進(jìn)一步封裝為RenderNode
筷凤,在同步給RenderThread
。 -
RenderThread
通過(guò)dequeue
拿到graphic buffer
(surfaceFlinger
的緩沖區(qū))苞七,根據(jù)繪制指令直接操作OpenGL
的繪制接口藐守,最終通過(guò)GPU
設(shè)備把繪制指令渲染到了離屏緩沖區(qū)graphic buffer
。 - 完成渲染后蹂风,把緩沖區(qū)交還給
SurfaceFlinger
的BufferQueue
卢厂。SurfaceFlinger
會(huì)通過(guò)硬件設(shè)備進(jìn)行layer
的合成,最終展示到屏幕惠啄。
作者:程序員江同學(xué)
鏈接:https://juejin.cn/post/7088100181261942792
如有侵權(quán)慎恒,請(qǐng)聯(lián)系刪除任内!