關(guān)于 Android 渲染你應(yīng)該了解的知識點
前言
談到Android的UI繪制,大家可能會想到onMeasure、onLayout、onDraw三大流程。但我們的View到底是如何一步一步顯示到屏幕上的?onDraw之后到View顯示到屏幕上,具體又做了哪些工作?
帶著這些問題,我們今天就深入學(xué)習(xí)一下Android渲染的流程吧,本文主包括以下內(nèi)容:
Android渲染的整體架構(gòu)是怎樣的?Android渲染的生產(chǎn)者包括哪些?Skia與OpenGl的區(qū)別是什么?什么是硬件加速?硬件繪制與軟件繪制的區(qū)別 Android渲染緩沖區(qū)是什么?什么是黃油計劃?Android渲染的消費者是什么? 什么是SurfaceFlinger?
Android渲染整體架構(gòu)

我們先來看一下Android渲染的整體架構(gòu),具體可分為以下幾個部分
image stream produceers: ?渲染數(shù)據(jù)的生產(chǎn)者,如App的draw方法會把繪制指令通過canvas傳遞給framework層的RenderThread線程。native Framework:RenderThread線程通過surface.dequeue得到緩沖區(qū)graphic bufer,然后在上面通過OpenGL來完成真正的渲染命令。在把緩沖區(qū)交還給BufferQueue隊列中。image stream consumers:surfaceFlinger從隊列中獲取數(shù)據(jù),同時和HAL完成layer的合成工作,最終交給HAL展示。HAL: ?硬件抽象層。把圖形數(shù)據(jù)展示到設(shè)備屏幕
可以看出,這其實是個很典型的生產(chǎn)者消費者模式
圖像生產(chǎn)者:也就是我們的 APP,再深入點就是canvas->surface。圖像消費者: SurfaceFlinger圖像緩沖區(qū): BufferQueue,一般是3緩沖區(qū)
下面我們就從生產(chǎn)者,消費者,緩沖區(qū)三個部分來詳細(xì)了解下Android渲染的過程
圖像生產(chǎn)者
從上面的架構(gòu)圖可知,圖像的生產(chǎn)者主要有MediaPlayer,CameraPreview,NDK(Skia),OpenGl ES。
其中MediaPlayer和Camera Preview是通過直接讀取圖像源來生成圖像數(shù)據(jù),NDK(Skia),OpenGL ES是通過自身的繪制能力生產(chǎn)的圖像數(shù)據(jù)
OpenGL、Vulkan、Skia的區(qū)別
OpenGL:是一種跨平臺的3D圖形繪制規(guī)范接口。OpenGL EL則是專門針對嵌入式設(shè)備,如手機做了優(yōu)化。Skia:skia是圖像渲染庫,2D圖形繪制自己就能完成。3D效果(依賴硬件)由OpenGL、Vulkan、Metal支持。它不僅支持2D、3D,同時支持CPU軟件繪制和GPU硬件加速。Android、flutter都是使用它來完成繪制。Vulkan:Android引入了Vulkan支持。VulKan是用來替換OpenGL的。它不僅支持3D,也支持2D,同時更加輕量級
硬件加速
關(guān)于硬件加速,相信大家也經(jīng)常聽到,尤其是有些API不支持硬件加速,因此需要我們手動關(guān)閉,那么硬件加速到底是什么呢?
CPU 與 GPU的區(qū)別
除了屏幕,UI 渲染還要依賴另外兩個核心的硬件:CPU 和 GPU。
CPU(Central Processing Unit,中央處理器),是計算機系統(tǒng)的運算和控制核心,是信息處理、程序運行的最終執(zhí)行單元;GPU(Graphics Processin Unit,圖形處理器),是一種專門用于圖像運算的處理器,在計算機系統(tǒng)中通常被稱為 "顯卡"的核心部件就是GPU。
UI 組件在繪制到屏幕之前,都需要經(jīng)過 Rasterization(柵格化)操作,而柵格化又是一個非常耗時的操作。
Rasterization 柵格化是繪制那些 Button、Shape、Path、String、Bitmap 等顯示組件最基礎(chǔ)的操作。柵格化將這些 UI 組件拆分到顯示器的不同像素上進行顯示。這是一個非常耗時的操作,GPU 的引入就是為了加快柵格化。
硬件繪制與軟件繪制

