天天看點

初識Android Project Butter: 黃油項目,使動畫更加的平滑、流暢

原文位址:http://www.androidpolice.com/2012/07/12/getting-to-know-android-4-1-part-3-project-butter-how-it-works-and-what-it-added/ VSYNC将幀繪制轉入一個平滑的機制之中        PC遊戲玩家應該對‘VSync’這個術語十分的熟悉。VSync是一個圖形選項框,這個圖形選項框可以阻止一個視訊遊戲中的螢幕被撕裂(停頓)。         為了正确的了解‘VSync’究竟是什麼,我們将需要一種靈活新手教學:視訊是由一系列獨特的,我們稱之為‘幀’,圖檔組成。通常而言,一個光滑的動畫每秒會有播放60個幀。一張幀(圖檔)又由許多像素點組成,當繪制一張幀的時候,像素點被一行一行的填充。        顯示屏(液晶顯示器?主動矩陣有機發光二極體面闆?無所謂)從顯示卡中擷取每一幀,并逐行繪制此幀。理想情況下,顯示屏在完成上一幀的繪制後,你期望顯示屏能從顯示卡中擷取新的一幀。然而實際情況卻是,在顯示屏的中央位置在加載一個新的幀圖檔時,一個撕裂(停頓)發生了,是以你将看到上一幀的一半内容以及新的幀的一半内容。        VSync則是同步這種情況的存在。它将告訴顯示卡,在顯示卡導入新的一張幀圖檔之前,需要等待螢幕完成它的逐行繪制。        Android總會使用VSync來阻止螢幕撕裂(停頓),但是android4.1卻讓這件事更進一步。VSync脈沖,被用來開始下一幀的所有處理。        絕大部分Android顯示屏一秒鐘都将運作大約60張幀圖檔。事實上,為了有一個平滑的動畫,你不得不以每秒60張幀圖檔的速率來處理動畫——這意味着你将隻有16毫秒的時間來處理每一張幀圖檔。如果你花費的時間多餘了16毫秒,動畫将有種結巴的感覺,而我們讓動畫像黃油一樣平滑起來的這個目标,将煙消雲散。        16毫秒不是一個很長的時間,是以需要充分利用。在android4.0中,處理下一幀就有點懶洋洋的感覺,當系統開始着手去做這件事情時。而在android4.1中,上一幀一結束(VSync脈沖一開始),制造下一幀的總體流程就開始了。換而言之,它們将盡可能的使用少于16毫秒的時間來處理一張幀圖檔。       沒有VSync的情況下,進行的處理:

初識Android Project Butter: 黃油項目,使動畫更加的平滑、流暢

        此圖就是在關掉VSync一切的情況下,繪制的生命周期。首先幀圖檔被CPU和GPU(顯示卡)處理,當這個過程結束後,在下一個VSync開始時,幀圖檔就會被傳遞給顯示屏。是以在此圖之中,第0張幀圖檔被展示了,在其被展示的16毫秒期間,CPU和GPU準備第1張幀圖檔。經過一段時間,計算完成,并在下一個VSync脈沖時,CPU和GPU将準備好的第一張幀圖檔交出。        至此我們将第一張幀圖檔顯示出來了,并且應該開始第二張幀圖檔的工作了。即使會因為某些原因使得系統被減緩了,然而對下一張幀圖檔的處理并不會馬上開始,直到我們很好的進入了16毫秒的時間限制。對應到此張圖而言,CPU和GPU開始處理第二張幀圖檔時,系統大概隻有4毫秒(第一個VSync與第二個VSync之間大約最後一個四分之一的地方)的時間來計算第二張幀圖檔,是以針對第二張幀圖檔的處理并不能及時的完成。因為第二張幀圖檔還未計算完成,是以顯示屏會強制要求再顯示一次第一張幀圖檔(即上圖示示有Jank字樣的那一段16毫秒),android團隊稱之為閃避,意思是在這期間發生的動畫不流暢,使用者将有一種很結巴的感覺。        擁有VSync的情況下,進行的處理:

