前置硬件知識
- 刷新率(Refresh Rate):代表了屏幕在一秒內(nèi)刷新屏幕的次數(shù)欣除,這取決于硬件的固定參數(shù),例如 60Hz挪略。
- 幀率(Frame Rate):代表了 GPU 在一秒內(nèi)繪制操作的幀數(shù)历帚,例如 30fps,60fps杠娱。
-
GPU(Graphics Processing Unit)主要負(fù)責(zé) Rasterization(柵格化)操作挽牢。柵格化是指將向量圖形格式表示的圖像轉(zhuǎn)換成位圖(像素)以用于顯示設(shè)備輸出的過程,簡單來說就是將我們要顯示的視圖摊求,轉(zhuǎn)換成用像素來表示的格式禽拔。柵格化是一個(gè)非常耗時(shí)的工作。
圖片一
4.畫面撕裂(Tearing) GPU 會(huì)獲取圖形數(shù)據(jù)進(jìn)行渲染,然后硬件負(fù)責(zé)把渲染后的內(nèi)容呈現(xiàn)到屏幕上睹栖,他們兩者不停的進(jìn)行協(xié)作硫惕。如果刷新率和幀率,各自做自己的事野来,不相互協(xié)調(diào)工作恼除,那么刷新頻率和幀率并不總能夠保持相同的節(jié)奏。如果發(fā)生幀率與刷新頻率不一致的情況梁只,就會(huì)容易出現(xiàn)畫面撕裂(Tearing)的現(xiàn)象缚柳,也就是畫面上下兩部分顯示內(nèi)容發(fā)生斷裂,來自不同的兩幀數(shù)據(jù)發(fā)生重疊搪锣。
Android 黃油計(jì)劃
為了解決 Android 系統(tǒng)中最飽受詬病的一個(gè)問題秋忙,滑動(dòng)不如 iOS 流暢。因此谷歌在 4.1 版本引入了一個(gè)重大的改進(jìn)—Project Butter——黃油計(jì)劃
Project Butter 對 Android Display 系統(tǒng)進(jìn)行了重構(gòu)构舟,引入了三個(gè)核心元素灰追,即 VSYNC、Triple Buffer 和 Choreographer狗超,
我們接下來一一介紹
VSYNC(Vertical Synchronization)
垂直同步(vsync)指的是顯卡的輸出幀數(shù)和屏幕的垂直刷新率相同弹澎。在當(dāng)下,垂直同步的含義我們可以理解為努咐,使得顯卡生成幀的速度和屏幕刷新的速度的保持一致苦蒿。舉例來說,如果屏幕的刷新率為 60Hz渗稍,那么生成幀的速度就應(yīng)該被固定在 16ms佩迟。
上文中我們知道了tearing現(xiàn)象以及產(chǎn)生原因而 VSYNC 最重要的作用是防止出現(xiàn)畫面撕裂。
VSYNC 信號是由屏幕(顯示設(shè)備)產(chǎn)生的竿屹,并且以 60fps 的固定頻率發(fā)送給 Android 系統(tǒng)报强,Android 系統(tǒng)中的 SurfaceFlinger 接收發(fā)送的 VSYNC 信號。VSYNC 信號表明可對屏幕進(jìn)行刷新而不會(huì)產(chǎn)生撕裂拱燃。當(dāng) SurfaceFlinger 接收到 VSYNC 信號后秉溉,SurfaceFlinger 會(huì)遍歷其層列表,以查找新的緩沖區(qū)碗誉。如果 SurfaceFlinger 找到新的緩沖區(qū)召嘶,SurfaceFlinger 會(huì)獲取緩沖區(qū);否則哮缺,SurfaceFlinger 會(huì)繼續(xù)使用上一次獲取的那個(gè)緩沖區(qū)苍蔬。SurfaceFlinger 必須始終顯示內(nèi)容,因此它會(huì)保留一個(gè)緩沖區(qū)蝴蜓。如果在某個(gè)層上沒有提交緩沖區(qū)碟绑,則該層會(huì)被忽略俺猿。
通常來說,幀率超過刷新頻率只是一種理想的狀況格仲,在超過 60fps 的情況下押袍,GPU 所產(chǎn)生的幀數(shù)據(jù)會(huì)因?yàn)榈却?VSYNC 的刷新信息而被 Hold 住,這樣能夠保持每次刷新都有實(shí)際的新的數(shù)據(jù)可以顯示凯肋。但是我們遇到更多的情況是幀率小于刷新頻率谊惭。
在這種情況下,某些幀顯示的畫面內(nèi)容就會(huì)與上一幀的畫面相同侮东。糟糕的事情是圈盔,幀率從超過 60fps 突然掉到 60fps 以下,卡頓掉幀的不順滑的情況悄雅。這也是用戶感受不好的原因所在驱敲。
接下來,我們以具體示例來看 VSYNC 的作用宽闲。
沒有 VSYNC 的情況
- 這個(gè)圖中有三個(gè)元素众眨,Display 是顯示屏幕,GPU 和 CPU 負(fù)責(zé)渲染幀數(shù)據(jù)容诬,每個(gè)幀以方框表示娩梨,并以數(shù)字進(jìn)行編號,如0览徒、1狈定、2等等。
- CPU 正常執(zhí)行幀1习蓬,GPU 正常渲染幀1纽什,所以幀1正常顯示。
但友雳,CPU 由于被占用等原因稿湿,等到即將顯示幀2時(shí)铅匹,它才開始處理第二幀的內(nèi)容押赊,這顯然完不成了,所以等到第二幀顯示的時(shí)候包斑,只能使用上一幀的內(nèi)容顯示了流礁,也即是丟幀了。 - 上面丟幀的原因罗丰,我們可以從圖中看出神帅,是因?yàn)樾碌囊粠_始的時(shí)候,CPU 在處理其他任務(wù)萌抵,并沒有馬上執(zhí)行下一幀的任務(wù)找御。
使用VSYNC 的情況
- 第0幀顯示時(shí)元镀,CPU 和 GPU 準(zhǔn)備好了第一幀的內(nèi)容。
- 第1幀剛開始顯示時(shí)霎桅,CPU 放下手中的任務(wù)栖疑,立馬處理第2幀顯示相關(guān)的任務(wù),這樣滔驶,在第二幀顯示之前遇革, CPU 和 GPU 也提前完成了顯示任務(wù)的處理,第二幀正常顯示揭糕。
可以看到萝快,使用 VSYNC 信號機(jī)制,提升了渲染任務(wù)的優(yōu)先級著角,優(yōu)化了渲染性能揪漩,可有效的減少了丟幀、卡頓等問題雇寇。
但是上圖中仍然存在一個(gè)問題:CPU 和 GPU 處理數(shù)據(jù)的速度似乎都能在 16ms 內(nèi)完成氢拥,而且還有時(shí)間空余,也就是說锨侯,CPU 和 GPU 的幀率要高于 Display 的幀率嫩海。由于 CPU/GPU 只在收到 VSYNC 時(shí)才開始數(shù)據(jù)處理,故它們的幀率被拉低到與 Display 相同囚痴。但這種處理并沒有什么問題叁怪,因?yàn)?Android 設(shè)備的 Display FPS 一般是 60,其對應(yīng)的顯示效果非常平滑深滚。
但如果 CPU/GPU 的幀率小于 Display 的幀率奕谭,情況又不同了,將會(huì)發(fā)生如下圖的情況:
在第二個(gè) 16ms 時(shí)間段痴荐,Display 本應(yīng)顯示 B 幀血柳,但卻因?yàn)?GPU 還在處理 B 幀,導(dǎo)致 A 幀被重復(fù)顯示生兆。
同理难捌,在第二個(gè) 16ms 時(shí)間段內(nèi),CPU 無所事事鸦难,因?yàn)?A Buffer 被 Display 在使用根吁。B Buffer 被 GPU 在使用。注意合蔽,一旦過了 VSYNC 時(shí)間點(diǎn)击敌,CPU 就不能被觸發(fā)以處理繪制工作了。
以上是使用雙重緩存機(jī)制時(shí)產(chǎn)生的問題拴事,那么又如何來解決呢沃斤?
為了解決這個(gè)問題圣蝎,Android 引入了 Triple Buffer 機(jī)制。
三重緩存機(jī)制(Triple Buffer)
一般我們在繪制 UI 的時(shí)候衡瓶,都會(huì)采用一種稱為“雙緩存”的技術(shù)(例如捅彻,上面幾個(gè)例子)。雙緩存意味著要使用兩個(gè)緩存區(qū)鞍陨,其中一個(gè)稱為 Front Buffer步淹,另外一個(gè)稱為 Back Buffer。UI 總是先在 Back Buffer 中繪制诚撵,然后再和 Front Buffer 交換缭裆,渲染到顯示設(shè)備中。理想情況下寿烟,這樣一個(gè)刷新會(huì)在 16ms 內(nèi)完成澈驼,下圖就是描述的這樣一個(gè)刷新過程:Display 處理前 Front Buffer,CPU筛武、GPU 處理 Back Buffer缝其。
只有兩個(gè) Buffer(Android 4.1之前)時(shí),CPU 在空閑時(shí)徘六,如果 Back Buffer 被占用了内边,它也只能等待 GPU 使用之后再次進(jìn)行寫入。我們可以想想待锈,如果有第三個(gè) Buffer 的存在漠其,CPU 是不是就可以提前工作,而不至于空閑了竿音?所以和屎,Google 在 Android4.1 以后,引入了三重緩存機(jī)制:Tripple Buffer春瞬。Tripple Buffer 利用 CPU/GPU 的空閑等待時(shí)間提前準(zhǔn)備好數(shù)據(jù)柴信,并不一定會(huì)使用。
引入 Triple Buffer 效果如下圖所示:
上圖中宽气,第二個(gè) 16ms 時(shí)間段随常,CPU 使用 C Buffer 繪圖。雖然還是會(huì)多顯示 A 幀一次抹竹,但后續(xù)顯示就比較順暢了线罕。
那么止潮,是不是 Buffer 越多越好呢窃判?回答是否定的。由上圖可知喇闸,在第二個(gè)時(shí)間段內(nèi)袄琳,并且大量的緩存數(shù)據(jù)也會(huì)導(dǎo)致內(nèi)存增大询件,以及顯示數(shù)據(jù)是否失效等問題。所以唆樊,Buffer 三個(gè)足矣宛琅。
Choreographer
Android系統(tǒng)從4.1(API 16)開始加入 Choreographer 這個(gè)類來協(xié)調(diào)動(dòng)畫(animations)、輸入(input)逗旁、繪制(drawing)三個(gè)UI相關(guān)的操作
Choreographer 中文翻譯過來是”編舞者“嘿辟,字面上的意思就是優(yōu)雅地指揮以上三個(gè)UI操作一起跳一支舞。Choreographer 從顯示子系統(tǒng)接收定時(shí)脈沖(例如垂直同步——VSYNC 信號)片效,然后安排工作以渲染下一個(gè)顯示幀红伦。
每個(gè)線程都有自己的 Choreographer,其他線程也可以發(fā)布回調(diào)以在 Choreographer 上運(yùn)行淀衣,但它們是運(yùn)行在 Choreographer 所屬的 Looper 上昙读。
通過 Choreographer 可以注冊5種類型的回調(diào):CALLBACK_INPUT(輸入回調(diào))、CALLBACK_INPUT(動(dòng)畫回調(diào))膨桥、CALLBACK_INSETS_ANIMATION(inset updates 相關(guān)的 Animation回調(diào))蛮浑、CALLBACK_TRAVERSAL(遍歷回調(diào))和 CALLBACK_COMMIT(提交回調(diào))。
Choreographer 提供了單例調(diào)用模式只嚣,系統(tǒng)源碼中或者我們在開發(fā)中都是通過單例調(diào)用來使用 Choreographer 的沮稚。
Android系統(tǒng)通過 Choreographer 的 postCallback 方法,添加回調(diào)處理册舞,發(fā)起信號同步流程壮虫。
FrameDisplayEventReceiver(父類: DisplayEventReceiver) 的 scheduleVsync 調(diào)用了 native 層方法 nativeScheduleVsync 來實(shí)現(xiàn) VSYNC 信號的請求(向 SurfaceFlinger 服務(wù)請求 Vsync 信號)。
下一次 VSYNC 信號接收后會(huì)調(diào)用 DisplayEventReceiver 的 dispatchVsync 方法环础。
最終囚似,doFrame 方法順序執(zhí)行所有的事件回調(diào)。
總結(jié)
刷新率(Refresh Rate):代表了屏幕在一秒內(nèi)刷新屏幕的次數(shù)线得,這取決于硬件的固定參數(shù)饶唤,例如 60Hz。
幀率(Frame Rate):代表了 GPU 在一秒內(nèi)繪制操作的幀數(shù)贯钩,例如 30fps募狂,60fps。
GPU 會(huì)獲取圖形數(shù)據(jù)進(jìn)行渲染角雷,然后硬件負(fù)責(zé)把渲染后的內(nèi)容呈現(xiàn)到屏幕上祸穷,他們兩者不停的進(jìn)行協(xié)作。
如果刷新率和幀率勺三,各自做自己的事雷滚,不相互協(xié)調(diào)工作,那么刷新頻率和幀率并不總能夠保持相同的節(jié)奏吗坚。如果發(fā)生幀率與刷新頻率不一致的情況祈远,就會(huì)容易出現(xiàn)畫面撕裂(Tearing)的現(xiàn)象呆万。
從 Android 4.1 開始,谷歌在黃油計(jì)劃中车份,引入了了三個(gè)核心元素谋减,即 VSYNC、Triple Buffer 和 Choreographer扫沼。
VSYNC 信號是由屏幕(顯示設(shè)備)產(chǎn)生的出爹,并且以 60fps 的固定頻率發(fā)送給 Android 系統(tǒng),Android 系統(tǒng)中的 SurfaceFlinger 接收發(fā)送的 VSYNC 信號缎除。VSYNC 信號表明可對屏幕進(jìn)行刷新而不會(huì)產(chǎn)生撕裂以政。
使用 VSYNC 信號機(jī)制,提升了渲染任務(wù)的優(yōu)先級伴找,優(yōu)化了渲染性能盈蛮,可有效的減少了丟幀、卡頓等問題技矮。
三重緩存機(jī)制(Triple Buffer) 利用 CPU/GPU 的空閑等待時(shí)間提前準(zhǔn)備好數(shù)據(jù)抖誉,有效的提升了渲染性能
Choreographer 這個(gè)類來協(xié)調(diào)動(dòng)畫(animations)、輸入(input)衰倦、繪制(drawing)三個(gè)UI相關(guān)的操作