日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

GUI系統(tǒng)之SurfaceFlinger(9)Project Butter黃油計劃

 老匹夫 2014-03-29
分類: Android專欄 2013-05-21 13:39 2250人閱讀 評論(2) 收藏 舉報

目錄(?)[+]

文章都是通過閱讀源碼分析出來的,還在不斷完善與改進(jìn)中,其中難免有些地方理解得不對,歡迎大家批評指正。
轉(zhuǎn)載請注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系統(tǒng)之SurfaceFlinger章節(jié)目錄:
blog.csdn.net/uiop78uiop78/article/details/8954508





1.1 SurfaceFlinger

從這一小節(jié)開始,我們正式切入SurfaceFlinger的分析。為了保持講解的連貫性,部分內(nèi)容可能在前面的章節(jié)中已經(jīng)有所涉及了,接下來將會對其中的細(xì)節(jié)做更多的擴(kuò)展講解。

內(nèi)容組織如下:

l  首先介紹Android 4.1引入的新特性(Project Butter),理解這個項(xiàng)目是必要的,可以說SurfaceFlinger有很大一部分的內(nèi)容就是圍繞它來的

l  SurfaceFlinger的啟動過程及工作方式

l  SurfaceFlinger與BufferQueue及應(yīng)用程序間的關(guān)系

l  SurfaceFlinger對VSYNC信號的處理過程(重點(diǎn))

1.1.1 ProjectButter

直譯過來,就是“黃油計劃”,為什么叫這個名字呢?這個Project的目的是為了改善用戶抱怨最多的Android幾大缺陷之一,即UI響應(yīng)速度——Google希望這一新計劃可以讓Android系統(tǒng)擺脫UI交互上給人帶來的“滯后”感,而能像黃油一般“順滑”。Google在2012年的I/O大會上宣布了這一計劃,并在Android 4.1中正式搭載了實(shí)現(xiàn)機(jī)制。

Butter中有兩個重要的組成部分,即VSync和Triple Buffering。下面先分別介紹引入它們的原因。

喜歡玩游戲或者看電影的讀者可能遇到過這樣的情形:

  某些游戲場面好像是幾個場景“拼湊”而成的

  電影畫面不連貫,好像被“割裂”了

這樣子描述有點(diǎn)抽象,我們引用widipedia上的一張圖來看下實(shí)際的效果:


圖 11?20 Screen Tearing實(shí)例

引自http://en./wiki/File:Tearing_%28simulated%29.jpg

 

我們把這種顯示錯誤稱為“screentearing”,那么為什么會出現(xiàn)這樣的情況呢?

相信大家都能得出結(jié)論,那就是屏幕上顯示的畫面實(shí)際上來源于多個“幀”。

在一個典型的顯示系統(tǒng)中,frame buffer代表了屏幕即將要顯示的一幀畫面。假如CPU/GPU繪圖過程與屏幕刷新所使用的buffer是同一塊,那么當(dāng)它們的速度不同步的時候,是很可能出現(xiàn)類似的畫面“割裂”的。舉個具體的例子來說,假設(shè)顯示器的刷新率為66Hz,而CPU/GPU繪圖能力則達(dá)到100Hz,也就是它們處理完成一幀數(shù)據(jù)分別需要0.015秒和0.01秒。

以時間為橫坐標(biāo)來描述接下來會發(fā)生的事情,如下圖:


圖 11?21 Screen Tearing產(chǎn)生過程分析

 

上半部分的方框表示在不同的時間點(diǎn)時顯示屏的內(nèi)容(加深的部分),下半部分則是同一時間點(diǎn)時frame buffer中的數(shù)據(jù)狀態(tài),編號表示第幾個frame,不考慮清屏。

·          0.01秒

由于兩者速率相差不小,此時buffer中已經(jīng)準(zhǔn)備好了第1幀數(shù)據(jù),顯示器只顯示了第1幀畫面的2/3

·          0.015秒

第1幀畫面完整地顯示出來了,此時buffer中有1/3的部分已經(jīng)被填充上第2幀數(shù)據(jù)了

·          0.02秒

Buffer中已經(jīng)準(zhǔn)備好第2幀數(shù)據(jù),而顯示屏出現(xiàn)了screen tearing,有三分之一是第2幀內(nèi)容,其余的則屬于第1幀畫面

 

在單緩沖區(qū)的情況下,這個問題很難規(guī)避。所以之前我們介紹了雙緩沖技術(shù),基本原理就是采用兩塊buffer。一塊back buffer用于CPU/GPU后臺繪制,另一塊framebuffer則用于顯示,當(dāng)back buffer準(zhǔn)備就緒后,它們才進(jìn)行交換。不可否認(rèn),doublebuffering可以在很大程度上降低screen tearing錯誤,但是它是萬能的嗎?

