扒一扒安卓渲染原理

0
回復
265
查看
打印 上一主題 下一主題
[復制鏈接]

394

主題

399

帖子

8877

安幣

手工藝人

樓主
發表于 2020-5-25 17:30:01 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
如果對本篇文章感興趣,請前往,原文地址:http://www.1574304.live/blog-822719-84094.html

導語:
在測試流暢度的過程中,必不可免的要與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甚至更長時間,讓用戶看起來畫面停頓。

  繼續閱讀全文



想在安卓巴士找到更多優質博文,可移步博客區

如果對本篇文章感興趣,請前往,
原文地址:
http://www.1574304.live/blog-822719-84094.html
分享到:  QQ好友和群 QQ空間 微信
收藏
收藏0
支持
支持0
反對
反對0
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

在柳州学什么小吃赚钱 北京pk10选号码技巧 上海快三基本走势图 福建31选7开奖数据 天齐锂业股票行情 精选16码期期必出 广东36选7好彩1走势图 平台捕鱼漏洞破解 下载贵阳捉鸡麻将 内蒙古十一选五玩法技巧 新疆11选5开奖号码