GPU由來:CPU的任務(wù)繁多,做邏輯計算,還要做內(nèi)存管理、顯示操作,因此在實際運算(浮點運算)的時候性能會大打折扣,在沒有GPU的時代,不能顯示復(fù)雜的圖形,其運算速度遠(yuǎn)跟不上今天復(fù)雜三維游戲的要求。即使CUP的工作頻率超過2GHZ或更高,對它繪制圖形提高也不大。這時GPU的設(shè)計就出來了。
CPU和GPU架構(gòu):
黃色的Control: 控制器,用于協(xié)調(diào)控制整個CPU的運行,包括取出指令、控制其他模塊的運行等;
綠色的ALU(Arithmetic Logic Unit): 算術(shù)邏輯單元,用于進行數(shù)學(xué)、邏輯運算;
橙色的Cache: 緩存,用于存儲信息。
橙色的DRAM: RAM,用于存儲信息。
從結(jié)構(gòu)圖可以看出,CPU的控制器較為復(fù)雜,而ALU數(shù)量較少。因此CPU擅長各種復(fù)雜的邏輯運算,但不擅長數(shù)學(xué)尤其浮點運算。

CPU: 中央處理器,它集成了運算,緩沖,控制等單元,包括繪圖功能.CPU將對象處理為多維圖形,紋理(Bitmaps、Drawables等都是一起打包到統(tǒng)一的紋理).
GPU:一個類似于CPU的專門用來處理Graphics的處理器, 作用用來幫助加快格柵化操作,當(dāng)然,也有相應(yīng)的緩存數(shù)據(jù)(例如緩存已經(jīng)光柵化過的bitmap等)機制。
OpenGL ES:是手持嵌入式設(shè)備的3DAPI,跨平臺的、功能完善的2D和3D圖形應(yīng)用程序接口API,有一套固定渲染管線流程. 附相關(guān)OpenGL渲染流程資料
DisplayList: 在Android把XML布局文件轉(zhuǎn)換成GPU能夠識別并繪制的對象。這個操作是在DisplayList的幫助下完成的。DisplayList持有所有將要交給GPU繪制到屏幕上的數(shù)據(jù)信息。
垂直同步VSYNC:讓顯卡的運算和顯示器刷新率一致以穩(wěn)定輸出的畫面質(zhì)量。它告知GPU在載入新幀之前,要等待屏幕繪制完成前一幀。
Refresh Rate:屏幕一秒內(nèi)刷新屏幕的次數(shù),由硬件決定,例如60Hz.
Frame Rate:GPU一秒繪制操作的幀數(shù),單位是30fps,
XML加載過程:


柵格化:
將向量圖形格式表示的圖像轉(zhuǎn)換成位圖以用于顯示器,即把button、textview等組件拆分到不同的像素上進行顯示。這是一個很費時的操作,GPU的引入就是為了加快柵格化的操作。

60HZ刷新頻率由來
12fps: 由于人類的眼睛的特殊生理結(jié)構(gòu),如果所看到的畫面幀率高于每秒10-12幀的時候,就會認(rèn)為是連慣的
24fps:有聲電影的拍攝及播放幀率均為每秒24幀,對一般人而言已算可接受
30fps:早期的高動態(tài)電子游戲,幀率少于每秒30幀的話就會顯得不連貫,這是因為沒有動態(tài)模糊使流暢度降低
60fps:在與手機交換過程中,如果觸摸及反饋 60幀以下人是能感覺出來的。60幀以上不能察覺變化。當(dāng)?shù)陀?0幀時感覺畫面卡頓和遲滯現(xiàn)象
Android系統(tǒng)每隔16ms發(fā)出VSYNC信號(1000ms/60=16.66ms),觸發(fā)對UI進行渲染,如果每次渲染都成功這樣能夠達到流暢畫面所需要的60fps,為了能夠?qū)崿F(xiàn)60fps,這意味著計算渲染的大多數(shù)操作都必須在16ms內(nèi)完成。
Android系統(tǒng)的繪制原理
Android中每個界面都是大大小小的View組成,對于應(yīng)用里的每個view都會經(jīng)過老三部:measure,layout,draw.然后就由主線程傳給CPU進行計算紋理,再通過OpenGL ES接口調(diào)用GPU進行柵格化處理,再通過跨進程通信機制把需要顯示的數(shù)據(jù)傳到SurfaceFlinger,通過它將柵格化的信息交給硬件合成器合成后輸出到顯示屏.
開啟硬件加速:

