關(guān)于 Android 渲染你應(yīng)該了解的知識點

前言

談到AndroidUI繪制,大家可能會想到onMeasureonLayout、onDraw三大流程。但我們的View到底是如何一步一步顯示到屏幕上的?onDraw之后到View顯示到屏幕上,具體又做了哪些工作?
帶著這些問題,我們今天就深入學(xué)習(xí)一下Android渲染的流程吧,本文主包括以下內(nèi)容:

  1. Android渲染的整體架構(gòu)是怎樣的?
  2. Android渲染的生產(chǎn)者包括哪些?SkiaOpenGl的區(qū)別是什么?
  3. 什么是硬件加速?硬件繪制與軟件繪制的區(qū)別
  4. Android渲染緩沖區(qū)是什么?什么是黃油計劃?
  5. Android渲染的消費者是什么? 什么是SurfaceFlinger?

Android渲染整體架構(gòu)


我們先來看一下Android渲染的整體架構(gòu),具體可分為以下幾個部分

  • image stream produceers: 渲染數(shù)據(jù)的生產(chǎn)者,如Appdraw方法會把繪制指令通過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)者主要有MediaPlayerCameraPreview,NDK(Skia),OpenGl ES。
其中MediaPlayerCamera Preview是通過直接讀取圖像源來生成圖像數(shù)據(jù),NDK(Skia),OpenGL ES是通過自身的繪制能力生產(chǎn)的圖像數(shù)據(jù)

OpenGL、Vulkan、Skia的區(qū)別

  • OpenGL: 是一種跨平臺的3D圖形繪制規(guī)范接口。OpenGL EL則是專門針對嵌入式設(shè)備,如手機做了優(yōu)化。
  • Skiaskia是圖像渲染庫,2D圖形繪制自己就能完成。3D效果(依賴硬件)由OpenGL、VulkanMetal支持。它不僅支持2D3D,同時支持CPU軟件繪制和GPU硬件加速。Android、flutter都是使用它來完成繪制。
  • Vulkan: Android引入了Vulkan支持。VulKan是用來替換OpenGL的。它不僅支持3D,也支持2D,同時更加輕量級

硬件加速

關(guān)于硬件加速,相信大家也經(jīng)常聽到,尤其是有些API不支持硬件加速,因此需要我們手動關(guān)閉,那么硬件加速到底是什么呢?

CPUGPU的區(qū)別

除了屏幕,UI 渲染還要依賴另外兩個核心的硬件:CPUGPU。

  • CPUCentral Processing Unit,中央處理器),是計算機系統(tǒng)的運算和控制核心,是信息處理、程序運行的最終執(zhí)行單元;
  • GPUGraphics Processin Unit,圖形處理器),是一種專門用于圖像運算的處理器,在計算機系統(tǒng)中通常被稱為 "顯卡"的核心部件就是 GPU。

UI 組件在繪制到屏幕之前,都需要經(jīng)過 Rasterization(柵格化)操作,而柵格化又是一個非常耗時的操作。


Rasterization 柵格化是繪制那些 Button、Shape、Path、String、Bitmap 等顯示組件最基礎(chǔ)的操作。柵格化將這些 UI 組件拆分到顯示器的不同像素上進行顯示。這是一個非常耗時的操作,GPU 的引入就是為了加快柵格化。

硬件繪制與軟件繪制

  • 從圖中可以看到,軟件繪制使用 Skia 庫,它是一款能在低端設(shè)備,如手機呈現(xiàn)高質(zhì)量的 2D 跨平臺圖形框架,類似 ChromeFlutter 內(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,SkiaVulkan將繪制的數(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ā)一次),CPUGPU 才立刻開始計算然后把數(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采用雙緩沖機制,讓繪制和顯示器擁有各自的bufferGPU 始終將完成的一幀圖像數(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.1Project 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 中存有渲染幀的所有信息,可以做一些屬性動畫,這樣即便主線程有耗時操作的時候也可以保證動畫流程。

圖像消費者

SurfaceFlingerAndroid系統(tǒng)中最重要的一個圖像消費者,Activity繪制的界面圖像,都會傳遞到SurfaceFlinger來,SurfaceFlinger的作用主要是接收GraphicBuffer,然后交給HWComposer或者OpenGL做合成,合成完成后,SurfaceFlinger會把最終的數(shù)據(jù)提交給FrameBuffer

SurfaceFlinger是圖像數(shù)據(jù)的消費者。在應(yīng)用程序請求創(chuàng)建surface的時候,SurfaceFlinger會創(chuàng)建一個LayerLayerSurfaceFlinger操作合成的基本單元。所以,一個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)者消費者的模型,如下圖所示:

  • onMeasureonLayout計算出view的大小和擺放的位置,這都是UI線程要做的事情,在draw方法中進行繪制,但此時是沒有真正去繪制。而是把繪制的指令封裝為displayList,進一步封裝為RenderNode,在同步給RenderThread。
  • RenderThread通過dequeue拿到graphic buffersurfaceFlinger的緩沖區(qū)),根據(jù)繪制指令直接操作OpenGL的繪制接口,最終通過GPU設(shè)備把繪制指令渲染到了離屏緩沖區(qū)graphic buffer。
  • 完成渲染后,把緩沖區(qū)交還給SurfaceFlingerBufferQueueSurfaceFlinger會通過硬件設(shè)備進行layer的合成,最終展示到屏幕。

作者:程序員江同學(xué)
鏈接:https://juejin.cn/post/7088100181261942792
如有侵權(quán),請聯(lián)系刪除!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容