Android 顯示刷新機制、VSYNC和三重緩存機制

和你一起終身學習,這裏是程序員 Android

經典好文推薦,通過閱讀本文,您將收穫以下知識點:

一、刷新率與幀率
二、Google 的優化
三、Triple Buffer三重緩存機制
四、總結

一、刷新率與幀率

爲了理解 APP 是如何進行渲染的,我們就必須瞭解手機硬件是如何工作的,也必須理解什麼是 VSYNC。

首先,我們需要了解2個相關概念:

1. 刷新率(Refresh Rate):

代表了屏幕在一秒內刷新屏幕的次數,這取決於硬件的固定參數,例如 60Hz。

2. 幀率(Frame Rate)

代表了 GPU 在一秒內繪製操作的幀數,例如 30fps,60fps。
GPU 會獲取圖形數據進行渲染,然後硬件負責把渲染後的內容呈現到屏幕上,他們兩者不停的進行協作。


如果刷新率和幀率,各自做自己的事,不相互協調工作,那麼刷新頻率和幀率並不總能夠保持相同的節奏。如果發生幀率與刷新頻率不一致的情況,就會容易出現畫面撕裂(Tearing)的現象,也就是畫面上下兩部分顯示內容發生斷裂,來自不同的兩幀數據發生重疊。



爲了解決 Tearing 問題,Android 引入了 VSYNC 信號以及雙重與三重緩存機制。

二、Google 的優化

從 Android 4.1 開始,谷歌致力於解決 Android 系統中最飽受詬病的一個問題,滑動不如 iOS 流暢。因谷歌在 4.1 版本引入了一個重大的改進—Project Butter,也即是黃油計劃。

Project Butter 對 Android Display 系統進行了重構,引入了三個核心元素,即 VSYNC、Triple Buffer 和 Choreographer。Choreographer 在之前的文章《從源碼分析Choreographer是如何實現VSYNC信號的請求及幀的刷新處理?(Android Q)》中已經分析過了,三重緩存機制我們後面介紹,這裏我們重點講解 VSYNC 的作用。

VSYNC(Vertical Synchronization)是一個相當古老的概念,對於遊戲玩家,它有一個更加大名鼎鼎的中文名字—-垂直同步。垂直同步(vsync)指的是顯卡的輸出幀數和屏幕的垂直刷新率相同。在當下,垂直同步的含義我們可以理解爲,使得顯卡生成幀的速度和屏幕刷新的速度的保持一致。舉例來說,如果屏幕的刷新率爲 60Hz,那麼生成幀的速度就應該被固定在 16ms。

上文中,我們已經知道了什麼事畫面撕裂(Tearing)現象以及它產生的原因,而 VSYNC 最重要的作用是防止出現畫面撕裂。

VSYNC 信號是由屏幕(顯示設備)產生的,並且以 60fps 的固定頻率發送給 Android 系統,Android 系統中的 SurfaceFlinger 接收發送的 VSYNC 信號。VSYNC 信號表明可對屏幕進行刷新而不會產生撕裂。當 SurfaceFlinger 接收到 VSYNC 信號後,SurfaceFlinger 會遍歷其層列表,以查找新的緩衝區。如果 SurfaceFlinger 找到新的緩衝區,SurfaceFlinger 會獲取緩衝區;否則,SurfaceFlinger 會繼續使用上一次獲取的那個緩衝區。SurfaceFlinger 必須始終顯示內容,因此它會保留一個緩衝區。如果在某個層上沒有提交緩衝區,則該層會被忽略。

通常來說,幀率超過刷新頻率只是一種理想的狀況,在超過 60fps 的情況下,GPU 所產生的幀數據會因爲等待 VSYNC 的刷新信息而被 Hold 住,這樣能夠保持每次刷新都有實際的新的數據可以顯示。但是我們遇到更多的情況是幀率小於刷新頻率。

在這種情況下,某些幀顯示的畫面內容就會與上一幀的畫面相同。糟糕的事情是,幀率從超過 60fps 突然掉到 60fps 以下,這樣就會發生 LAG,JANK,HITCHING 等卡頓掉幀的不順滑的情況。這也是用戶感受不好的原因所在。

接下來,我們以具體示例來看 VSYNC 的作用。

1. 沒有使用 VSYNC 時

我們來看沒有 VSYNC 的情況:

這個圖中有三個元素,Display 是顯示屏幕,GPU 和 CPU 負責渲染幀數據,每個幀以方框表示,並以數字進行編號,如0、1、2等等。

CPU 正常執行幀1,GPU 正常渲染幀1,所以幀1正常顯示。
但,CPU 由於被佔用等原因,等到即將顯示幀2時,它纔開始處理第二幀的內容,這顯然完不成了,所以等到第二幀顯示的時候,只能使用上一幀的內容顯示了,也即是丟幀了。
上面丟幀的原因,我們可以從圖中看出,是因爲新的一幀開始的時候,CPU 在處理其他任務,並沒有馬上執行下一幀的任務,那麼如何讓 CPU 在新的一幀開始的時候立即處理顯示內容呢?答案就在 VSYNC 身上!

2.使用 VSYNC 信號

