本篇文章主要介紹 Android 開發(fā)中的部分知識點,通過閱讀本篇文章,您將收獲以下內(nèi)容:
一、Vsync 概述二、Android 圖形數(shù)據(jù)流向三、Systrace 中的圖像數(shù)據(jù)流四、Vsync Offset五、HW_Vsync
Vsync 信號可以由硬件產(chǎn)生,也可以用軟件模擬,不過現(xiàn)在基本上都是硬件產(chǎn)生,負責(zé)產(chǎn)生硬件 Vsync 的是 HWC,HWC 可生成 VSYNC 事件并通過回調(diào)將事件發(fā)送到 SurfaceFlinger , DispSync 將 Vsync 生成由 Choreographer 和 SurfaceFlinger 使用的 VSYNC_APP 和 VSYNC_SF 信號
在 Android 基于 Choreographer 的渲染機制詳解 這篇文章里面,我們有提到 :Choreographer 的引入,主要是配合 Vsync,給上層 App 的渲染提供一個穩(wěn)定的 Message 處理的時機,也就是 Vsync 到來的時候 ,系統(tǒng)通過對 Vsync 信號周期的調(diào)整,來控制每一幀繪制操作的時機. 目前大部分手機都是 60Hz 的刷新率,也就是 16.6ms 刷新一次,系統(tǒng)為了配合屏幕的刷新頻率,將 Vsync 的周期也設(shè)置為 16.6 ms,每個 16.6 ms,Vsync 信號喚醒 Choreographer 來做 App 的繪制操作 ,這就是引入 Choreographer 的主要作用
渲染層(App)與 Vsync 打交道的是 Choreographer,而合成層與 Vsync 打交道的,則是 SurfaceFlinger。SurfaceFlinger 也會在 Vsync 到來的時候,將所有已經(jīng)準備好的 Surface 進行合成操作
下圖顯示在 Systrace 中,SurfaceFlinger 進程中的 VSYNC_APP 和 VSYNC_SF 的情況
首先我們要大概了解 Android 中的圖形數(shù)據(jù)流的方向,從下面這張圖,結(jié)合 Android 的圖像流,我們大概把從 App 繪制到屏幕顯示,分為下面幾個階段:
image
下面這張圖也是官方的一張圖,結(jié)合上面的階段,從左到右看,可以看到一幀的數(shù)據(jù)是如何在各個進程之間流動的
了解了 Android 中的圖形數(shù)據(jù)流的方向,我們就可以把上面這個比較抽象的數(shù)據(jù)流圖,在 Systrace 上進行映射展示
上圖中主要包含 SurfaceFlinger、App 和 hwc 三個進程,下面就來結(jié)合圖中的標(biāo)號,來進一步說明數(shù)據(jù)的流向
文章最開始有提到,Vsync 信號可以由硬件產(chǎn)生,也可以用軟件模擬,不過現(xiàn)在基本上都是硬件產(chǎn)生,負責(zé)產(chǎn)生硬件 Vsync 的是 HWC,HWC 可生成 VSYNC 事件并通過回調(diào)將事件發(fā)送到 SurfaceFlinge , DispSync 將 Vsync 生成由 Choreographer 和 SurfaceFlinger 使用的 VSYNC_APP 和 VSYNC_SF 信號.
disp_sync_arch
其中 app 和 sf 相對 hw_vsync_0 都有一個偏移,即 phase-app 和 phase-sf,如下圖
image
Vsync Offset 我們指的是 VSYNC_APP 和 VSYNC_SF 之間有一個 Offset,即上圖中 phase-sf - phase-app 的值,這個 Offset 是廠商可以配置的。如果 Offset 不為 0,那么意味著 App 和 SurfaceFlinger 主進程不是同時收到 Vsync 信號,而是間隔 Offset (通常在 0 - 16.6ms 之間)
目前大部分廠商都沒有配置這個 Offset,所以 App 和 SurfaceFlinger 是同時收到 Vsync 信號的.
可以通過 Dumpsys SurfaceFlinger 來查看對應(yīng)的值
Offset 為 0:(sf phase - app phase = 0)
Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync]DispSync configuration: app phase 1000000 ns, sf phase 1000000 ns early app phase 1000000 ns, early sf phase 1000000 ns early app gl phase 1000000 ns, early sf gl phase 1000000 ns present offset 0 ns refresh 16666666 ns
Offset 不為 0 (SF phase - app phase = 4 ms)
Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync]VSYNC configuration: app phase: 2000000 ns SF phase: 6000000 ns early app phase: 2000000 ns early SF phase: 6000000 nsGL early app phase: 2000000 ns GL early SF phase: 6000000 ns present offset: 0 ns VSYNC period: 16666666 ns
下面以 Systrace 為例,來看 Offset 在 Systrace 中的表現(xiàn)
首先說 Offset 為 0 的情況, 此時 App 和 SurfaceFlinger 是同時收到 Vsync 信號 , 其對應(yīng)的 Systrace 圖如下:
這個圖上面也有講解,這里就不再詳細說明,大家只需要看到,App 渲染好的 Buffer,要等到下一個 Vsync-SF 來的時候才會被 SurfaceFlinger 拿去做合成,這個時間大概在 16.6 ms。這時候大家可能會想,如果 App 的 Buffer 渲染結(jié)束,Swap 到 BufferQueue 中 ,就觸發(fā) SurfaceFlinger 去做合成,那豈不是省了一些時間(0-16.6ms )?
答案是可行的,這也就引入了 Offset 機制,在這種情況下,App 先收到 Vsync 信號,進行一幀的渲染工作,然后過了 Offset 時間后,SurfaceFlinger 才收到 Vsync 信號開始合成,這時候如果 App 的 Buffer 已經(jīng) Ready 了,那么 SurfaceFlinger 這一次合成就可以包含 App 這一幀,用戶也會早一點看到。
下圖中,就是一個 Offset 為 4ms 的案例,App 收到 Vsync 4 ms 之后,SurfaceFlinger 才收到 Vsync 信號
image
Offset 的一個比較難以確定的點就在與 Offset 的時間該如何設(shè)置,這也是眾多廠商默認都不進行配置 Offset 的一個原因,其優(yōu)缺點是動態(tài)的,與機型的性能和使用場景有很大的關(guān)系
這里需要說明的是,不是每次申請 Vsync 都會由硬件產(chǎn)生 Vsync,只有此次請求 vsync 的時間距離上次合成時間大于 500ms,才會通知 hwc,請求 HW_VSYNC
以桌面滑動為例,看 SurfaceFlinger 的進程 Trace 可以看到 HW_VSYNC 的狀態(tài)
后續(xù) App 申請 Vsync 時候,會有兩種情況,一種是有 HW_VSYNC 的情況,一種是沒有有 HW_VSYNC 的情況
HW_VSYNC 主要是利用最近的硬件 VSYNC 來做預(yù)測,最少要 3 個,最多是 32 個,實際上要用幾個則不一定, DispSync 拿到 6 個 VSYNC 后就會計算出 SW_VSYNC,只要收到的 Present Fence 沒有超過誤差,硬件 VSYNC 就會關(guān)掉,不然會繼續(xù)接收硬件 VSYNC 計算 SW_VSYNC 的值,直到誤差小于 threshold.關(guān)于這一塊的計算具體過程,可以參考這篇文章: S W-VS YN C 的生成與傳遞 ,關(guān)于這一塊的流程大家也可以參考這篇文章,里面有更細節(jié)的內(nèi)容,這里摘錄了他的結(jié)論
SurfaceFlinger 通過實現(xiàn)了 HWC2::ComposerCallback 接口,當(dāng) HW-VSYNC 到來的時候,SurfaceFlinger 將會收到回調(diào)并且發(fā)給 DispSync。DispSync 將會把這些 HW-VSYNC 的時間戳記錄下來,當(dāng)累計了足夠的 HW-VSYNC 以后(目前是大于等于 6 個),就開始計算 SW-VSYNC 的偏移 mPeriod。計算出來的 mPeriod 將會用于 DispSyncThread 用來模擬 HW-VSYNC 的周期性起來并且通知對 VSYNC 感興趣的 Listener,這些 Listener 包括 SurfaceFlinger 和所有需要渲染畫面的 app。這些 Listener 通過 EventThread 以 Connection 的抽象形式注冊到 EventThread。DispSyncThread 與 EventThread 通過 DispSyncSource 作為中間人進行連接。EventThread 在收到 SW-VSYNC 以后將會把通知所有感興趣的 Connection,然后 SurfaceFlinger 開始合成,app 開始畫幀。在收到足夠多的 HW-VSYNC 并且在誤差允許的范圍內(nèi),將會關(guān)閉通過 EventControlThread 關(guān)閉 HW-VSYNC。
推薦閱讀:蘋果x好還是xr好
查看心情排行你看到此篇文章的感受是: