Android VSYNC與圖形系統(tǒng)中的撕裂、雙緩沖球昨、三緩沖淺析

VSYNC與畫面撕裂

VSYNC即vertical sync尔店,也稱為垂直同步,是一種圖形技術(shù),主要就是強(qiáng)制將幀速率與顯示器的刷新率同步嚣州,最初由 GPU 制造商提出鲫售,主要用來(lái)處理屏幕撕裂。首先了解下兩個(gè)名詞:FPS與屏幕刷新頻率

  • 幀率[Frame Rate该肴,單位FPS]-顯卡生成幀的速率情竹,也可以認(rèn)為是數(shù)據(jù)處理的速度
  • 屏幕刷新頻率 [Refresh Rate單位赫茲/HZ]:是指硬件設(shè)備刷新屏幕的頻率,值一般是固定的匀哄,以黑白電視的電子掃描槍類比秦效,比如60Hz的顯示屏,每16ms電子槍從上到下從左到右一行一行逐漸把圖片繪制出來(lái)涎嚼。

兩者要同步配合好才能高效的顯示圖像阱州,可以人為幀率對(duì)應(yīng)的是圖像數(shù)據(jù)的輸出,刷新率對(duì)應(yīng)的是圖像數(shù)據(jù)的屏幕展示苔货,如果幀率同設(shè)備的刷新率不一致鹊汛,而又沒(méi)有采用合適的同步技術(shù),會(huì)出現(xiàn)什么問(wèn)題呢滥嘴?可能會(huì)出現(xiàn)上述的屏幕撕裂[多幀的局部數(shù)據(jù)共同組成了一個(gè)完整幀]至耻,示意如下:

image.png

理論上來(lái)講,只要沒(méi)做到讀/寫線性同步就有幾率發(fā)生撕裂走触, 只有幀數(shù)據(jù)完整更新+顯示設(shè)備完整渲染才能阻止撕裂疤苹,相對(duì)應(yīng)的撕裂的復(fù)現(xiàn)場(chǎng)景有兩種:

  • 1:顯示設(shè)備未完整渲染: 假設(shè)顯示設(shè)備只有一塊顯存存放顯示數(shù)據(jù),在沒(méi)有同步加鎖的情況下卧土,幀數(shù)據(jù)由CPU/GPU處理完可隨時(shí)寫入到顯存,如果恰好在上一幀A還沒(méi)100%在屏幕顯示完的時(shí)候旅敷,B幀到達(dá)颤霎,并且覆蓋了A涂滴,那么在繼續(xù)刷新下半部分時(shí)晴音,繪制的就是B幀數(shù)據(jù),此時(shí)就會(huì)出現(xiàn)上半部分是A下半部分是B首量,即發(fā)生屏幕撕裂:如下
image.png
  • 2 幀數(shù)據(jù)未完整更新 :依舊假設(shè)顯示設(shè)備只有一塊顯存存放顯示數(shù)據(jù)进苍,如果在GPU覆蓋舊幀的間隙觉啊,也就是顯存數(shù)據(jù)沒(méi)有100%刷新的時(shí)候沈贝,通知渲染到屏幕,這個(gè)時(shí)候同樣會(huì)發(fā)生上述事情宋下,即使用了半成品的幀:撕裂幀。參考視頻

所以同步鎖的機(jī)制是撕裂的關(guān)鍵罩引,必須有這么一個(gè)機(jī)制告訴GPU顯卡枝笨,要等待當(dāng)前幀繪完整,才能替換當(dāng)前幀横浑,即VSYNC,VSYNC強(qiáng)制幀率和顯示器刷新頻率同步洒缀,如果當(dāng)前幀沒(méi)繪制完欺冀,即使下一幀準(zhǔn)備好了,也禁止使用下一幀脚猾,直到顯示器繪制完當(dāng)前幀,即:60HZ顯示器砰奕,開(kāi)了垂直同步后,顯示幀率就會(huì)限定最高60军援,即使顯卡輸出高達(dá)90FPS也沒(méi)用,甚至可以認(rèn)為他是一種妥協(xié)性優(yōu)化胸哥,一定程度上還會(huì)降低性能。以上都是針對(duì)一塊顯示存儲(chǔ)的情況庐船,理論上只要加鎖就能解決,讀的時(shí)候禁止寫筐钟,但這么做無(wú)疑會(huì)大大降低效率赋朦,所以不能簡(jiǎn)單依靠單純加鎖解決問(wèn)題。

