宜賓在線_宜賓最專業的企業資訊門戶網站
加入收藏 網站地圖

福彩:Systrace 之 Vsync 解讀

來源:時間:2020-03-21 06:00:46 閱讀:-

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

福彩 www.otoab.com 本篇文章主要介紹 Android 開發中的部分知識點,通過閱讀本篇文章,您將收獲以下內容:

一、Vsync 概述二、Android 圖形數據流向三、Systrace 中的圖像數據流四、Vsync Offset五、HW_Vsync

一、Vsync 概述

Vsync 信號可以由硬件產生,也可以用軟件模擬,不過現在基本上都是硬件產生,負責產生硬件 Vsync 的是 HWC,HWC 可生成 VSYNC 事件并通過回調將事件發送到 SurfaceFlinger , DispSync 將 Vsync 生成由 Choreographer 和 SurfaceFlinger 使用的 VSYNC_APP 和 VSYNC_SF 信號



在 Android 基于 Choreographer 的渲染機制詳解 這篇文章里面,我們有提到 :Choreographer 的引入,主要是配合 Vsync,給上層 App 的渲染提供一個穩定的 Message 處理的時機,也就是 Vsync 到來的時候 ,系統通過對 Vsync 信號周期的調整,來控制每一幀繪制操作的時機. 目前大部分手機都是 60Hz 的刷新率,也就是 16.6ms 刷新一次,系統為了配合屏幕的刷新頻率,將 Vsync 的周期也設置為 16.6 ms,每個 16.6 ms,Vsync 信號喚醒 Choreographer 來做 App 的繪制操作 ,這就是引入 Choreographer 的主要作用

渲染層(App)與 Vsync 打交道的是 Choreographer,而合成層與 Vsync 打交道的,則是 SurfaceFlinger。SurfaceFlinger 也會在 Vsync 到來的時候,將所有已經準備好的 Surface 進行合成操作

下圖顯示在 Systrace 中,SurfaceFlinger 進程中的 VSYNC_APP 和 VSYNC_SF 的情況



二、Android 圖形數據流向

首先我們要大概了解 Android 中的圖形數據流的方向,從下面這張圖,結合 Android 的圖像流,我們大概把從 App 繪制到屏幕顯示,分為下面幾個階段:


image


  1. 第一階段:App 在收到 Vsync-App 的時候,在主線程進行 measure、layout、draw(構建 DisplayList , 里面包含 OpenGL 渲染需要的命令及數據) 。這里對應的 Systrace 中的主線程 doFrame 操作
  2. 第二階段:CPU 將數據上傳(共享或者拷貝)給 GPU, 這里 ARM 設備 內存一般是 GPU 和 CPU 共享內存。這里對應的 Systrace 中的渲染線程的 flush drawing commands 操作
  3. 第三階段:通知 GPU 渲染,真機一般不會阻塞等待 GPU 渲染結束,CPU 通知結束后就返回繼續執行其他任務,使用 Fence 機制輔助 GPU CPU 進行同步操作
  4. 第四 階段:swapBuffers,并通知 SurfaceFlinger 圖層合成。這里對應的 Systrace 中的渲染線程的 eglSwapBuffersWithDamageKHR 操作
  5. 第五階段:SurfaceFlinger 開始合成圖層,如果之前提交的 GPU 渲染任務沒結束,則等待 GPU 渲染完成,再合成(Fence 機制),合成依然是依賴 GPU,不過這就是下一個任務了.這里對應的 Systrace 中的 SurfaceFlinger 主線程的 onMessageReceived 操作(包括 handleTransaction、handleMessageInvalidate、handleMessageRefresh)SurfaceFlinger 在合成的時候,會將一些合成工作委托給 Hardware Composer,從而降低來自 OpenGL 和 GPU 的負載,只有 Hardware Composer 無法處理的圖層,或者指定用 OpenGL 處理的圖層,其他的 圖層偶會使用 Hardware Composer 進行合成
  6. 第六階段 :最終合成好的數據放到屏幕對應的 Frame Buffer 中,固定刷新的時候就可以看到了

下面這張圖也是官方的一張圖,結合上面的階段,從左到右看,可以看到一幀的數據是如何在各個進程之間流動的



三、Systrace 中的圖像數據流

了解了 Android 中的圖形數據流的方向,我們就可以把上面這個比較抽象的數據流圖,在 Systrace 上進行映射展示



上圖中主要包含 SurfaceFlinger、App 和 hwc 三個進程,下面就來結合圖中的標號,來進一步說明數據的流向

  1. 第一個 Vsync 信號到來, SurfaceFlinger 和 App 同時收到 Vsync 信號
  2. SurfaceFlinger 收到 Vsync-sf 信號,開始進行 App 上一幀的 Buffer 的合成
  3. App 收到 Vsycn-app 信號,開始進行這一幀的 Buffer 的渲染(對應上面的第一、二、三、四階段)
  4. 第二個 Vsync 信號到來 ,SurfaceFlinger 和 App 同時收到 Vsync 信號,SurfaceFlinger 獲取 App 在第二步里面渲染的 Buffer,開始合成(對應上面的第五階段),App 收到 Vsycn-app 信號,開始新一幀的 Buffer 的渲染(對應上面的第一、二、三、四階段)