如果沒有開啟硬件加速,系統(tǒng)則會用軟件加速的形式來渲染,即CPU計算紋理后通過skia進行柵格化,再通過跨進程通信機制把需要顯示的數(shù)據(jù)傳到SurfaceFlinger,通過它將柵格化的信息交給硬件合成器合成后輸出到顯示屏.

PS:Androd3.0開始支持硬件加速,到Android4.0默認(rèn)開啟硬件加速.
繪制任務(wù)由應(yīng)用發(fā)起,最終通過系統(tǒng)層繪制到硬件屏幕上,也就是說應(yīng)用進程繪制后,通過跨進程通信機制把需要顯示的數(shù)據(jù)傳到系統(tǒng)層,由系統(tǒng)層中的SurfaceFlinger服務(wù)繪制到屏幕上;
-
應(yīng)用層
一個Android應(yīng)用程序窗口里面包含了很多UI元素,這些UI元素是以樹形結(jié)構(gòu)來組織的,即它們存在著父子關(guān)系,其中,子UI元素位于父UI元素里面,如下圖:
image
在繪制一個Android應(yīng)用程序窗口的UI之前,我們首先要確定它里面的各個子UI元素在父UI元素里面的大小以及位置。確定各個子UI元素在父UI元素里面的大小以及位置的過程又稱為測量過程和布局過程。Android每個View繪制的三個核心步驟:通過Measure和Layout確定當(dāng)前需要繪制View的大小和位置,通過繪制到surface,在Android系統(tǒng)繪制源碼是在ViewRootImpl的performTraversals方法開始的,通過該方法會執(zhí)行Measure和layout和draw方法;Measure和layout都是遞歸獲取View的大小和位置,都是以深度為優(yōu)先級,可以看出層級越深元素越多,耗時也就越長;
測量、布局沒有太多要說的,這里要著重說一下繪制。Android目前有兩種繪制模型:基于軟件的繪制模型和硬件加速的繪制模型(從Android 3.0開始全面支持)。
基于軟件的繪制模型下,CPU主導(dǎo)繪圖,視圖按照兩個步驟繪制
(1)讓View層次結(jié)構(gòu)失效;
(2) 繪制View層次結(jié)構(gòu);
當(dāng)應(yīng)用程序需要更新它的部分UI時,都會調(diào)用內(nèi)容發(fā)生改變的View對象的invalidate()方法。無效(invalidation)消息請求會在View對象層次結(jié)構(gòu)中傳遞,以便計算出需要重繪的屏幕區(qū)域(臟區(qū))。然后,Android系統(tǒng)會在View層次結(jié)構(gòu)中繪制所有的跟臟區(qū)相交的區(qū)域。不幸的是,這種方法有兩個缺點:
(1)繪制了不需要重繪的視圖(與臟區(qū)域相交的區(qū)域);
(2)掩蓋了一些應(yīng)用的bug(由于會重繪與臟區(qū)域相交的區(qū)域);
注意:在View對象的屬性發(fā)生變化時,如背景色或TextView對象中的文本等,Android系統(tǒng)會自動的調(diào)用該View對象的invalidate()方法。
基于硬件加速的繪制模式下,GPU主導(dǎo)繪圖,繪制按照三個步驟繪制:
(1)讓View層次結(jié)構(gòu)失效
(2)記錄、更新顯示列表
(3)繪制顯示列表
這種模式下,Android系統(tǒng)依然會使用invalidate()方法和draw()方法來請求屏幕更新和展現(xiàn)View對象。但Android系統(tǒng)并不是立即執(zhí)行繪制命令,而是首先把這些View的繪制函數(shù)作為繪制指令記錄一個顯示列表中,然后再讀取顯示列表中的繪制指令調(diào)用OpenGL相關(guān)函數(shù)完成實際繪制。另一個優(yōu)化是,Android系統(tǒng)只需要針對由invalidate()方法調(diào)用所標(biāo)記的View對象的臟區(qū)進行記錄和更新顯示列表。沒有失效的View對象則能重放先前顯示列表記錄的繪制指令來進行簡單的重繪工作。使用顯示列表的目的是,把視圖的各種繪制函數(shù)翻譯成繪制指令保存起來,對于沒有發(fā)生改變的視圖把原先保存的操作指令重新讀取出來重放一次就可以了,提高了視圖的顯示速度。而對于需要重繪的View,則更新顯示列表,以便下次重用,然后再調(diào)用OpenGL完成繪制。硬件加速提高了Android系統(tǒng)顯示和刷新的速度,但它也不是萬能的,它有三個缺陷:
耗電:GPU功耗比CPU高;
兼容問題:某些接口或者函數(shù)不支持硬件加速;
內(nèi)存大:使用OpenGL接口至少需要8MB內(nèi)存;
所以是否使用硬件加速需要考慮接口是否支持,通過結(jié)合產(chǎn)品形態(tài),如TV版本不需要考慮功耗問題,TV屏幕大,使用硬件加速實現(xiàn)更好的顯示效果; -
系統(tǒng)層:
真正把需要顯示器的數(shù)據(jù)渲染到屏幕上,是通過系統(tǒng)級進程匯總的SurfaceFlinger服務(wù)來實現(xiàn)的,SurfaceFlinger主要工作:
(1)響應(yīng)客戶端事件,創(chuàng)建Layer,與客戶端Surface建立連接;
(2)接收客戶端數(shù)據(jù)及屬性,修改Layer屬性,如尺寸、顏色、透明度等;
(3)將創(chuàng)建的layer內(nèi)容刷新到屏幕上;
(4)維持layer序列,并對Layer最終輸出做出裁剪計算;
既然是兩個不同進程,那么肯定需要跨進程通信機制來實現(xiàn)數(shù)據(jù)傳輸,Android顯示系統(tǒng)使用匿名共享內(nèi)存:SharedClient,每個應(yīng)用和SurfaceFlinger之間都會創(chuàng)建一個SharedClient,如下圖所示,在每個SharedClient中,最多會創(chuàng)建31個SharedBufferStack,每個Surface對應(yīng)一個SharedBufferStack,也就是一個Window;一個SharedClient對應(yīng)一個Android應(yīng)用程序,而一個Android應(yīng)用程序可能包含多個窗口,即Surface,也就是說SharedClient包含的是SharedBufferStack集合,因為最多可以創(chuàng)建31個SharedBufferStack,也就意味著一個Android應(yīng)用最多可以還包含31個窗口,同時每個SharedBufferStack中又包含兩個(低于4.1版本)或者三個(4.1及以上版本)緩沖區(qū),即顯示刷新機制中雙緩沖和三重緩沖機制;
image
最后總結(jié)起來顯示整體流程分為三個模塊:應(yīng)用層繪制到緩存區(qū),SurfaceFlinger把緩存區(qū)數(shù)據(jù)渲染到屏幕,由于是兩個不同的進程,所以Android使用匿名共享內(nèi)存SharedClient緩存需要顯示的數(shù)據(jù)來達到目的;SurfaceFlinger把緩存區(qū)的數(shù)據(jù)渲染到屏幕主要是驅(qū)動層的事情。
梳理如下:- 每個Surface對應(yīng)的BufferQueue內(nèi)部都有兩個Graphic Buffer ,一個用于繪制一個用于顯示.我們會把內(nèi)容先繪制到離屏緩 沖區(qū)(OffScreen Buffer),在需要顯示時,才把離屏緩沖區(qū)的內(nèi)容通過SwapBuffer驅(qū)動復(fù)制到Front Graphic Buffer中. Android4.1加入了Tripple Buffer。
- 這樣SurfaceFlinge就拿到了某個Surface最終要顯示的內(nèi)容,但是同一時間我們可能會有多個Surface.這里面可能是不同 應(yīng)用的Surface,也可能是同一個應(yīng)用里面類似SurefaceView和TextureView,它們都會有自己單獨的Surface.
- 這時SurfaceFlinger把所有Surface要顯示的內(nèi)容統(tǒng)一交給Hareware Composer,它會根據(jù)位置、Z-Order順序等信息合 成為最終屏幕需要顯示的內(nèi)容,而這個內(nèi)容會交給系統(tǒng)的幀緩沖區(qū)Frame Buffer來顯示(Frame Buffer是非常底層的,可以 理解為屏幕顯示的抽象).
Android是如何將view繪制到屏幕?
大致流程如下:
(1)首先應(yīng)用主線里里的每個view都會經(jīng)過老三部:measure,layout,draw.然后TextView,Button等等控件通過CPU計算轉(zhuǎn)換為內(nèi)存中的polygons(多邊圖形)和texture(紋理)。
(2)其次,CPU通過OpenGL的接口將紋理數(shù)據(jù)傳遞給GPU渲染處理,由于圖形API不允許CPU直接與GPU通信,而是通過中間圖形驅(qū)動層來連接兩部分,驅(qū)動層維護了一個隊列,CPU把display list添加到隊列中,GPU從這個隊列去除數(shù)據(jù)進行繪制,最終在屏幕上顯示出來;在這個過程中,每個View都有一個DisplayList,由DisplayList這個結(jié)構(gòu)負(fù)責(zé)保存繪制用到的所有信息,在Displaylist無需重新創(chuàng)建或改變的情況下,GPU可以直接使用這里的數(shù)據(jù)進行渲染.當(dāng)View中的某些可見組件,那么之前的DisplayList就無法繼續(xù)使用了,我們需要回頭重新創(chuàng)建一個DisplayList并且重新執(zhí)行渲染指令并更新到屏幕上。而不是像軟件繪制那樣需要向上遞歸。這樣可以大大減少繪圖的操作數(shù)量,因而提高了渲染效率.
(3)最后,GPU對圖形數(shù)據(jù)進行渲染,通過匿名共享內(nèi)存:SharedClient把需要顯示的數(shù)據(jù)傳到SurfaceFlinger;一個SharedClient對應(yīng)一個Android應(yīng)用程序,一個SharedClient可以創(chuàng)建31個SharedBufferStack;每個SharedBufferStack對應(yīng)一個Surface,也就是一個Window;每個SharedBufferStack包含的BufferQueue內(nèi)部都有三個Graphic Buffer,兩個用于繪制一個用于顯示.我們會把內(nèi)容先繪制到一個后置緩沖區(qū)(OffScreen Buffer或者Back Buffer),在另外一個繪制下一幀;在需要顯示時,才把離屏緩沖區(qū)的內(nèi)容通過SwapBuffer驅(qū)動復(fù)制到Front Graphic Buffer中, 通過它將柵格化的信息交給SurfaceFlinger,SurfaceFlinger通過創(chuàng)建維護Layer再交給Hareware Composer,它會根據(jù)Layer中的位置、Z-Order順序等信息合成為最終屏幕需要顯示的內(nèi)容,而這個內(nèi)容會交給系統(tǒng)的幀緩沖區(qū)Frame Buffer來顯示(Frame Buffer是非常底層的,可以 理解為屏幕顯示的抽象).
(4)垂直同步VSYNC 60fps: 讓顯卡的運算和顯示器刷新率一致以穩(wěn)定輸出的畫面質(zhì)量。它告知GPU在載入新幀之前,要等待屏幕繪制完成前一幀。如果下一幀周期到是屏幕前一幀沒有繪制結(jié)束,后置緩沖區(qū)不能清空,多出來的一個后置緩沖區(qū)就可以用來繪制。
名詞解釋:
DisplayList:DisplayList持有所有將要交給GPU繪制到屏幕上的數(shù)據(jù)信息。顯示刷新機制
Android系統(tǒng)一直在不斷的優(yōu)化、更新,但直到4.0版本發(fā)布,有關(guān)UI顯示不流暢的問題仍未得到根本解決;從Android4.1版本開始,Android對顯示系統(tǒng)進行了重構(gòu),引入了三個核心元素:VSYNC, Tripple Buffer和Choreographer。VSYNC是Vertical Synchronized的縮寫,是一種定時中斷;Tripple Buffer是顯示數(shù)據(jù)的緩沖區(qū);Choreographer起調(diào)度作用,將繪制工作統(tǒng)一到VSYNC的某個時間點上,使應(yīng)用的繪制工作有序進行。
名詞解釋:
雙緩沖:顯示內(nèi)容的數(shù)據(jù)內(nèi)存,雙緩沖意味著要使用兩個緩沖區(qū)(SharedBufferStack中),其中一個稱為Front Buffer,另外一個稱為Back Buffer。UI總是先在Back Buffer中繪制,然后再和Front Buffer交換,渲染到顯示設(shè)備中。
三緩沖:即Triple Buffer。一個前置緩沖區(qū)和兩個后置緩沖區(qū),利用CPU/GPU的空閑時間準(zhǔn)備數(shù)據(jù),用于彌補在VSYNC+雙緩沖配合使用的缺陷(一前一后);
VSYNC:當(dāng)雙緩沖的介紹了解到,只有當(dāng)另外一個buffer準(zhǔn)備好之后,才能去刷新,這就需要CPU以主動查詢方式來保證數(shù)據(jù)是否準(zhǔn)備好,因為這種機制效率很低,引入VSYNC,一旦受到VSYNC定時中斷,CPU就開始處理各幀數(shù)據(jù);沒有VSYNC信號,CPU不知道何時去處理UI繪制,引入VSYNC核心目的就是解決刷新不同步的問題;
Choreographer:收到VSYNC信號時,調(diào)用用戶設(shè)置的回調(diào)函數(shù),一種有三種類型的回調(diào):
CALLBACK_INPUT:優(yōu)先級最高,與輸入事件有關(guān);
CALLBACK_ANIMATON:第二優(yōu)先級,與動畫有關(guān);
CALLBACK_TRAVERSAL:最低優(yōu)先級,與UI控件繪制有關(guān);
View的onclick、onDraw等等都是從Choreographer.doFrame開始執(zhí)行的;關(guān)于Choreographer可以參考Android Choreographer 源碼分析,講的特別好;那雙緩沖機制又是什么呢?
雙緩沖機制簡單說就是不同的View或者Activity它們都會共用一個Window,
也就是共用同一個Surface對象. 而每個Surface都會有一個BufferQueue緩存隊列,但是這個隊列會由SurfaceFlinger管理,通過匿名共享內(nèi)存機制與App應(yīng)用
層交互.那三級緩沖機制又是什么呢?
簡單來說,三緩沖機制就是在雙緩沖機制基礎(chǔ)上增加了一個Graphic Buffer緩沖區(qū),這樣可以最大限度的利用空閑時間.
如果只有兩個Graphic Buffer緩存區(qū)A和B, CPU/GPU又繪制過程過?,超過了一個VSYNC信號周期,因為緩沖區(qū)B中的數(shù)據(jù)還沒有準(zhǔn)備完成,所以只能繼續(xù)展示A緩沖區(qū) 的內(nèi)容,這樣緩沖區(qū)A和B都分別被顯示設(shè)備和GPU占用,CPU無法準(zhǔn)備下一幀的數(shù)據(jù).RenderNode和RenderThread
在Android 5.0引入了兩個比較大的改變.一個是引入了RenderNode的概念,它對DisplayList及一些View顯示屬性 做了進一步封裝.另一個是引入了RenderThread,所有的GL命令執(zhí)行都放到這個線程上,渲染線程在RenderNode中存有渲 染幀的所有信息,可以做一些屬性動畫,這樣即便主線程有耗時操作的時候也可以保證動畫流暢.HWUI
hwui主要是android用于2d硬件繪圖而加入的一個模塊,在hwui之前,android主要是用skia來進行軟件繪制,后由于繪制性能等問題,現(xiàn)在android的繪圖幾乎都是使用了hwui硬件加速繪圖。hwui主要則是使用opengles來進行g(shù)pu硬件繪圖,提升整個系統(tǒng)的繪制性能,主要有以下方式:直接渲染,顯示列表渲染,延時渲染列表,分別代表的類為:OpenGLRenderer,DisplayListRenderer,DeferredDisplayList。
原文鏈接:http://www.itdecent.cn/p/abfaea892611Vulkan
Vulkan為Khronos Group推出的下一代跨平臺圖形開發(fā)接口,用于替代歷史悠久的OpenGL。Android從7.0(Nougat)開始加入了對其的支持。Vulkan與OpenGL相比,接口更底層,從而使開發(fā)者能更直接地控制GPU。由于更好的并行支持,及更小的開銷,性能上也有一定的提升。另外層式架構(gòu)可以幫助減少調(diào)試和測試的時間。但是,代價是實現(xiàn)相同的功能更復(fù)雜了。原本用OpenGL寫個最簡單的demo百來行,用vulkan祼寫的話沒千把行下不來。因此實際使用中需要有utility層來簡化接口調(diào)用。Android對vulkan的支持主要是提供接口讓開發(fā)者可以用vulkan開發(fā)圖形相關(guān)應(yīng)用,尤其是像游戲這樣的3D渲染場景。如果有支持vulkan的Android移動設(shè)備,開發(fā)者就可以利用NDK進行基于vulkan的開發(fā)
原文鏈接:https://blog.csdn.net/jinzhuojun/article/details/52430543
卡頓原理分析:
????當(dāng)這一幀畫面渲染時間超過16ms的時候,垂直同步機制會讓顯示器硬件等待這一次GPU完成柵格化渲染操作,這樣會讓這一幀畫面,多停留16ms,甚至更多,這樣就造成了畫面看起來停頓。