雙緩沖+垂直同步

如何解決單緩沖+同步的性能問(wèn)題呢壹将?多增加一塊顯示存儲(chǔ)區(qū)能解決嗎?假定顯示設(shè)備有兩塊顯存诽俯,BackBuffer與FrontBuffer狱庇,可以簡(jiǎn)單的認(rèn)為CPU/GPU占據(jù)一個(gè)緩沖、當(dāng)前呈現(xiàn)的數(shù)據(jù)占據(jù)一個(gè)緩沖颜启,GPU/CPU 繪制更新BackBuffer,不需要關(guān)心正在展示的FrontBuffer缰盏,這就是雙緩沖淹遵,相比于單緩存,雙緩沖可讓寫與讀分離济炎,提高效率。但緊靠雙緩沖理論上解決不了撕裂的問(wèn)題须尚,BackBuffer畢竟也是要展示的,也要”拷貝“到FrontBuffer耐床,如果不對(duì)拷貝操作添加干預(yù),也可能出現(xiàn)撕裂撩轰,VSYNC機(jī)制必須兼具禁止在刷新的過(guò)程中更新FrontBuffer的功能,所有的COPY或者說(shuō)是Page flipping操作都要等待上一幀完全渲染完才可以堪嫂,渲染完成之后,顯示設(shè)備就按節(jié)奏可以發(fā)出下一個(gè)VSYNC信號(hào)镜廉,通知BackBuffer與FrontBuffer間進(jìn)行拷貝愚战,拷貝結(jié)束后齐遵,接著進(jìn)行下一幀屏幕渲染,這樣就能避免屏幕撕裂梗摇,當(dāng)然,如果BackBuffer還未來(lái)得及完成幀更新也是需要阻斷拷貝過(guò)程断序,否則就是渲染了半成品的幀,所以個(gè)人人為违诗,Vsync解決撕裂疮蹦、雙緩沖來(lái)解決性能。

It does this by preventing the GPU from doing anything to the display memory until the monitor has concluded its current refresh cycle — effectively not feeding it any more information until it’s ready for it. Through a combination of double buffering and page flipping, VSync synchronizes the drawing of frames onto the display only when it has finished a refresh cycle, so you shouldn’t ever see tears when VSync is enabled.

image.png

對(duì)Android系統(tǒng)而言阵苇,VSYNC除了強(qiáng)制幀率和顯示器刷新頻率同步外感论,還有其他很多作用,在Android Jelly Bean之前VSYNC使用的場(chǎng)景比較少比肄,只用在最后緩沖區(qū)切換囊陡,系統(tǒng)的其他環(huán)節(jié)沒(méi)用关斜,這種做法可能會(huì)讓CPU浪費(fèi)在其他低優(yōu)先級(jí)的業(yè)務(wù)上,如下圖:

image.png

如此情況就是一次jank

image.png

Jelly Bean之前VSYNC僅用在最后的圖像顯示階段痢畜,防止屏幕撕裂丁稀,但是并未協(xié)調(diào)UI的繪制,CPU對(duì)于顯示幀的處理是凌亂的线衫,VSYNC到達(dá)后惑折,如果CPU被其他任務(wù)占據(jù),UI繪制的執(zhí)行就會(huì)延遲惨驶,等到它開(kāi)始處理UI生成幀的時(shí)候,可能已經(jīng)處于16ms的中間屋确,這樣就很容易跨兩個(gè)VYSNC信號(hào)续扔,導(dǎo)致掉幀。在Jelly Bean中纱昧,下一幀的處理被限定在VSync信號(hào)到達(dá)時(shí),并且依賴Android的消息屏障機(jī)制呜投,將UI重繪消息的優(yōu)先級(jí)是提高存璃,其他的同步消息均不會(huì)執(zhí)行,由于是在每個(gè)VSYNC信號(hào)到達(dá)時(shí)就處理幀纵东,可以讓UI繪制充分使用16ms耗時(shí),可以盡量避免跨越兩幀的情況出現(xiàn)洒扎。