我們來看,Android 引入 VSYNC 之後的幀執行示意圖:

第0幀顯示時,CPU 和 GPU 準備好了第一幀的內容。
第1幀剛開始顯示時,CPU 放下手中的任務,立馬處理第2幀顯示相關的任務(這裏使用了消息屏障機制,可以參考前文《Android消息循環的同步屏障機制及UI渲染性能的提升(Android Q)》),這樣,在第二幀顯示之前, CPU 和 GPU 也提前完成了顯示任務的處理,第二幀正常顯示。
可以看到,使用 VSYNC 信號機制,提升了渲染任務的優先級,優化了渲染性能,可有效的減少了丟幀、卡頓等問題。

但是上圖中仍然存在一個問題:CPU 和 GPU 處理數據的速度似乎都能在 16ms 內完成,而且還有時間空餘,也就是說,CPU 和 GPU 的幀率要高於 Display 的幀率。由於 CPU/GPU 只在收到 VSYNC 時纔開始數據處理,故它們的幀率被拉低到與 Display 相同。但這種處理並沒有什麼問題,因爲 Android 設備的 Display FPS 一般是 60,其對應的顯示效果非常平滑。

但如果 CPU/GPU 的幀率小於 Display 的幀率,情況又不同了,將會發生如下圖的情況:


在第二個 16ms 時間段,Display 本應顯示 B 幀,但卻因爲 GPU 還在處理 B 幀,導致 A 幀被重複顯示。
同理,在第二個 16ms 時間段內,CPU 無所事事,因爲 A Buffer 被 Display 在使用。B Buffer 被 GPU 在使用。注意,一旦過了 VSYNC 時間點,CPU 就不能被觸發以處理繪製工作了。

以上是使用雙重緩存機制時產生的問題,那麼又如何來解決呢?

爲了解決這個問題,Android 引入了 Triple Buffer 機制。

三、Triple Buffer三重緩存機制

一般我們在繪製 UI 的時候,都會採用一種稱爲“雙緩存”的技術(例如,上面幾個例子)。雙緩存意味着要使用兩個緩存區,其中一個稱爲 Front Buffer,另外一個稱爲 Back Buffer。UI 總是先在 Back Buffer 中繪製,然後再和 Front Buffer 交換,渲染到顯示設備中。理想情況下,這樣一個刷新會在 16ms 內完成,下圖就是描述的這樣一個刷新過程:Display 處理前 Front Buffer,CPU、GPU 處理 Back Buffer。

只有兩個 Buffer(Android 4.1之前)時,CPU 在空閒時,如果 Back Buffer 被佔用了,它也只能等待 GPU 使用之後再次進行寫入。我們可以想想,如果有第三個 Buffer 的存在,CPU 是不是就可以提前工作,而不至於空閒了?所以,Google 在 Android4.1 以後,引入了三重緩存機制:Tripple Buffer。Tripple Buffer 利用 CPU/GPU 的空閒等待時間提前準備好數據,並不一定會使用。

引入 Triple Buffer 效果如下圖所示:


上圖中,第二個 16ms 時間段,CPU 使用 C Buffer 繪圖。雖然還是會多顯示 A 幀一次,但後續顯示就比較順暢了。

那麼,是不是 Buffer 越多越好呢?回答是否定的。由上圖可知,在第二個時間段內,CPU 繪製的第 C 幀數據要到第四個 16ms 才能顯示,這比雙 Buffer 情況多了 16ms 延遲,並且大量的緩存數據也會導致內存增大,以及顯示數據是否失效等問題。所以,Buffer 三個足矣。

四、總結

刷新率(Refresh Rate):代表了屏幕在一秒內刷新屏幕的次數,這取決於硬件的固定參數,例如 60Hz。

幀率(Frame Rate):代表了 GPU 在一秒內繪製操作的幀數,例如 30fps,60fps。

GPU 會獲取圖形數據進行渲染,然後硬件負責把渲染後的內容呈現到屏幕上,他們兩者不停的進行協作。

如果刷新率和幀率,各自做自己的事,不相互協調工作,那麼刷新頻率和幀率並不總能夠保持相同的節奏。如果發生幀率與刷新頻率不一致的情況,就會容易出現畫面撕裂(Tearing)的現象。

從 Android 4.1 開始,谷歌在黃油計劃中,引入了了三個核心元素,即 VSYNC、Triple Buffer 和 Choreographer。

VSYNC 信號是由屏幕(顯示設備)產生的,並且以 60fps 的固定頻率發送給 Android 系統,Android 系統中的 SurfaceFlinger 接收發送的 VSYNC 信號。VSYNC 信號表明可對屏幕進行刷新而不會產生撕裂。

使用 VSYNC 信號機制,提升了渲染任務的優先級,優化了渲染性能,可有效的減少了丟幀、卡頓等問題。

三重緩存機制(Triple Buffer) 利用 CPU/GPU 的空閒等待時間提前準備好數據,有效的提升了渲染性能。

原文鏈接:https://blog.csdn.net/u011578734/article/details/110921266

至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點擊閱讀原文,支持原創作者,如有侵權,懇請聯繫小編刪除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章