從圖中可以看到,軟件繪制使用 Skia庫,它是一款能在低端設(shè)備,如手機呈現(xiàn)高質(zhì)量的2D跨平臺圖形框架,類似Chrome、Flutter內(nèi)部使用的都是Skia庫。硬件繪制的思想就是通過底層軟件代碼,將 CPU不擅長的圖形計算轉(zhuǎn)換成GPU專用指令,由GPU完成繪制任務(wù)。
所以說硬件加速的本質(zhì)就是使用GPU代替CPU完成Graphic Buffer繪制工作,以實現(xiàn)更好的性能,Android從4.0開始默認(rèn)開啟了硬件加速,但還有一些API不支持硬件加速,因此需要手動關(guān)閉硬件加速。
需要注意的是,軟件繪制使用的Skia庫,但這不代表Skia不支持硬件加速,從Android 8開始,我們可以選擇使用Skia進行硬件加速,Android 9開始就默認(rèn)使用Skia來進行硬件加速。Skia的硬件加速主要是通過 copybit 模塊調(diào)用OpenGL或者SKia來實現(xiàn)。
圖像緩沖區(qū)
Android中的圖像生產(chǎn)者OpenGL,Skia,Vulkan將繪制的數(shù)據(jù)存放在圖像緩沖區(qū)中,Android中的圖像消費SurfaceFlinger從圖像緩沖區(qū)將數(shù)據(jù)取出,進行加工及合成
那么圖像緩沖區(qū)我們又需要注意哪些內(nèi)容呢?
黃油計劃
優(yōu)化是無止境的,Google 在 2012 年的 I/O 大會上宣布了 Project Butter 黃油計劃,并且在 Android 4.1 中正式開啟了這個機制。
VSYNC信號
VSYNC(Vertical Synchronization)是理解 Project Butter 的核心。對于 Android 4.0,CPU 可能會因為在忙其他的事情,導(dǎo)致沒來得及處理 UI 繪制。
為了解決這個問題,系統(tǒng)在收到VSync信號后,將馬上開始下一幀的渲染。即一旦收到VSync通知(16ms觸發(fā)一次),CPU和GPU 才立刻開始計算然后把數(shù)據(jù)寫入buffer。如下圖
CPU/GPU根據(jù)VSYNC信號同步處理數(shù)據(jù),可以讓CPU/GPU有完整的16ms時間來處理數(shù)據(jù),減少了jank。
一句話總結(jié),VSync同步使得CPU/GPU充分利用了16.6ms時間,減少jank。
三緩沖機制
在Android 4.0之前,Android采用雙緩沖機制,讓繪制和顯示器擁有各自的buffer:GPU 始終將完成的一幀圖像數(shù)據(jù)寫入到 Back Buffer,而顯示器使用 Frame Buffer,當(dāng)屏幕刷新時,Frame Buffer 并不會發(fā)生變化,當(dāng)Back buffer準(zhǔn)備就緒后,它們才進行交換。
但是如果界面比較復(fù)雜,CPU/GPU的處理時間較長 超過了16.6ms呢,雙緩沖機制會帶來什么問題?如下圖:
在第二個時間段內(nèi),但卻因 GPU還在處理B幀,緩存沒能交換,導(dǎo)致A幀被重復(fù)顯示。而 B完成后,又因為缺乏VSync信號,它只能等待下一個signal的來臨。于是在這一過程中,有一大段時間是被浪費的。當(dāng)下一個 VSync出現(xiàn)時,CPU/GPU馬上執(zhí)行操作(A幀),且緩存交換,相應(yīng)的顯示屏對應(yīng)的就是B。這時看起來就是正常的。只不過由于執(zhí)行時間仍然超過16ms,導(dǎo)致下一次應(yīng)該執(zhí)行的緩沖區(qū)交換又被推遲了——如此循環(huán)反復(fù),便出現(xiàn)了越來越多的“Jank”。
三緩沖就是在雙緩沖機制基礎(chǔ)上增加了一個Graphic Buffer緩沖區(qū),這樣可以最大限度的利用空閑時間,帶來的壞處是多使用的一個Graphic Buffer所占用的內(nèi)存。
三緩沖機制有效利用了等待vysnc的時間,可以幫助我們減少了jank
RenderThread
經(jīng)過 Android 4.1 的 Project Butter 黃油計劃之后,Android 的渲染性能有了很大的改善。不過你有沒有注意到這樣一個問題,雖然利用了 GPU 的圖形高性能運算,但是從計算 DisplayList,到通過 GPU 繪制到 Frame Buffer,整個計算和繪制都在 UI 主線程中完成。
UI 線程任務(wù)過于繁重。如果整個渲染過程比較耗時,可能造成無法響應(yīng)用戶的操作,進而出現(xiàn)卡頓的情況。GPU 對圖形的繪制渲染能力更勝一籌,如果使用 GPU 并在不同線程繪制渲染圖形,那么整個流程會更加順暢。
正因如此,在 Android 5.0 引入兩個比較大的改變。一個是引入了 RenderNode 的概念,它對 DisplayList 及一些 View 顯示屬性都做了進一步封裝。另一個是引入了 RenderThread,所有的 GL 命令執(zhí)行都放到這個線程上,渲染線程在 RenderNode 中存有渲染幀的所有信息,可以做一些屬性動畫,這樣即便主線程有耗時操作的時候也可以保證動畫流程。
圖像消費者
SurfaceFlinger是Android系統(tǒng)中最重要的一個圖像消費者,Activity繪制的界面圖像,都會傳遞到SurfaceFlinger來,SurfaceFlinger的作用主要是接收GraphicBuffer,然后交給HWComposer或者OpenGL做合成,合成完成后,SurfaceFlinger會把最終的數(shù)據(jù)提交給FrameBuffer。
SurfaceFlinger是圖像數(shù)據(jù)的消費者。在應(yīng)用程序請求創(chuàng)建surface的時候,SurfaceFlinger會創(chuàng)建一個Layer。Layer是SurfaceFlinger操作合成的基本單元。所以,一個surface對應(yīng)一個Layer。
當(dāng)應(yīng)用程序把繪制好的GraphicBuffer數(shù)據(jù)放入BufferQueue后,接下來的工作就是SurfaceFlinger來完成了。
系統(tǒng)會有多個應(yīng)用程序,一個程序有多個BufferQueue隊列。SurfaceFlinger就是用來決定何時以及怎么去管理和顯示這些隊列的。SurfaceFlinger請求HAL硬件層,來決定這些Buffer是硬件來合成還是自己通過OpenGL來合成。
最終把合成后的buffer數(shù)據(jù),展示在屏幕上。
總結(jié)
總得來說,Android圖像渲染機制是一個生產(chǎn)者消費者的模型,如下圖所示:
onMeasure、onLayout計算出view的大小和擺放的位置,這都是UI線程要做的事情,在draw方法中進行繪制,但此時是沒有真正去繪制。而是把繪制的指令封裝為displayList,進一步封裝為RenderNode,在同步給RenderThread。RenderThread通過dequeue拿到graphic buffer(surfaceFlinger的緩沖區(qū)),根據(jù)繪制指令直接操作OpenGL的繪制接口,最終通過GPU設(shè)備把繪制指令渲染到了離屏緩沖區(qū)graphic buffer。完成渲染后,把緩沖區(qū)交還給 SurfaceFlinger的BufferQueue。SurfaceFlinger會通過硬件設(shè)備進行layer的合成,最終展示到屏幕。
技術(shù)問答,學(xué)習(xí)成長,歡迎加入音視頻開發(fā)進階知識星球

技術(shù)交流,歡迎加我微信:ezglumes ,拉你入技術(shù)交流群。
私信領(lǐng)取相關(guān)資料
推薦閱讀:
開通專輯 | 細(xì)數(shù)那些年寫過的技術(shù)文章專輯
Android NDK 免費視頻在線學(xué)習(xí)?。。?/span>
覺得不錯,點個在看唄~

