Android 黃油計(jì)劃和顯示刷新機(jī)制學(xué)習(xí)筆記

前置硬件知識

  1. 刷新率(Refresh Rate):代表了屏幕在一秒內(nèi)刷新屏幕的次數(shù)欣除,這取決于硬件的固定參數(shù),例如 60Hz挪略。
  2. 幀率(Frame Rate):代表了 GPU 在一秒內(nèi)繪制操作的幀數(shù)历帚,例如 30fps,60fps杠娱。
  3. 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 的情況

圖片四
  1. 第0幀顯示時(shí)元镀,CPU 和 GPU 準(zhǔn)備好了第一幀的內(nèi)容。
  2. 第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é)

  1. 刷新率(Refresh Rate):代表了屏幕在一秒內(nèi)刷新屏幕的次數(shù)线得,這取決于硬件的固定參數(shù)饶唤,例如 60Hz。

  2. 幀率(Frame Rate):代表了 GPU 在一秒內(nèi)繪制操作的幀數(shù)贯钩,例如 30fps募狂,60fps。

  3. GPU 會(huì)獲取圖形數(shù)據(jù)進(jìn)行渲染角雷,然后硬件負(fù)責(zé)把渲染后的內(nèi)容呈現(xiàn)到屏幕上祸穷,他們兩者不停的進(jìn)行協(xié)作。

  4. 如果刷新率和幀率勺三,各自做自己的事雷滚,不相互協(xié)調(diào)工作,那么刷新頻率和幀率并不總能夠保持相同的節(jié)奏吗坚。如果發(fā)生幀率與刷新頻率不一致的情況祈远,就會(huì)容易出現(xiàn)畫面撕裂(Tearing)的現(xiàn)象呆万。

  5. 從 Android 4.1 開始,谷歌在黃油計(jì)劃中车份,引入了了三個(gè)核心元素谋减,即 VSYNC、Triple Buffer 和 Choreographer扫沼。

  6. VSYNC 信號是由屏幕(顯示設(shè)備)產(chǎn)生的出爹,并且以 60fps 的固定頻率發(fā)送給 Android 系統(tǒng),Android 系統(tǒng)中的 SurfaceFlinger 接收發(fā)送的 VSYNC 信號缎除。VSYNC 信號表明可對屏幕進(jìn)行刷新而不會(huì)產(chǎn)生撕裂以政。

  7. 使用 VSYNC 信號機(jī)制,提升了渲染任務(wù)的優(yōu)先級伴找,優(yōu)化了渲染性能盈蛮,可有效的減少了丟幀、卡頓等問題技矮。

  8. 三重緩存機(jī)制(Triple Buffer) 利用 CPU/GPU 的空閑等待時(shí)間提前準(zhǔn)備好數(shù)據(jù)抖誉,有效的提升了渲染性能

  9. Choreographer 這個(gè)類來協(xié)調(diào)動(dòng)畫(animations)、輸入(input)衰倦、繪制(drawing)三個(gè)UI相關(guān)的操作

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末袒炉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子樊零,更是在濱河造成了極大的恐慌我磁,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驻襟,死亡現(xiàn)場離奇詭異夺艰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沉衣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門郁副,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人豌习,你說我怎么就攤上這事存谎。” “怎么了肥隆?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵既荚,是天一觀的道長。 經(jīng)常有香客問我栋艳,道長恰聘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮憨琳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旬昭。我一直安慰自己篙螟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布问拘。 她就那樣靜靜地躺著遍略,像睡著了一般。 火紅的嫁衣襯著肌膚如雪骤坐。 梳的紋絲不亂的頭發(fā)上绪杏,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音纽绍,去河邊找鬼蕾久。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拌夏,可吹牛的內(nèi)容都是我干的僧著。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼障簿,長吁一口氣:“原來是場噩夢啊……” “哼盹愚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起站故,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤皆怕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后西篓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愈腾,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年岂津,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了顶滩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寸爆,死狀恐怖礁鲁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赁豆,我是刑警寧澤仅醇,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站魔种,受9級特大地震影響析二,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一叶摄、第九天 我趴在偏房一處隱蔽的房頂上張望属韧。 院中可真熱鬧,春花似錦蛤吓、人聲如沸宵喂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锅棕。三九已至,卻和暖如春淌山,著一層夾襖步出監(jiān)牢的瞬間裸燎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工泼疑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留德绿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓退渗,卻偏偏與公主長得像脆炎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子氓辣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 丟幀和卡頓 卡頓秒裕,是字面意思上來講,就是畫面不流暢钞啸,即頁面刷新不連貫几蜻。Android系統(tǒng)默認(rèn)的頁面刷新頻率是60幀...
    zackyG閱讀 1,483評論 7 9
  • @[TOC] 閱讀本篇可能需要的預(yù)備知識《View的工作原理》絮吵、《Handler:Android消息機(jī)制》弧烤、《Wi...
    胡飛洋閱讀 2,937評論 1 16
  • 久違的晴天,家長會(huì)蹬敲。 家長大會(huì)開好到教室時(shí)暇昂,離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)伴嗡。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,528評論 16 22
  • 今天感恩節(jié)哎急波,感謝一直在我身邊的親朋好友。感恩相遇瘪校!感恩不離不棄澄暮。 中午開了第一次的黨會(huì)名段,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,572評論 0 11
  • 可愛進(jìn)取,孤獨(dú)成精泣懊。努力飛翔伸辟,天堂翱翔。戰(zhàn)爭美好馍刮,孤獨(dú)進(jìn)取信夫。膽大飛翔,成就輝煌渠退。努力進(jìn)取忙迁,遙望脐彩,和諧家園碎乃。可愛游走...
    趙原野閱讀 2,738評論 1 1