Android 之理解 VSYNC 信號(hào)

UI 優(yōu)化系列專題占贫,來(lái)聊一聊 Android 渲染相關(guān)知識(shí),主要涉及 UI 渲染背景知識(shí)齐婴、如何優(yōu)化 UI 渲染兩部分內(nèi)容单匣。


UI 優(yōu)化系列專題
  • UI 渲染背景知識(shí)

View 繪制流程之 setContentView() 到底做了什么?
View 繪制流程之 DecorView 添加至窗口的過(guò)程
深入 Activity 三部曲(3)View 繪制流程
Android 之 LayoutInflater 全面解析
關(guān)于渲染铃绒,你需要了解什么鸽照?
Android 之 Choreographer 詳細(xì)分析

  • 如何優(yōu)化 UI 渲染

Android 之如何優(yōu)化 UI 渲染(上)
Android 之如何優(yōu)化 UI 渲染(下)


優(yōu)化是無(wú)止境的,Google 在 2012 年的 I/O 大會(huì)上宣布了 Project Butter 黃油計(jì)劃颠悬,并且在 Android 4.1 中正式開啟了這個(gè)機(jī)制矮燎。

Project Butter 主要包含兩個(gè)組成部分:一個(gè)是 VSYNC,另一個(gè)是 Triple Buffering赔癌。

也正是從這時(shí)候開始诞外,作為嚴(yán)重影響 Android 口碑的 UI 流暢性問(wèn)題便得到了有效解決。今天我們就來(lái)聊一聊這兩個(gè)組成部分的工作原理灾票,不過(guò)在理解它們之前峡谊,需要先看下所涉及的另外兩個(gè)概念:

1. 刷新率

表示屏幕在一秒內(nèi)刷新畫面的次數(shù), 刷新率取決于硬件的固定參數(shù),單位 HZ(Hz)靖苇。例如常見(jiàn)的 60 Hz席噩,即每秒鐘刷新 60 次。

逐行掃描

顯示器并不是一次性將畫面顯示到屏幕上贤壁,而是從左到右邊悼枢,從上到下逐行掃描顯示,不過(guò)這一過(guò)程快到人眼無(wú)法察覺(jué)到變化脾拆,以 60 Hz 刷新率的屏幕為例馒索,即 1000 / 60 ≈ 16ms。

2. 幀速率

表示 GPU 在一秒內(nèi)繪制操作的幀數(shù)名船。例如電影采用 24 fps绰上、Android 系統(tǒng)采用 60 fps,即一秒鐘繪制 30 / 60 幀畫面渠驼。更多內(nèi)容參考《Why 60 fps》蜈块。


屏幕撕裂

現(xiàn)在,刷新頻率和幀速率需要一起合作迷扇,才能使圖形內(nèi)容呈現(xiàn)在屏幕上百揭,GPU 會(huì)獲取圖形數(shù)據(jù)進(jìn)行繪制, 然后硬件負(fù)責(zé)把圖像內(nèi)容呈現(xiàn)到屏幕上蜓席,這一過(guò)程在應(yīng)用程序的生命周期內(nèi)一遍又一遍的發(fā)生器一。

不幸的是,刷新頻率和幀率并不總是能夠保持相對(duì)同步厨内,如果你的幀速率實(shí)際比刷新率快祈秕,例如幀速率是 120 fps,顯示器的刷新頻率為 60 Hz雏胃。此時(shí)將會(huì)發(fā)生一些視覺(jué)上的問(wèn)題请毛。

由于顯示器提取畫面是從左到右,從上到下逐行掃描提取圖像顯示丑掺,這一過(guò)程需要 16ms(1000 / 60)获印,當(dāng) GPU 利用一塊內(nèi)存區(qū)域?qū)懭霂瑪?shù)據(jù)時(shí),從頂部開始新一幀覆蓋前一幀街州,并立刻輸出一行內(nèi)容兼丰。當(dāng)屏幕刷新時(shí),它并不知道圖像緩沖區(qū)的狀態(tài)唆缴,因此它從 GPU 抓取的幀并不是完整的數(shù)據(jù)鳍征。也就是它有一半的前一幀和一半的當(dāng)前幀,這種情況被稱之為屏幕撕裂面徽。

  • 理想情況下艳丛,希望顯示器在完成一幀繪制之后再?gòu)?GPU 獲取到下一幀圖像數(shù)據(jù)匣掸,但是由于幀率和刷新頻率不一致導(dǎo)致顯示器在繪圖過(guò)程中,GPU 已經(jīng)開始加載下一幀圖像數(shù)據(jù)氮双。屏幕撕裂是由于幀率和刷新頻率不一致的情況導(dǎo)致碰酝。