image.png

這種做法保證了UI繪制的執(zhí)行時(shí)間,雖然不能完全解決jank【比如本身繪制就超過(guò)16ms】袍冷,但是對(duì)于本來(lái)就小于16ms的任務(wù)是能保證的,從而降低jank的概率邓线,因此VSYNC+雙緩沖能夠很好降低單緩沖的性能問(wèn)題,降低延時(shí)骇陈。

雙緩沖的進(jìn)階:三緩沖

之前的VSYNC+雙緩沖流程圖示都是用1瑰抵、2、3代表第幀來(lái)表示更新流程二汛,接線來(lái)用緩沖區(qū)代表,看一下雙緩沖的數(shù)據(jù)流向逛球,理想情況下苫昌,16ms內(nèi)CPU處理完數(shù)據(jù)幸海,將緩沖區(qū)A交給GPU,GPU接著處理A物独,結(jié)束后,等下個(gè)VSYNC與前面展示緩沖區(qū)B交換婉陷,A進(jìn)行屏幕渲染官研,B回收用來(lái)繼續(xù)生成下一幀,如下圖所示:

image.png

在這種模型下担神,CPU與GPU其實(shí)是一種串行處理的操作,存在資源的浪費(fèi)妄讯,因?yàn)閮烧咂湟槐乜臻e,畢竟沒(méi)有多余的緩沖區(qū)讓其處理數(shù)據(jù)亥贸,理想情況下其實(shí)雙緩沖并未有什么不妥,但是一旦CPU或者GPU處理超時(shí)炕置,jank就很容易發(fā)生。

VSYNC+雙緩沖保證低延時(shí)垦沉,三緩沖保證穩(wěn)定性:讓閑置的資源動(dòng)起來(lái)

雙緩沖模型中顯示仍劈、CPU厕倍、GPU處理都會(huì)用到Buffer贩疙,VSYNC+雙緩沖在理想情況下是沒(méi)有問(wèn)題的,但如果某個(gè)環(huán)節(jié)出現(xiàn)問(wèn)題组民,那就不一樣了,比如某些幀耗時(shí)是[CPU 8ms +GPU 12ms]臭胜,超過(guò)了16ms癞尚,如下:

image.png

可以看到在第二個(gè)階段,存在CPU資源浪費(fèi)仪壮,雙緩沖只會(huì)提供兩個(gè)Buffer胳徽,B被GPU處理占用积锅,A正在用顯示养盗,那么在第二個(gè)16ms里面,CPU就無(wú)法獲取到Buffer處理UI更新往核,在Jank的階段空空等待。而且蝶缀,一般出現(xiàn)這種場(chǎng)景都是連續(xù)的:比如復(fù)雜視覺(jué)效果,那么GPU可能會(huì)一直超負(fù)荷翁都,CPU一直跟GPU搶Buffer,這樣帶來(lái)的問(wèn)題就是滾雪球似的掉幀鳍悠,一直浪費(fèi),完全沒(méi)有利用CPU與GPU并行處理的效率坐搔,成了串行處理,如下所示

image.png

如何處理呢蠢挡?多增加一個(gè)Buffer給CPU用凳忙,讓它提前忙起來(lái),這樣就能做到三方都有Buffer可用勤家,CPU不用跟GPU爭(zhēng)一個(gè)Buffer柳恐,真正實(shí)現(xiàn)并行處理。如下:

image.png

