扒一扒安卓渲染原理
導語:
在測試流暢度的過程中,必不可免的要與FPS,Jank等指標接觸,但為了加深理解,今天來簡單扒一扒安卓的渲染原理;
PerfDog使用Jank作為來代表游戲流暢度的指標
一.CPU與GPU結(jié)構
現(xiàn)在大部分移動端都會配有CPU(中央處理器)和GPU(圖形處理器),有的現(xiàn)在還有一塊NPU用于處理智能運算。來簡單看一下他們的結(jié)構;
?
綠色的是計算單元(ALU),
橙紅色的是存儲單元,
橙黃色的是控制單元。
CPU需要很強的通用性來處理各種不同的數(shù)據(jù)類型,同時又要進行復雜的數(shù)學和邏輯運算,所以使得CPU的內(nèi)部結(jié)構異常復雜;
CPU被Cache占據(jù)了大量空間,還有很多復雜的控制邏輯和諸多優(yōu)化電路,其實計算能力只是CPU很小的一部分,在早期的時候,CPU除了做邏輯計算外,還負責內(nèi)存管理、圖形顯示等操作因此在實際運算的時候性能會大打折扣,而且還不能顯示復雜的圖形,完全不能滿足現(xiàn)在3D游戲的要求;所以GPU應運而生。
GPU面對的則是類型高度統(tǒng)一的、相互無依賴的大規(guī)模數(shù)據(jù)和不需要被打斷的純凈的計算環(huán)境,所以結(jié)構也大不相同。
GPU采用了數(shù)量眾多的計算單元和超長的流水線,但只有非常簡單的控制邏輯并省去了Cache,GPU將計算機系統(tǒng)所需要的顯示信息進行轉(zhuǎn)換驅(qū)動,并向顯示器提供行掃描信號,控制顯示器的正確顯示,主要負責圖形顯示部分的工作。
二.Android系統(tǒng)繪圖機制
現(xiàn)在的安卓終端通常在一個典型顯示系統(tǒng)中首先由CPU發(fā)出圖像繪制指令要讓GPU去畫一個樣式,但CPU不能直接和GPU通信,也要遵守相應的規(guī)則,就和現(xiàn)在我們干什么事都要走個流程一樣的嘛,不能亂套;所以CPU要先向OpenGL ES發(fā)送一些指令,表達要畫一個樣式,Opengl ES是一組接口API,**通過這些API可以操作驅(qū)動,讓GPU達到各種各樣的操作;GPU接收到這些命令,開始柵格化處理,把樣式顯示到屏幕中;
現(xiàn)在我們把應用加到顯示流程里面來
?
在Android應用層通過LayoutInflater把布局XML文件映射成對象加載到內(nèi)存中,此時這個UI對象含有大小,位置啦等等信息。然后CPU從內(nèi)存中取出這個UI對象,再經(jīng)過運算處理成多維的矢量圖形,然后交給GPU去柵格化成位圖,顯示到屏幕上;
簡單介紹一下矢量圖和位圖
矢量圖:由一個函數(shù)來描述,這個函數(shù)描述了此圖如何生成
位圖:由像素點矩陣來描述
Android系統(tǒng)每隔16ms就重新繪制一次Activity,所以要求應用必須在16ms內(nèi)完成屏幕刷新的全部邏輯操作,這樣才能達到每秒60幀(60FPS),然而這個每秒幀數(shù)的參數(shù)由手機硬件所決定,現(xiàn)在大多數(shù)手機屏幕刷新率是60赫茲(是每秒中的周期性變動重復次數(shù)的計量),如果超過了16ms就會出現(xiàn)所謂的丟幀(1000ms/60=16.66ms)
三.一幀圖像完整渲染過程
在Android應用程序窗口里面包含了很多視圖(View)元素,這些元素是以樹形結(jié)構來組織,最終構成所謂視圖樹的結(jié)構;
在繪制一個Android應用程序窗口的UI之前,要確定它里面的各個子View元素在父元素里面的大小以及位置。確定各個子View元素在父View元素里面的二手手機靚號購買平臺大小以及位置的過程又稱為測量過程和布局過程。Android應用程序窗口的UI渲染過程可以分為
Measure(測量)、Layout(布局)和Draw(繪制)
三個階段(由ViewRootImpl類的performTraversals()方法發(fā)起)
測量——遞歸(深度優(yōu)先)確定所有視圖的大小(高、寬)
布局——遞歸(深度優(yōu)先)確定所有視圖的位置
繪制——在畫布canvas上繪制應用程序窗口所有的視圖
經(jīng)過多次繪制后,這一幀內(nèi)要顯示的所有view都已經(jīng)被繪制完畢,注意繪制View層次結(jié)構這些操作是在圖形緩沖區(qū)中繪制完成的;
此時就要把這個圖形緩沖區(qū)被交給SurfaceFlinger服務
SurfaceFlinger服務概述:
?
SurfaceFlinger服務和其他系統(tǒng)服務一樣是在Android系統(tǒng)的System進程里被啟動并運行在其中的,主要負責統(tǒng)一管理設備中Android系統(tǒng)的幀緩沖區(qū)(Frame Buffer,簡單理解為屏幕所顯示出來的所有圖形效果都是由它統(tǒng)一管理的),在SurfaceFlinger服務啟動的過程中會自動創(chuàng)建兩個線程:其中一個線程用于監(jiān)控控制臺事件,另外一個線程則用于渲染系統(tǒng)的UI;
Android應用程序為了能夠?qū)⒆约旱腢I繪制在系統(tǒng)的幀緩沖區(qū)上,就需要將UI數(shù)據(jù)傳遞SurfaceFlinger服務并告知自己具體的UI數(shù)據(jù)(例如要繪制UI的區(qū)域、位置等信息),
Android應用程序與SurfaceFlinger服務是運行在不同的進程中,所以相互間通過Binder機制進行通信,
大致可以分為3步:
1.首先是創(chuàng)建一個到SurfaceFlinger服務的連接,
2通過這個連接來創(chuàng)建一個Surface,
3.請求SurfaceFlinger服務渲染該Surface(在Android應用的每個窗口對應一個畫布(Canvas),也可以理解為Android應用程序的一個窗口)
在APP層我們對于這部分的無法進行任何的優(yōu)化,這是ROOM做的工作。
簡單來說就是當Android應用層在圖形緩沖區(qū)中繪制好View層次結(jié)構后,應用層通過Binder機制與SurfaceFlinger通信并借助一塊匿名共享內(nèi)存會把這個圖形緩沖區(qū)會被交給SurfaceFlinger服務。因為單純的匿名共享內(nèi)存在傳遞多個窗口數(shù)據(jù)時缺乏有效的管理,所以匿名共享內(nèi)存就被抽象為一個更上流的數(shù)據(jù)結(jié)構SharedClient,在每個SharedClient中,最多有31個SharedBufferStack,每個SharedBufferStack都對應一個Surface即一個窗口。
幀緩存有個地址,是在內(nèi)存里。我們通過不停的向frame buffer中寫入數(shù)據(jù), 顯示控制器就自動的從frame buffer中取數(shù)據(jù)并顯示出來。全部的圖形都共享內(nèi)存中同一個幀緩存。
四.VSync機制
為了減少卡頓,Android 4.1(JB)中已經(jīng)開始引入VSync(垂直同步)機制
簡單來說就是CPU/GPU會接收vsync信號,Android系統(tǒng)每隔16ms發(fā)出Vsync信號,觸發(fā)對UI 進行渲染(即每16ms顯示一幀)
在16ms內(nèi)需要完成兩項任務:將UI 對象轉(zhuǎn)換為一系列多邊形和紋理(柵格化)和CPU傳遞處理數(shù)據(jù)到GPU。
但即使引入垂直同步機制也不是非常完美,如果某些原因?qū)е翪PU和GPU渲染某一幀畫面的時間超過16ms時,Vsync垂直同步機制會讓硬件顯示器等待,直到GPU完成柵格化操作,這就直接導致這一幀畫面多停留了16ms甚至更長時間,讓用戶看起來畫面停頓。
總結(jié)
- 上一篇: 从零点五开始用Unity做半个2D战棋小
- 下一篇: 类mc地图设计