解決該問(wèn)題的方案是雙緩沖,即 GPU 和顯示器都有各自的工作緩沖區(qū)戴差。GPU 始終將完成的一幀繪制數(shù)據(jù)寫入到 Back Buffer送爸,而顯示器使用 Frame Buffer。當(dāng)屏幕刷新時(shí)暖释,F(xiàn)rame Buffer 并不會(huì)發(fā)生變化袭厂。Back Buffer 根據(jù)屏幕的刷新將數(shù)據(jù) copy 到 Frame Buffer,這便是 VSYNC 的用武之地球匕。

在 Android 4.1 之前纹磺,Android 使用雙緩沖機(jī)制。怎么理解呢亮曹?一般來(lái)說(shuō)橄杨,同一個(gè) View Hierarchy 內(nèi)的 View 都會(huì)共用一個(gè) Window,也就是共用一個(gè) Surface照卦。

而每個(gè) Surface 都會(huì)有一個(gè) BufferQueue 緩存隊(duì)列讥珍,但是這個(gè)隊(duì)列會(huì)由 SurfaceFlinger 管理,通過(guò)匿名共享內(nèi)存與 App 應(yīng)用層交互窄瘟。

整個(gè)流程如下:

  • 每個(gè) Surface 對(duì)應(yīng)的 BufferQueue 內(nèi)部都有兩個(gè) Graphic Buffer,一個(gè)用于繪制一個(gè)用于顯示趟卸。系統(tǒng)會(huì)把內(nèi)容先到離屏緩沖區(qū)(OffScreen Buffer)蹄葱,在需要顯示時(shí),才把離屏緩沖區(qū)的內(nèi)容通過(guò) Swap Buffer 復(fù)制到 Front Graphic Buffer 中锄列。

  • 這樣 SurfaceFlinger 就拿到了某個(gè) Surface 最終要顯示的內(nèi)容图云,但是同一時(shí)間我們可能會(huì)有多個(gè) Surface。這里面可能是不同應(yīng)用的 Surface邻邮,也可能是同一個(gè)應(yīng)用里面類似 SurfaceView 和 TextureView竣况,它們都會(huì)有自己?jiǎn)为?dú)的 Surface。

  • 這個(gè)時(shí)候 SurfaceFlinger 把所有 Surface 要顯示的內(nèi)容統(tǒng)一交給 Hardware Composer筒严,它會(huì)根據(jù)位置丹泉、Z-Order 順序等信息合成為最終屏幕需要顯示的內(nèi)容,而這個(gè)內(nèi)容會(huì)交給系統(tǒng)的幀緩沖區(qū) Frame Buffer 來(lái)顯示(Frame Buffer 是非常底層的鸭蛙,可以理解為屏幕顯示的抽象)摹恨。

Android 一直使用 VSYNC 來(lái)阻止屏幕撕裂,對(duì)于 Android 4.0娶视,CPU 可能會(huì)因?yàn)樵诿ζ渌氖虑樯购澹瑢?dǎo)致沒(méi)來(lái)得及處理 UI 繪制睁宰。所以從 4.1 開始 VSYNC 則更進(jìn)一步,VSYNC 脈沖現(xiàn)在用于開始下一幀的所有處理寝凌。

VSYNC 類似于時(shí)鐘中斷柒傻,每收到 VSYNC 中斷,CPU 會(huì)立即準(zhǔn)備 Buffer 數(shù)據(jù)较木,由于大部分顯示設(shè)備刷新頻率都是 60Hz(一秒刷新 60 次)红符,也就是說(shuō)一幀數(shù)據(jù)的準(zhǔn)備工作都要在 16ms(1000/60≈16)內(nèi)完成。

這樣應(yīng)用總是在 VSYNC 邊界上開始繪制劫映,而 SurfaceFlinger 總是在 VSYNC 邊界上進(jìn)行合成违孝。這樣便可以消除卡頓,并提升圖形的視覺(jué)表現(xiàn)泳赋。

Triple Buffering