一個需要考慮的問題是我們什么時候進(jìn)行兩個緩沖區(qū)的交換呢?假如是back buffer準(zhǔn)備完成一幀數(shù)據(jù)以后就進(jìn)行,那么如果此時屏幕還沒有完整顯示上一幀內(nèi)容的話,肯定是會出問題的。看來只能是等到屏幕處理完一幀數(shù)據(jù)后,才可以執(zhí)行這一操作了。

我們知道,一個典型的顯示器有兩個重要特性,行頻和場頻。行頻(Horizontal ScanningFrequency)又稱為“水平掃描頻率”,是屏幕每秒鐘從左至右掃描的次數(shù); 場頻(Vertical Scanning Frequency)也稱為“垂直掃描頻率”,是每秒鐘整個屏幕刷新的次數(shù)。由此也可以得出它們的關(guān)系:行頻=場頻*縱坐標(biāo)分辨率。

當(dāng)掃描完一個屏幕后,設(shè)備需要重新回到第一行以進(jìn)入下一次的循環(huán),此時有一段時間空隙,稱為VerticalBlanking Interval(VBI)。大家應(yīng)該能想到了,這個時間點(diǎn)就是我們進(jìn)行緩沖區(qū)交換的最佳時間。因?yàn)榇藭r屏幕沒有在刷新,也就避免了交換過程中出現(xiàn)screentearing的狀況。VSync(垂直同步)是VerticalSynchronization的簡寫,它利用VBI時期出現(xiàn)的vertical sync pulse來保證雙緩沖在最佳時間點(diǎn)才進(jìn)行交換。

所以說V-sync這個概念并不是Google首創(chuàng)的,它在早些年前的PC機(jī)領(lǐng)域就已經(jīng)出現(xiàn)了。不過Android 4.1給它賦予了新的功用,稍后就可以看到。

上面我們討論的情況基于的假設(shè)是繪圖速度大于顯示速度,那么如果反過來呢?


圖 11?22繪圖過程沒有采用VSync同步的情況

引用自Google2012 I/O,作者Chet Haase和Romain Guy,AndroidUI Toolkit Engineers

 

這個圖中有三個元素,Display是顯示屏幕,GPU和CPU負(fù)責(zé)渲染幀數(shù)據(jù),每個幀以方框表示,并以數(shù)字進(jìn)行編號,如0、1、2等等。VSync用于指導(dǎo)雙緩沖區(qū)的交換。

以時間的順序來看下將會發(fā)生的異常:

Step1. Display顯示第0幀數(shù)據(jù),此時CPU和GPU渲染第1幀畫面,而且趕在Display顯示下一幀前完成

Step2. 因?yàn)殇秩炯皶r,Display在第0幀顯示完成后,也就是第1個VSync后,正常顯示第1幀

Step3. 由于某些原因,比如CPU資源被占用,系統(tǒng)沒有及時地開始處理第2幀,直到第2個VSync快來前才開始處理

Step4. 第2個VSync來時,由于第2幀數(shù)據(jù)還沒有準(zhǔn)備就緒,顯示的還是第1幀。這種情況被Android開發(fā)組命名為“Jank”。

Step5. 當(dāng)?shù)?幀數(shù)據(jù)準(zhǔn)備完成后,它并不會馬上被顯示,而是要等待下一個VSync。

所以總的來說,就是屏幕平白無故地多顯示了一次第1幀。原因大家應(yīng)該都看到了,就是CPU沒有及時地開始著手處理第2幀的渲染工作,以致“延誤軍機(jī)”。 Android系統(tǒng)中一直存在著這個問題,即便是上一版本的Ice Cream Sandwich。

從Android 4.1Jelly Bean開始,VSync得到了進(jìn)一步的應(yīng)用。系統(tǒng)在收到VSync pulse后,將馬上開始下一幀的渲染。


圖 11?23 整個顯示系統(tǒng)都以VSync進(jìn)行同步

 

如上圖所示,一旦VSync出現(xiàn)后,CPU不再猶豫,緊接著就開始執(zhí)行buffer的準(zhǔn)備工作。大部分的Android顯示設(shè)備刷新率是60Hz,這也就意味著每一幀最多只能有1/60=16ms左右的準(zhǔn)備時間。假如CPU/GPU的FPS(FramesPer Second)高于這個值,那么這個方案是完美的,顯示效果將很好。

可是我們沒有辦法保證所有設(shè)備的硬件配置都能達(dá)到要求。假如CPU/GPU的性能無法滿足上圖的條件,又是什么情況呢?