16毫秒的時間主要被兩件事情所占用
第一件:將UI對象轉(zhuǎn)換為一系列多邊形和紋理
第二件事情:CPU傳遞處理數(shù)據(jù)到GPU。
所以很明顯,我們要縮短這兩部分的時間,也就是說需要盡量減少對象轉(zhuǎn)換的次數(shù),以及上傳數(shù)據(jù)的次數(shù)(布局 自定義)
CPU 減少xml轉(zhuǎn)換成對象的時間
GPU 減少重復(fù)繪制的時間

什么是過度繪制:
????GPU的繪制過程,就跟刷墻一樣,一層層的進行,16ms刷一次,這樣就會造成,圖層覆蓋的現(xiàn)象,即無用的突出還是被繪制在底層,造成不必要的浪費。
GPU過度繪制幾種情況:
????1.自定義控件中 onDraw方法做了過多重復(fù)繪制
????2.布局層次太深,重疊性太強。用戶看不到的區(qū)域GPU也會渲染,導(dǎo)致耗時增加。

過度繪制工具使用鏈接
Android系統(tǒng)優(yōu)化操作:
????CPU轉(zhuǎn)移到GPU是一件很麻煩的事情,所幸的是OpenGL ES可以把那些需要渲染的紋理Hold在GPU Memory里面,在下次需要渲染的時候直接進行操作。所以如果你更新了GPU所hold住的紋理內(nèi)容,那么之前保持的狀態(tài)就丟失了。
????在Android里面那些由主題所提供的資源,例如Bitmaps,Drawables都是一起打包到統(tǒng)一的Texture紋理當(dāng)中,然后再傳遞到GPU里面,這意味著每次你需要使用這些資源的時候,都是直接從紋理里面進行獲取渲染的。當(dāng)然隨著UI組件的越來越豐富,有了更多演變的形態(tài)。例如顯示圖片的時候,需要先經(jīng)過CPU的計算加載到內(nèi)存中,然后傳遞給GPU進行渲染。文字的顯示比較復(fù)雜,需要先經(jīng)過CPU換算成紋理,然后交給GPU進行渲染,返回到CPU繪制單個字符的時候,再重新引用經(jīng)過GPU渲染的內(nèi)容。動畫則存在一個更加復(fù)雜的操作流程。
為了能夠使得App流暢,我們需要在每幀16ms以內(nèi)處理完所有的CPU與GPU的計算,繪制,渲染等等操作

以上參考了以下博客文章
http://www.itdecent.cn/p/a978a6250f9e
http://zzmblog.cn/html/sb/arc/157105315943.html
https://blog.csdn.net/ccj659/article/details/53219288