如果理解了雙緩沖機(jī)制的原理雌桑,那就非常容易理解什么是三緩沖區(qū)了。如果只有兩個(gè) Graphic Buffer 緩存區(qū) A 和 B祖今,如果 CPU/GPU 繪制過(guò)程較長(zhǎng)校坑,超過(guò)了一個(gè) VSYNC 信號(hào)周期,因?yàn)榫彌_區(qū) B 中的數(shù)據(jù)還沒(méi)有準(zhǔn)備完成千诬,所以只能繼續(xù)展示 A 緩沖區(qū)的內(nèi)容耍目,這樣緩沖區(qū) A 和 B 都分別被顯示設(shè)備和 GPU 占用,CPU 則無(wú)法準(zhǔn)備下一幀的數(shù)據(jù)徐绑。

如果再提供一個(gè)緩沖區(qū)邪驮,CPU、GPU 和顯示設(shè)備都能使用各自的緩沖區(qū)工作毅访,互不影響盘榨。簡(jiǎn)單來(lái)說(shuō),三緩沖機(jī)制就是在雙緩沖機(jī)制基礎(chǔ)上增加了一個(gè) Graphic Buffer 緩沖區(qū)草巡,這樣可以最大限度利用空閑時(shí)間守呜,帶來(lái)的壞處是多使用了一個(gè) Graphic Buffer 所占用的內(nèi)存查乒。

從圖中可以看出,緩沖區(qū) B 花費(fèi)的時(shí)間太長(zhǎng)萍歉,并且正在使用 A 來(lái)顯示當(dāng)前幀。不過(guò)這次憔晒,系統(tǒng)不是在重復(fù)的緩沖區(qū)中浪費(fèi)時(shí)間拒担,而是創(chuàng)建一個(gè) C 緩沖區(qū),并開始處理下一幀州弟。三重緩沖降低了 jank 的進(jìn)一步加劇婆翔。

三緩沖并不總是存在掏婶,通常情況下僅運(yùn)行一個(gè)雙緩沖區(qū)雄妥,但是當(dāng)發(fā)生延遲等情況時(shí)老厌,第三個(gè)緩沖區(qū)就會(huì)出現(xiàn)枝秤,以便降低延遲的加劇。對(duì)于 VSYNC 信號(hào)和 Triple Buffering 更詳細(xì)的介紹趁仙,可以參考《Project Butter - How it works and What it added?》干奢。

Android 渲染框架非常龐大忿峻,而且演進(jìn)的非常快搓谆。感興趣的朋友可以進(jìn)一步閱讀下面的參考資料到逊。


擴(kuò)展閱讀
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載蚕苇,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者捆蜀。
  • 序言:七十年代末辆它,一起剝皮案震驚了整個(gè)濱河市锰茉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌片吊,老刑警劉巖俏脊,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異补憾,居然都是意外死亡盈匾,警方通過(guò)查閱死者的電腦和手機(jī)削饵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)橱赠,“玉大人狭姨,你說(shuō)我怎么就攤上這事饼拍∈Τ” “怎么了教硫?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵茶鉴,是天一觀的道長(zhǎng)涵叮。 經(jīng)常有香客問(wèn)我割粮,道長(zhǎng)媚污,這世上最難降的妖魔是什么耗美? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮谬盐,結(jié)果婚禮上飞傀,老公的妹妹穿的比我還像新娘。我一直安慰自己绞吁,他們只是感情好家破,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布汰聋。 她就那樣靜靜地躺著烹困,像睡著了一般髓梅。 火紅的嫁衣襯著肌膚如雪绎签。 梳的紋絲不亂的頭發(fā)上辜御,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天袱巨,我揣著相機(jī)與錄音碳抄,去河邊找鬼剖效。 笑死璧尸,一個(gè)胖子當(dāng)著我的面吹牛爷光,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欢瞪,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼啸盏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼回懦!你這毒婦竟也來(lái)了曾我?” 一聲冷哼從身側(cè)響起抒巢,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤稚晚,失蹤者是張志新(化名)和其女友劉穎型诚,沒(méi)想到半個(gè)月后狰贯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涵紊,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颤练,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年嗦玖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宇挫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片器瘪。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娱局,死狀恐怖衰齐,靈堂內(nèi)的尸體忽然破棺而出耻涛,到底是詐尸還是另有隱情瘟檩,我是刑警寧澤墨辛,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布奏赘,位于F島的核電站太惠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏梁只。R本人自食惡果不足惜搪锣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佩谷。 院中可真熱鬧谐檀,春花似錦桐猬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坚嗜。三九已至诗充,卻和暖如春蝴蜓,著一層夾襖步出監(jiān)牢的瞬間励翼,已是汗流浹背汽抚。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工造烁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惭蟋,地道東北人告组。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓木缝,卻偏偏與公主長(zhǎng)得像我碟,于是被迫代替她去往敵國(guó)和親矫俺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355