初識Android Project Butter: 黃油項目,使動畫更加的平滑、流暢

             在android4.1中,有一個新的方式來處理這個流程。是以對下一張幀圖檔的處理都将在一個VSync脈沖發出時開始,是以現在你需要充分利用這段用來渲染的16毫秒時間。對幀圖檔的處理已經從“是的,我們可以随時啟動它”向一種嚴格的排班、高度組織化的事件轉變。在此圖中,所有的處理過程都發生在16毫秒這個限制時間之中,所有的幀圖檔都會按時傳遞,作為結果你将有一個類似于黃油般平滑的體驗。

三緩存,用來阻止像雪球一樣越來越多的閃避

       VSync并不是唯一的一種用來幫助動畫更加平滑化的方法;android也能夠更加平滑的從一個緩慢中恢複。         兩緩存并行處理的模式:

初識Android Project Butter: 黃油項目,使動畫更加的平滑、流暢

          那麼到底什麼是一個“緩存(Buffer)”呢?簡單而言,一個緩存就是一張幀圖檔在其中建立并存儲其中的容器。上文我們通過數字來提及幀圖檔(例如第0張幀圖檔、第1張幀圖檔……),但是實際上,android使用了一個雙緩(容器)存機制,一個非常典型的設計,這個機制意味着當一個幀圖檔被展示的時候,另一張幀視圖正在被處理;此外,這兩個緩存中分别對應一張幀圖檔,上文提及的每一張幀圖檔都是這兩者之一。此圖中,兩個緩存被标記為A和B。當展示A容器中的幀圖檔時,系統将在B容器中建立一張新的幀圖檔。當新幀圖檔被建立完畢後,兩者進行交換。B容器中的幀圖檔将被顯示,而A容器中的幀圖檔将被情況并且一張新的幀圖檔将被處理。        當你繪制幀圖檔的時間超過了16毫秒,則雙緩存潛在的問題就發生了。如下圖所示:       

初識Android Project Butter: 黃油項目,使動畫更加的平滑、流暢

        B容器像這樣運作,則一個閃避發生了。雖說閃避也是不好的,但是這張圖所反映的真正問題卻是CPU與GPU存在大量被浪費的時間(圖中CPU與GPU存在大量空白區域,空白區域表示CPU與GPU沒有東西可以處理)。在第一個幀時(一幀時等于16毫秒)中,B緩存的處理逾時,在B緩存被展示出來之前,它一直處于使用中,A緩存也處于使用中,因為A緩存中的幀視圖被展示了2個幀時(一幀時等于16毫秒),之是以要展示2個幀時的原因,是因為android隻會在一幀時結束,下一幀時開始的時候切換緩存。 CPU和GPU受限于可以使用的緩存數,不得不消極怠工(産生空白區域),進而使得系統,一步慢步步慢,這就是android4.0的缺陷。         在android4.1中,通過引入第三個緩存,來解決上文中所提及的雙緩存機制中潛在的問題。如下圖所示:      

初識Android Project Butter: 黃油項目,使動畫更加的平滑、流暢

          與雙緩沖機制中的過程一樣,B緩存将花費太多的時間;然而與雙緩存機制中浪費CPU與GPU時間不一樣的是,這段被浪費的時間,被用來建立了C緩存(第三個緩存),并且這個緩存會立即作用于一張新的幀圖檔。三緩存機制阻止了閃避情況的産生,經過最初的閃避後,将會為使用者展示出一段平滑的動畫。 即便有些問題發生了,但系統還會努力給使用者滿意的結果。       那麼為什麼系統不一直采用三緩存機制呢?正如上圖所示,三緩存機制向處理過程中引入了一點輸入延遲。例如,在渲染C緩存(上圖藍/綠部分)和展示C緩存之間。 是以,當出現某些錯誤行為時,你有兩個選項: 輸入延遲(你的觸摸操作生效時間會延長)或者畫面卡頓。      為了解決這個問題,android4.1并沒有一直執行三緩存機制。一般而言,它會正常的執行雙緩存機制,而第三個緩存将會出現在任何它應該出現的位置。通過這種方式,你将得到一個更少的輸入延遲,而當有不好的事情發生時,你又能通過第三個緩存來恢複系統。