扒一扒安卓渲染原理

導語:
在測試流暢度的過程中,必不可免的要與FPS,Jank等指標接觸,但爲了加深理解,今天來簡單扒一扒安卓的渲染原理;
PerfDog使用Jank作爲來代表遊戲流暢度的指標,詳情可以看
APP&遊戲需要關注Jank卡頓嗎?

一.CPU與GPU結構

現在大部分移動端都會配有CPU(中央處理器)和GPU(圖形處理器),有的現在還有一塊NPU用於處理智能運算。來簡單看一下他們的結構;
在這裏插入圖片描述
綠色的是計算單元(ALU),
橙紅色的是存儲單元,
橙黃色的是控制單元。
CPU需要很強的通用性來處理各種不同的數據類型,同時又要進行復雜的數學和邏輯運算,所以使得CPU的內部結構異常複雜;
CPU被Cache佔據了大量空間,還有很多複雜的控制邏輯和諸多優化電路,其實計算能力只是CPU很小的一部分,在早期的時候,CPU除了做邏輯計算外,還負責內存管理、圖形顯示等操作因此在實際運算的時候性能會大打折扣,而且還不能顯示覆雜的圖形,完全不能滿足現在3D遊戲的要求;所以GPU應運而生。
GPU面對的則是類型高度統一的、相互無依賴的大規模數據和不需要被打斷的純淨的計算環境,所以結構也大不相同。
GPU採用了數量衆多的計算單元和超長的流水線,但只有非常簡單的控制邏輯並省去了Cache,GPU將計算機系統所需要的顯示信息進行轉換驅動,並向顯示器提供行掃描信號,控制顯示器的正確顯示,主要負責圖形顯示部分的工作。

二.Android系統繪圖機制

在這裏插入圖片描述
現在的安卓終端通常在一個典型顯示系統中首先由CPU發出圖像繪製指令要讓GPU去畫一個樣式,但CPU不能直接和GPU通信,也要遵守相應的規則,就和現在我們幹什麼事都要走個流程一樣的嘛,不能亂套;所以CPU要先向OpenGL ES發送一些指令,表達要畫一個樣式,Opengl ES是一組接口API,**通過這些API可以操作驅動,讓GPU達到各種各樣的操作;GPU接收到這些命令,開始柵格化處理,把樣式顯示到屏幕中;

現在我們把應用加到顯示流程裏面來
在這裏插入圖片描述
在Android應用層通過LayoutInflater把佈局XML文件映射成對象加載到內存中,此時這個UI對象含有大小,位置啦等等信息。然後CPU從內存中取出這個UI對象,再經過運算處理成多維的矢量圖形,然後交給GPU去柵格化成位圖,顯示到屏幕上;
簡單介紹一下矢量圖和位圖
矢量圖:由一個函數來描述,這個函數描述了此圖如何生成
位圖:由像素點矩陣來描述

Android系統每隔16ms就重新繪製一次Activity,所以要求應用必須在16ms內完成屏幕刷新的全部邏輯操作,這樣才能達到每秒60幀(60FPS),然而這個每秒幀數的參數由手機硬件所決定,現在大多數手機屏幕刷新率是60赫茲(是每秒中的週期性變動重複次數的計量),如果超過了16ms就會出現所謂的丟幀(1000ms/60=16.66ms)

三.一幀圖像完整渲染過程

在這裏插入圖片描述
在Android應用程序窗口裏麪包含了很多視圖(View)元素,這些元素是以樹形結構來組織,最終構成所謂視圖樹的結構;
在繪製一個Android應用程序窗口的UI之前,要確定它裏面的各個子View元素在父元素裏面的大小以及位置。確定各個子View元素在父View元素裏面的大小以及位置的過程又稱爲測量過程佈局過程。Android應用程序窗口的UI渲染過程可以分爲
Measure(測量)、Layout(佈局)和Draw(繪製)
三個階段(由ViewRootImpl類的performTraversals()方法發起)

測量——遞歸(深度優先)確定所有視圖的大小(高、寬)
佈局——遞歸(深度優先)確定所有視圖的位置
繪製——在畫布canvas上繪製應用程序窗口所有的視圖

經過多次繪製後,這一幀內要顯示的所有view都已經被繪製完畢,注意繪製View層次結構這些操作是在圖形緩衝區中繪製完成的;
此時就要把這個圖形緩衝區被交給SurfaceFlinger服務

SurfaceFlinger服務概述:
在這裏插入圖片描述
SurfaceFlinger服務和其他系統服務一樣是在Android系統的System進程裏被啓動並運行在其中的,主要負責統一管理設備中Android系統的幀緩衝區Frame Buffer,簡單理解爲屏幕所顯示出來的所有圖形效果都是由它統一管理的),在SurfaceFlinger服務啓動的過程中會自動創建兩個線程:其中一個線程用於監控控制檯事件,另外一個線程則用於渲染系統的UI
Android應用程序爲了能夠將自己的UI繪製在系統的幀緩衝區上,就需要將UI數據傳遞SurfaceFlinger服務並告知自己具體的UI數據(例如要繪製UI的區域、位置等信息),
Android應用程序與SurfaceFlinger服務是運行在不同的進程中,所以相互間通過Binder機制進行通信,
大致可以分爲3步:
1.首先是創建一個到SurfaceFlinger服務的連接,
2通過這個連接來創建一個Surface,
3.請求SurfaceFlinger服務渲染該Surface(在Android應用的每個窗口對應一個畫布(Canvas),也可以理解爲Android應用程序的一個窗口)

在APP層我們對於這部分的無法進行任何的優化,這是ROOM做的工作。

簡單來說就是當Android應用層在圖形緩衝區中繪製好View層次結構後,應用層通過Binder機制與SurfaceFlinger通信並藉助一塊匿名共享內存會把這個圖形緩衝區會被交給SurfaceFlinger服務。因爲單純的匿名共享內存在傳遞多個窗口數據時缺乏有效的管理,所以匿名共享內存就被抽象爲一個更上流的數據結構SharedClient,在每個SharedClient中,最多有31個SharedBufferStack,每個SharedBufferStack都對應一個Surface即一個窗口。

幀緩存有個地址,是在內存裏。我們通過不停的向frame buffer中寫入數據, 顯示控制器就自動的從frame buffer中取數據並顯示出來。全部的圖形都共享內存中同一個幀緩存。

四.VSync機制

爲了減少卡頓,Android 4.1(JB)中已經開始引入VSync(垂直同步)機制
簡單來說就是CPU/GPU會接收vsync信號,Android系統每隔16ms發出Vsync信號,觸發對UI 進行渲染(即每16ms顯示一幀)
在16ms內需要完成兩項任務:將UI 對象轉換爲一系列多邊形和紋理(柵格化)和CPU傳遞處理數據到GPU。
但即使引入垂直同步機制也不是非常完美,如果某些原因導致CPU和GPU渲染某一幀畫面的時間超過16ms時,Vsync垂直同步機制會讓硬件顯示器等待,直到GPU完成柵格化操作,這就直接導致這一幀畫面多停留了16ms甚至更長時間,讓用戶看起來畫面停頓。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章