【Android】從垂直同步到屏幕刷新機制
本文參考以及部分圖片來源:
垂直同步_小科普:“垂直同步”究竟是什么?-CSDN博客
“終于懂了” 系列:Android屏幕刷新機制—VSync、Choreographer 全面理解!-騰訊云開發者社區-騰訊云(這篇博客超級詳細)
打瓦的時候圖像設置這么多,經常在網上看到有提升畫面流暢度的設置參考/最佳性能設置參考等等。
抄襲網絡上各路大佬的設置配置,但是并不理解為什么開關某些設置會對畫面造成這么大的影響。今天就從最常見的垂直同步說起,講講屏幕刷新機制。
什么是幀?什么是幀率?什么是刷新率?
首先來解釋一些基礎概念。
1. 幀(Frame)
幀就是一張靜態畫面,類似翻頁動畫書中的一頁紙。視頻、游戲中的動態效果,本質上是通過快速連續播放多幀畫面實現的。
關鍵點:
- 每一幀包含當前時刻畫面的完整信息(比如角色位置、顏色等)。
- 人眼的視覺暫留效應(約0.1秒)讓連續幀看起來是連貫的動作。
- 舉例:電影通常每秒播放24幀,游戲可能每秒生成60幀甚至更多。
2. 幀率(Frame Rate / FPS)
每秒生成的幀數,單位是 FPS(Frames Per Second),由內容源(如游戲、視頻)決定。
表示 GPU 在一秒內繪制操作的幀數,單位 fps。例如在電影界采用 24 幀的速度足夠使畫面運行的非常流暢。而 Android 系統則采用更加流程的 60 fps,即每秒鐘GPU最多繪制 60 幀畫面。幀率是動態變化的,例如當畫面靜止時,GPU 是沒有繪制操作的,屏幕刷新的還是buffer中的數據,即GPU最后操作的幀數據。
3. 刷新率(Refresh Rate)
顯示器每秒刷新畫面的次數,單位是 Hz(赫茲),由顯示器硬件決定。
- 例如:60Hz顯示器每秒刷新60次,144Hz則刷新144次。
- 每次刷新時,顯示器從顯卡獲取最新幀并顯示。
關鍵點:
- 刷新率是顯示器的“物理上限”。
- 舉例:即使游戲生成100FPS,60Hz顯示器也只能每秒顯示60幀,多余幀會被丟棄或導致畫面撕裂。
畫面撕裂與掉幀
剛剛圖片帖子中貼主提到,在調整完設置之后,不會有畫面撕裂和掉幀的現象了。這兩個詞匯我們平時經常提到,不妨思考兩個問題:
掉幀,是說 這一幀延遲顯示 還是 丟棄不再顯示 ?為什么?
顯示器為什么會出現畫面撕裂的問題?為什么兩個幀會同時顯示在屏幕上?
帶著這個問題我們來探尋一下,首先依然是給出結論。
1. 畫面撕裂(Screen Tearing)
是什么?
顯示器在刷新過程中,同時顯示了多個幀的部分內容,導致畫面被“撕裂”成上下兩部分或多塊不一致的圖像(如下圖)。
為什么發生?
- 幀率(FPS) ≠ 刷新率(Hz):當顯卡輸出幀的速度(FPS)與顯示器刷新率不同步時,顯示器可能在一次刷新中途切換到新幀,導致新舊幀混雜。
- 舉例:顯卡每秒生成100幀(100FPS),顯示器是60Hz。顯卡生成幀的速度遠快于顯示器刷新,顯示器在刷新到一半時可能突然收到新幀,導致畫面撕裂。
如何解決?
- 開啟垂直同步(V-Sync):強制顯卡等待顯示器刷新完成再輸出新幀。
- 使用自適應同步技術(如G-Sync/FreeSync):讓顯示器動態調整刷新率,匹配顯卡輸出的幀率。
- 限制幀率:手動將游戲幀率限制在顯示器刷新率以內(如60FPS配60Hz顯示器)。
2. 掉幀(Frame Drops)
是什么?
內容源(如游戲、視頻)實際生成的幀數低于預期幀率,導致畫面卡頓、不連貫。例如:
- 游戲標稱60FPS,但因性能不足,實際只能生成40FPS → 每秒少了20幀,動作變得卡頓。
- 視頻播放時因解碼或帶寬問題,部分幀未能及時加載 → 畫面突然“跳幀”。
為什么發生?
- 硬件性能不足:顯卡/CPU無法及時渲染足夠幀(常見于高畫質游戲或復雜場景)。
- 軟件優化差:程序代碼效率低,導致幀生成不穩定。
- 外部干擾:網絡延遲(在線視頻/直播)、硬盤讀取速度慢(加載貼圖卡頓)等。
寫到這里我們基本上了解了,畫面撕裂是由于多個幀的內容被同時顯示在屏幕上,而掉幀是實際生成的幀數低于預期幀率。而垂直同步可以強制顯卡等待顯示器刷新完成再輸出新幀,從而幫助我們解決畫面撕裂的問題,但可能導致掉幀的問題。
但是開頭的兩個問題仍未得到解決,并且我們依舊沒有真正了解垂直同步和畫面撕裂的內部原因。或許我們需要更加深入地學習一下顯示系統的基礎知識。
顯示系統基礎知識
基礎架構與組件角色
- CPU:負責生成幀的邏輯數據。處理內容包括應用狀態(如游戲角色坐標、UI控件位置)、物理計算、動畫邏輯等。輸出為圖形渲染所需的非像素化數據(如頂點坐標、紋理坐標、材質屬性)。
- GPU:接收CPU傳遞的圖形數據,通過渲染管線(頂點著色→光柵化→像素著色)生成最終像素圖像,寫入圖形緩沖區(Graphic Buffer)。渲染速度取決于著色復雜度(如光照、抗鋸齒、分辨率)。
- 顯示器:以固定刷新率(如60Hz)從緩沖區讀取像素數據,通過逐行掃描將圖像顯示到屏幕。每次刷新周期包含有效掃描期(Active)和垂直空白期(VBlank)。
逐行掃描
定義:逐行掃描指顯示器從上到下、從左到右依次繪制每一行像素,完整顯示一幀畫面后,再開始下一幀的掃描。
關鍵特征:
- 順序性:每一幀的所有行(如1080p的1920×1080=2073600行)按物理順序連續掃描。
- 完整性:每次刷新周期(如16.67ms@60Hz)內,屏幕顯示完整的單一幀畫面。
- 同步信號:依賴**水平同步(HSync)和垂直同步(VSync)**信號控制掃描節奏。
單緩存
早期的顯示系統采用單緩存模式(Single Buffering),即僅使用一個緩沖區(Frame Buffer)供GPU寫入渲染數據,同時顯示器從中讀取數據刷新屏幕。這種設計雖然簡單,但存在以下核心問題:
畫面撕裂(Screen Tearing)
顯示器在逐行掃描過程中,若GPU在屏幕刷新中途更新緩沖區數據,會導致屏幕上半部分顯示舊幀、下半部分顯示新幀,畫面被“撕裂”為不連貫的兩部分。這主要是因為GPU和顯示器異步訪問同一緩沖區,缺乏同步機制。顯示器無法感知GPU寫入時機,可能讀取到部分更新的幀。
示例:假設顯示器以60Hz刷新(16.6ms/幀),GPU每10ms渲染一幀:
- T=0ms:顯示器開始掃描第N幀。
- T=8ms:GPU完成第N+1幀并寫入緩沖區。
- T=8~16.6ms:顯示器繼續掃描,下半部分顯示第N+1幀,上半部分仍為第N幀,畫面撕裂。
讀寫沖突(Read-Write Contention)
GPU和顯示器同時訪問同一緩沖區時,可能導致數據損壞或需要復雜的鎖機制,降低系統效率。
- GPU寫入速度與顯示器讀取速度不匹配(如GPU寫入速度遠快于顯示器刷新速度)。
- 單緩存無讀寫分離機制,硬件需頻繁仲裁緩沖區訪問權。
雙緩存
為克服單緩存缺陷,現代顯示系統引入**雙緩存(Double Buffering)和垂直同步(VSync)**機制:
雙緩存結構:
- Front Buffer:僅用于顯示器讀取(當前顯示幀)。
- Back Buffer:僅用于GPU寫入(下一渲染幀)。
- 緩沖區交換:在顯示器垂直空白期(VBlank)交換兩者內存地址(非數據拷貝)。
VSync同步:
- 顯示器在VBlank期間發送同步信號,強制GPU在此時完成緩沖區交換。
- 確保顯示器每次刷新都讀取完整幀,消除撕裂與讀寫沖突。
雙緩存結構
雙緩存的核心思想是通過兩個獨立的緩沖區實現渲染與顯示的物理隔離。**Front Buffer(前緩沖區)專門用于顯示器逐行掃描輸出當前幀,而Back Buffer(后緩沖區)**則留給GPU自由寫入下一幀的渲染數據。
這兩個緩沖區各司其職——顯示器在刷新周期內持續從前緩沖區讀取像素,而GPU無需等待顯示器的進度,可以全速向后緩沖區填充新幀。這種分離徹底避免了單緩存模式下讀寫沖突的問題,GPU和顯示器不再爭奪同一塊內存的訪問權,數據損壞和鎖競爭的風險也隨之消失。
垂直同步
然而,雙緩存本身并不能完全解決畫面撕裂。如果緩沖區交換的時機不當,顯示器仍可能掃描到部分更新的幀。此時,垂直同步(VSync)便成為關鍵的同步機制。其工作原理基于顯示器硬件的物理特性:每一幀掃描完成后,顯示器會從屏幕右下角回到左上角,開始下一幀的掃描,這段短暫的返回時間稱為垂直空白期(VBlank)。
VSync信號正是由顯示器在VBlank開始時發出的一個脈沖,它像交通信號燈一樣,強制GPU在此時間窗口內完成緩沖區的交換。具體來說,當VSync信號觸發時,系統會將Front Buffer和Back Buffer的內存地址瞬間互換(而非拷貝數據),確保顯示器下一幀掃描的始終是完整的、已渲染好的圖像。這種同步機制從根本上消除了畫面撕裂的可能,因為顯示器每次刷新都從全新的完整幀開始,新舊幀的切換被嚴格限制在屏幕無輸出的“安全期”內。
雙緩存帶來的問題
盡管雙緩存+VSync的組合解決了撕裂問題,但也引入了新的挑戰。**輸入延遲(Input Lag)**是其中最顯著的影響——由于GPU必須等待VSync信號才能開始渲染下一幀,玩家的操作(如點擊鼠標或觸摸屏幕)需要多等待一個刷新周期(如16.6ms@60Hz)才能反映到畫面上,這對競技類游戲或實時交互場景是致命的。
另一個問題是幀率鎖死:若GPU無法在下一個VSync信號到來前完成渲染(例如復雜場景下渲染耗時超過16.6ms),顯示器只能重復顯示上一幀,導致幀率驟降(如60Hz→30Hz),形成卡頓(Jank)。這種“全有或全無”的機制使得性能波動被放大,幀率只能以刷新率的整數倍(1/2、1/3)跌落,用戶體驗呈現明顯的階梯式劣化。
借用“終于懂了” 系列:Android屏幕刷新機制—VSync、Choreographer 全面理解!-騰訊云開發者社區-騰訊云博客中的圖。
在第三幀時,GPU未完成計算,故而發生了重復顯示,只能將第二幀顯示兩次,而后等到下一次VSync再顯示。
輸入延遲
在雙緩存+VSync的架構下,輸入延遲的累積源自同步機制對渲染管線的強制阻塞。具體流程如下:
- 操作觸發:玩家點擊鼠標或觸摸屏幕(T=0ms)。
- CPU處理:游戲引擎接收到輸入事件,更新角色位置或射擊邏輯(耗時1ms)。
- GPU渲染:根據新數據生成下一幀(耗時10ms),但渲染完成時(T=11ms),若距離下一個VSync信號(T=16.6ms)還有5.6ms,GPU必須等待。
- 緩沖區交換:直到T=16.6ms(VSync觸發),新幀才被提交至顯示器。
- 顯示延遲:顯示器從T=16.6ms開始掃描,到T+16.6ms=33.2ms完成顯示。
總延遲:從操作觸發到畫面反饋需33.2ms(操作1ms + 渲染10ms + 等待5.6ms + 顯示16.6ms)。
- 對比無VSync:若關閉VSync,GPU完成渲染后立即交換緩沖區,延遲可降至27.6ms(操作1ms + 渲染10ms + 顯示16.6ms)。
下次打瓦的時候輸了就可以說自己不小心把垂直同步打開了,導致機器反應慢了(
幀率鎖死
當GPU渲染速度無法匹配顯示器刷新率時,VSync的“全有或全無”規則導致幀率呈離散式下降:
案例:60Hz顯示器 + GPU渲染耗時20ms/幀
- VSync 1(T=0ms):GPU開始渲染第1幀至Back Buffer。
- VSync 2(T=16.6ms):第1幀未完成(僅渲染16.6ms),無法交換緩沖區,顯示器繼續顯示舊幀(第0幀)。
- T=20ms:GPU完成第1幀,但需等待至VSync 3(T=33.3ms)才能交換。
- VSync 3(T=33.3ms):顯示第1幀,GPU開始渲染第2幀。
- VSync 4(T=50ms):第2幀耗時20ms,同樣未完成,顯示器重復顯示第1幀。
結果:實際幀率降至30Hz(1幀/33.3ms),而非理論上的50Hz(1000ms/20ms=50FPS)。幀率被強制對齊到刷新率的分數倍(60/2=30Hz、60/3=20Hz等),形成“階梯式卡頓”。
三緩存
雙緩存與垂直同步(VSync)這一設計通過物理隔離的緩沖區與精準的時序控制,確實解決了撕裂問題,卻也帶來了輸入延遲與幀率鎖死的新挑戰。
為了突破這些限制,現代技術轉向了更靈活的協同機制,其中最具代表性的便是三緩存(Triple Buffering)與自適應同步(G-Sync/FreeSync)。
依然借用一下這張圖。
三緩存在雙緩存的Front Buffer和Back Buffer基礎上,增加一個備用緩沖區(Extra Back Buffer),形成三個緩沖區的環形隊列。其核心邏輯是允許GPU在等待VSync期間繼續渲染后續幀,而非強制空閑。
優勢
減少連續卡頓:單幀超時不會阻塞后續幀的渲染,避免Jank鏈式反應。
硬件利用率提升:GPU在等待VSync期間可繼續工作,算力浪費減少。
代價
內存占用增加:1080p@32位色深下,單緩沖區需8MB,三緩存額外消耗8MB。
潛在延遲增加:幀可能多等待一個VSync周期顯示(如第1幀在33.3ms而非16.6ms顯示)。
自適應同步
自適應同步的核心思想是讓顯示器的刷新率實時匹配GPU的輸出幀率。這一過程依賴三個關鍵技術組件:
- 可變刷新率顯示器:硬件支持刷新率在特定范圍內連續變化(如FreeSync的30-144Hz、G-Sync的1-240Hz)。
- 同步控制器:集成于顯示器或顯卡中的芯片,負責監測GPU的幀提交狀態,并動態調整顯示器的時序信號。
- 通信協議:通過DisplayPort或HDMI接口傳遞同步信號,確保GPU與顯示器的指令實時互通。
當GPU完成一幀渲染時,同步控制器立即通知顯示器:“這一幀已就緒,現在開始掃描!”顯示器隨即啟動逐行刷新,并在掃描完成后立即準備接收下一幀,而非等待固定的VSync周期。例如,若GPU以45FPS的速度渲染,顯示器會將刷新率精準調整為45Hz,每22.2ms刷新一次;若GPU突然加速到90FPS,顯示器也瞬間切換至90Hz,每11.1ms刷新一次。這種“幀到幀”的同步徹底消除了傳統VSync的等待期,使得每一幀的顯示時機與GPU的輸出完全契合。
結語
雖然標題帶了個Android,但是實際上本文并未特地解析Andorid屏幕刷新機制,這些留到下一期再說~
下一期我們將解析Choreographer的源碼,了解一下Android Display系統!