在分析這一問題之前,我們先來看下正常情況下,采用雙緩沖區(qū)的系統(tǒng)的運(yùn)行情況。


圖 11?24 雙緩沖展示

 

這個圖采用了雙緩沖,以及前面介紹的VSync,可以看到整個過程還是相當(dāng)不錯的,雖然CPU/GPU處理所用的時間時短時長,但總的來說都在16ms以內(nèi),因而不影響顯示效果。A和B分別代表兩個緩沖區(qū),它們不斷地交換來正確顯示畫面。

現(xiàn)在我們可以繼續(xù)分析FPS低于屏幕刷新率的情況。

如下圖所示:


 

圖 11?25 FPS低于屏幕刷新率的情況

 

當(dāng)CPU/GPU的處理時間超過16ms時,第一個VSync到來時,緩沖區(qū)B中的數(shù)據(jù)還沒有準(zhǔn)備好,于是只能繼續(xù)顯示之前A緩沖區(qū)中的內(nèi)容。而B完成后,又因?yàn)槿狈Sync pulse信號,它只能等待下一個signal的來臨。于是在這一過程中,有一大段時間是被浪費(fèi)的。當(dāng)下一個VSync出現(xiàn)時,CPU/GPU馬上執(zhí)行操作,此時它可操作的buffer是A,相應(yīng)的顯示屏對應(yīng)的就是B。這時看起來就是正常的。只不過由于執(zhí)行時間仍然超過16ms,導(dǎo)致下一次應(yīng)該執(zhí)行的緩沖區(qū)交換又被推遲了——如此循環(huán)反復(fù),便出現(xiàn)了越來越多的“Jank”。

那么有沒有規(guī)避的辦法呢?

很顯然,第一次的Jank看起來是沒有辦法的,除非升級硬件配置來加快FPS。我們關(guān)注的重點(diǎn)是被CPU/GPU浪費(fèi)的時間段,怎么才能充分利用起來呢?分析上述的過程,造成CPU/GPU無事可做的假象是因?yàn)楫?dāng)前已經(jīng)沒有可用的buffer了。換句話說,如果增加一個buffer,情況會不會好轉(zhuǎn)呢?


圖 11?26 Triple Buffering

 

Triple Buffering是MultipleBuffering的一種,指的是系統(tǒng)使用3個緩沖區(qū)用于顯示工作。我們來逐步分析下這個新機(jī)制是否有效。首先和預(yù)料中的一致,第一次“Jank”無可厚非。不過讓人欣慰的是,當(dāng)?shù)谝淮蜼Sync發(fā)生后,CPU不用再等待了,它會使用第三個buffer C來進(jìn)行下一幀數(shù)據(jù)的準(zhǔn)備工作。雖然對緩沖區(qū)C的處理所需時間同樣超過了16ms,但這并不影響顯示屏——第2次VSync到來后,它選擇buffer B進(jìn)行顯示;而第3次VSync時,它會接著采用C,而不是像double buffering中所看到的情況一樣只能再顯示一遍B了。這樣子就有效地降低了系統(tǒng)顯示錯誤的機(jī)率。

前面小節(jié)我們看到BufferQueue中最多有32個BufferSlot,不過在實(shí)際使用時具體值是可以設(shè)置的。

·          TARGET_DISABLE_TRIPLE_BUFFERING

這個宏用于disable triple buffering。如果宏打開的話,Layer.cpp在onFirstRef有如下操作:

#ifdefTARGET_DISABLE_TRIPLE_BUFFERING

#warning"disabling triple buffering"

   mSurfaceTexture->setBufferCountServer(2);

#else

   mSurfaceTexture->setBufferCountServer(3);

#endif

 

也就是將mSurfaceTexture(即BufferQueue)中的mServerBufferCount設(shè)為2,否則就是3

 

·          對于應(yīng)用程序來說,它也可以通過ISurfaceTexture::setBufferCount來告訴BufferQueue它希望的Slot值,對應(yīng)的則是mClientBufferCount。默認(rèn)情況下這個變量是0,表示應(yīng)用端不關(guān)心到底有多少buffer可用。

 

·          BufferQueue中還有另一個變量mBufferCount,默認(rèn)值是MIN_ASYNC_BUFFER_SLOTS。在具體的實(shí)現(xiàn)中,以上這三個變量都是要考慮到的,BufferQueue會通過權(quán)衡各個值來選擇最佳的解決方式

 

請大家務(wù)必理解本小節(jié)的幾個場景分析,明白采用TripleBuffering、VSync機(jī)制的原因。帶著這些理解進(jìn)入SurfaceFlinger的學(xué)習(xí),可以幫助我們“有的放矢”,對源碼的分析也能事半功倍。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多