如上圖所示讼庇,雖然即使每幀需要20ms【CPU 8ms +GPU 12ms】伤提,但是由于多加了一個(gè)Buffer认烁,實(shí)現(xiàn)了CPU跟GPU并行,便可以做到了只在開(kāi)始掉一幀舶沛,后續(xù)卻不掉幀窗价,雙緩沖充分利用16ms做到低延時(shí),三緩沖保障了其穩(wěn)定性撼港,為什么4緩沖沒(méi)必要呢骤竹?因?yàn)槿齻€(gè)既可保證并行蒙揣,四個(gè)徒增資源浪費(fèi)开瞭。 在Android系統(tǒng)中,雙緩沖不僅僅是兩份存儲(chǔ)嗤详,它是一個(gè)概念,雙緩沖是一條鏈路递宅,不是某一個(gè)環(huán)節(jié)冬筒,是整個(gè)系統(tǒng)采用的一個(gè)機(jī)制,需要各個(gè)環(huán)節(jié)的支持舞痰,從APP到SurfaceFlinger、到圖像顯示都要參與協(xié)作玷禽。對(duì)于APP端而言呀打,每個(gè)Window都是一個(gè)雙緩沖的模型,一個(gè)Window對(duì)應(yīng)一個(gè)Surface贬丛,而每個(gè)Surface里至少映射兩個(gè)存儲(chǔ)區(qū),一個(gè)給圖層合成顯示用额获,一個(gè)給APP端圖形處理恭应,這便是應(yīng)于上層的雙緩沖。

總結(jié)

  • 同步是防止畫面撕裂的關(guān)鍵昼榛,VSYNC同步能防止畫面撕裂
  • VSYNC+雙緩沖在Android中能有序規(guī)劃渲染流程,降低延時(shí)
  • Android已經(jīng)采用了雙緩沖奥喻,雙緩沖不僅僅是兩份存儲(chǔ),它是一個(gè)概念衫嵌,雙緩沖是一條鏈路,不是某一個(gè)環(huán)節(jié)结闸,是整個(gè)系統(tǒng)采用的一個(gè)機(jī)制酒朵,需要各個(gè)環(huán)節(jié)的支持,從APP到SurfaceFlinger蔫耽、到圖像顯示都要參與協(xié)作
  • 三緩沖在UI復(fù)雜情況下能保證畫面的連續(xù)性,提高柔韌性

參考文檔

Google I/O 2012 - For Butter or Worse: Smoothing Out Performance in Android UIs

Android Performance Patterns: Understanding VSYNC

作者:看書(shū)的小蝸牛

Android VSYNC與圖形系統(tǒng)中的雙緩沖图甜、三緩沖淺析

僅供參考鳖眼,歡迎指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末钦讳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子愿卒,更是在濱河造成了極大的恐慌,老刑警劉巖易结,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柜候,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡滋尉,警方通過(guò)查閱死者的電腦和手機(jī)玉控,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)碾篡,“玉大人,你說(shuō)我怎么就攤上這事开泽】桑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵峦耘,是天一觀的道長(zhǎng)旅薄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)少梁,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任第焰,我火速辦了婚禮著洼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豹悬。我一直安慰自己,他們只是感情好瞻佛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布伤柄。 她就那樣靜靜地躺著,像睡著了一般适刀。 火紅的嫁衣襯著肌膚如雪煤蹭。 梳的紋絲不亂的頭發(fā)上取视,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天作谭,我揣著相機(jī)與錄音,去河邊找鬼折欠。 笑死吼过,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盗忱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼斤葱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼揖闸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起汤纸,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贮泞,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后啃擦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡聚霜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年珠叔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姥芥。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡汇鞭,死狀恐怖报嵌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤腕巡,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站煎楣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏择懂。R本人自食惡果不足惜另玖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慷丽。 院中可真熱鬧,春花似錦要糊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至药有,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間塑猖,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工羊苟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人令花。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像兼都,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子扮碧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345