小米電池休眠自動解除打開后蓋 小米電池休眠自動解除( 三 )


這一點在 XR 上得到了驗證,用 Instruments 記錄一次主線程發生的卡頓,得到:

小米電池休眠自動解除打開后蓋  小米電池休眠自動解除

文章插圖
其中:
之一行 runloop 記錄每次 RunLoop AfterWaiting -> BeforeWaiting 的間隔第二行 tick 記錄默認配置的 CADisplayLink 回調間的間隔最下面則是硬件 Display/VSync 事件時序圖可以觀察到下述現象,符合我們之前的對 DisplayLink 的認識:
沒有卡頓的情況下,VSync 信號和 RunLoop 的喚醒 & CADisplayLink 回調的觸發嚴格一一對應 。RunLoop 卡頓,無法處理 Source 1 信號,DisplayLink 回調被延遲到卡頓結束時 。在此過程中 VSync 信號間隔始終保持不變 。ProMotion 設備下面看看 ProMotion 設備的測試結果 。
VSync 信號間隔可變在 ProMotion 屏幕上 VSync 信號間隔是可變的,具體而言:
顯示靜態內容時,屏幕降頻,更低以 10Hz 的頻率進行刷新顯示 Core Animation 動畫時,系統會適配動畫的幀率設置改變刷新率*通過 preferredFrameRateRange 可以設置 hint 請求高刷,但并不一定生效,詳見下文“動態幀率的應用場景”部分 。
顯示滑動中內容時,刷新率在 80Hz 左右波動,并且跟隨滑動速度變化而變化 ??旎瑫r刷新率升高,慢滑時降低 。顯示視頻時,刷新率和視頻幀率維持一致可以看到 VSync 信號間隔能主動跟隨顯示內容的渲染幀率的改變而改變 。
減少卡頓造成的顯示延遲在主線程發生卡頓導致滑動中某一幀渲染耗時過長時,系統會改變這一幀所對應的 VSync 信號間隔(下圖 Surface 5),減小從渲染到展示的延時,從而減緩用戶感知到的卡頓時長 。
小米電池休眠自動解除打開后蓋  小米電池休眠自動解除

文章插圖
DisplayLink 不完全跟隨 VSync 信號如圖是一張滑動中場景的 CADisplayLink 回調 和 Display/VSync 事件對照記錄 。和之前不同的是,再 ProMotion 設備上 DisplayLink 和 VSync 信號之間沒有表現出明顯的跟隨關系:
小米電池休眠自動解除打開后蓋  小米電池休眠自動解除

文章插圖
具體而言:
第三個箭頭所指向的 DisplayLink 的回調并不及時 。在這之前主線程的卡頓已經結束,并且額外執行了兩次 RunLoop,但直到第三次才調用了 DisplayLink 的回調 。不僅僅是時機不匹配,也存在收到 VSync 但不觸發 DisplayLink 回調的情況(并且主線程處于空閑狀態),例如上圖中的 ? 處 。解除 DisplayLink 的幀數限制我們知道,在 iOS 15 上 Apple 對第三方應用的顯示幀率默認做了限制 。第三方應用需要在 Info.plist 中添加<key>CADisableMinimumFrameDurationOnPhone</key><true/> 字段才可以解鎖 120Hz 的刷新率 。
于此同時,在 iOS 15 中,CADisplayLink 等動畫相關 API 也新增了一個用于配置偏好幀率的屬性:
/* Defines the range of desired callback rate in frames-per-second for thisdisplay link. If the range contains the same minimum and maximum frame rate,this property is identical as preferredFramesPerSecond. Otherwise, the actualcallback rate will be dynamically adjusted to better align with otheranimation sources. */@property(nonatomic) CAFrameRateRange preferredFrameRateRangeAPI_AVAILABLE(ios(15.0), watchos(8.0), tvos(15.0));為了進一步探究新設備上 DisplayLink 和 VSync 信號之間的關系,筆者將測試 App 的 Core Animation 的幀率限制解除,并配置對應的 API,分別在不同的場景重新進行測試:
顯示動態內容的場景動畫場景展示一個速度中等的位移動畫,得到下圖:
小米電池休眠自動解除打開后蓋  小米電池休眠自動解除

文章插圖
可以很直觀地發現,DisplayLink 解鎖幀率后的屏幕刷新率基本穩定在 120Hz 。并且 VSync 和 DisplayLink 的關系似乎又重新一一對應了起來 。
但是,將動畫速度減慢,筆者發現這種對應關系發生了變化:
小米電池休眠自動解除打開后蓋  小米電池休眠自動解除

文章插圖
可以觀察到在播放慢速動畫時,DisplayLink 的頻率依然是配置的 120Hz,但是實際的屏幕刷新率卻只有 30Hz 。
滑動場景讓我們換一種場景再次進行測試,快速滑動視圖,在 Instruments 中得到下圖:
小米電池休眠自動解除打開后蓋  小米電池休眠自動解除

文章插圖
可以發現,DisplayLink 解鎖幀率后,屏幕刷新率同樣基本穩定在 120Hz,僅在丟幀時有降頻 。
需要注意的是筆者在 CADisplayLink 的回調中除了調用 os_signpost 上報 log 外無任何 UI 改動 。即便筆者展示的 TableView 極其簡單,上圖中仍然可以觀察到丟幀,無法在滑動中完美穩定 120Hz 。這也許說明 UIKit 的渲染性能在 120Hz 下會有某種程度上的原生瓶頸 。然后降低滑動屏幕的速度,得到了和慢速動畫相似的結果,盡管 DisplayLink 回調速度不減,但是 VSync 信號頻率一直保持在較低的水平:

推薦閱讀