四、Vsync Offset

文章最開始有提到,Vsync 信號可以由硬件產生,也可以用軟件模擬,不過現在基本上都是硬件產生,負責產生硬件 Vsync 的是 HWC,HWC 可生成 VSYNC 事件并通過回調將事件發送到 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 來查看對應的值

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 中的表現

1.Offset 為 0

首先說 Offset 為 0 的情況, 此時 App 和 SurfaceFlinger 是同時收到 Vsync 信號 , 其對應的 Systrace 圖如下:



這個圖上面也有講解,這里就不再詳細說明,大家只需要看到,App 渲染好的 Buffer,要等到下一個 Vsync-SF 來的時候才會被 SurfaceFlinger 拿去做合成,這個時間大概在 16.6 ms。這時候大家可能會想,如果 App 的 Buffer 渲染結束,Swap 到 BufferQueue 中 ,就觸發 SurfaceFlinger 去做合成,那豈不是省了一些時間(0-16.6ms )?

答案是可行的,這也就引入了 Offset 機制,在這種情況下,App 先收到 Vsync 信號,進行一幀的渲染工作,然后過了 Offset 時間后,SurfaceFlinger 才收到 Vsync 信號開始合成,這時候如果 App 的 Buffer 已經 Ready 了,那么 SurfaceFlinger 這一次合成就可以包含 App 這一幀,用戶也會早一點看到。

2.Offset 不為 0

下圖中,就是一個 Offset 為 4ms 的案例,App 收到 Vsync 4 ms 之后,SurfaceFlinger 才收到 Vsync 信號


image


3.Offset 的優缺點

Offset 的一個比較難以確定的點就在與 Offset 的時間該如何設置,這也是眾多廠商默認都不進行配置 Offset 的一個原因,其優缺點是動態的,與機型的性能和使用場景有很大的關系

  1. 如果 Offset 配置過短,那么可能 App 收到 Vsync-App 后還沒有渲染完成,SurfaceFlinger 就收到 Vsync-SF 開始合成,那么此時如果 App 的 BufferQueue 中沒有之前累積的 Buffer,那么 SurfaceFlinger 這次合成就不會有 App 的東西在里面,需要等到下一個 Vsync-SF 才能合成這次 App 的內容,時間相當于變成了 Vsync 周期+Offset,而不是我們期待的 Offset
  2. 如果 Offset 配置過長,就起不到作用了

五、HW_Vsync

這里需要說明的是,不是每次申請 Vsync 都會由硬件產生 Vsync,只有此次請求 vsync 的時間距離上次合成時間大于 500ms,才會通知 hwc,請求 HW_VSYNC

以桌面滑動為例,看 SurfaceFlinger 的進程 Trace 可以看到 HW_VSYNC 的狀態



后續 App 申請 Vsync 時候,會有兩種情況,一種是有 HW_VSYNC 的情況,一種是沒有有 HW_VSYNC 的情況

1.不使用HW_VSYNC



2.使用 HW_VSYNC



HW_VSYNC 主要是利用最近的硬件 VSYNC 來做預測,最少要 3 個,最多是 32 個,實際上要用幾個則不一定, DispSync 拿到 6 個 VSYNC 后就會計算出 SW_VSYNC,只要收到的 Present Fence 沒有超過誤差,硬件 VSYNC 就會關掉,不然會繼續接收硬件 VSYNC 計算 SW_VSYNC 的值,直到誤差小于 threshold.關于這一塊的計算具體過程,可以參考這篇文章: S W-VS YN C 的生成與傳遞 ,關于這一塊的流程大家也可以參考這篇文章,里面有更細節的內容,這里摘錄了他的結論

SurfaceFlinger 通過實現了 HWC2::ComposerCallback 接口,當 HW-VSYNC 到來的時候,SurfaceFlinger 將會收到回調并且發給 DispSync。DispSync 將會把這些 HW-VSYNC 的時間戳記錄下來,當累計了足夠的 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 并且在誤差允許的范圍內,將會關閉通過 EventControlThread 關閉 HW-VSYNC。

圖文推薦

宜賓在線版權及免責聲明:

1、凡本網注明 “來源:***(非宜賓在線)” 的作品,均轉載自其它媒體,轉載目的在于傳遞更多信息,并不代表本網贊同其觀點和對其真實性負責。

2、如因作品內容、版權和其它問題需要同本網聯系的,請在30日內進行。

最新新聞
熱門資訊榜
{ganrao}