多種刷新率

Android 11 新增支援採用多種刷新率的裝置。這項功能有三個主要元件:

  • android.hardware.graphics.composer@2.4 中推出的新 HAL API。
  • 平台程式碼,用於剖析不同螢幕重新整理頻率的裝置設定,並設定所需的螢幕重新整理頻率
  • 新的 SDK 和 NDK API,可讓應用程式設定所需的影格速率

實作

android.hardware.graphics.composer@2.4 HAL 已加入專屬的刷新率切換支援功能。強烈建議您使用這個版本,因為先前版本的 Composer HAL 對重新整理頻率切換的支援有限。

設定群組

已在 IComposerClient::Attribute 中新增屬性 CONFIG_GROUP,該屬性可使用 getDisplayAttribute_2_4 API 查詢。這項屬性可讓供應商將顯示設定分組。在大多數情況下,同一個群組中的設定可讓您無縫切換。平台會使用設定群組來區分可在其間切換的設定,以便切換設定的刷新率,而非其他屬性。

請參考以下範例,瞭解在支援四種顯示設定的裝置上使用設定群組的好處:

  • 1080p@60Hz
  • 1080p@90Hz
  • 1080i@72Hz
  • 1080i@48Hz

雖然裝置支援 48Hz、60Hz、72Hz 和 90Hz 的螢幕刷新率,但螢幕會以不同的模式運作,且從 60Hz 切換至 72Hz 會將螢幕設定從 1080p 變更為 1080i,這可能不是您想要的行為。您可以使用設定群組解決這個問題。將 60Hz 和 90Hz 歸入同一個設定群組,而 48Hz 和 72Hz 則歸入另一個設定群組。平台知道可以切換 60 Hz 和 90 Hz 之間,以及 48 Hz 和 72 Hz 之間,但不能切換 60 Hz 和 72 Hz 之間,因為這會導致設定變更,而非單純變更刷新率。

Composer API 更新

getDisplayVsyncPeriod
為了在變更螢幕更新率時提供更佳的控管和可預測性,我們已新增 getDisplayVsyncPeriod getDisplayVsyncPeriod 會傳回螢幕目前的刷新率 (以 vsync 週期為準)。如果平台需要從刷新率和目前的刷新率轉換,才能決定啟動下一個影格的時機,因此這項功能特別實用。
setActiveConfigWithConstraint
setActiveConfigWithConstraints 方法是現有 setActiveConfig 方法的新擴充功能,可提供更多設定變更資訊。限制條件會提供為 vsyncPeriodChangeConstraints 參數的一部分,並包含下列參數。
    desiredTimeNanos
    CLOCK_MONOTONIC 中的時間,此時間過後,vsync 週期可能會變更 (也就是說,vsync 週期必須在這個時間之前變更)。當平台想要提前規劃刷新率變更,但佇列中已有要顯示的緩衝區時,這項功能就非常實用。平台會根據這些緩衝區設定這段時間,確保螢幕刷新率轉換過程盡可能順暢。
    seamlessRequired
    如果為 true,則要求 vsync 期間變更必須無縫進行,且不會出現明顯的視覺瑕疵。如果因內容變更 (例如裝置處於閒置狀態且動畫開始播放) 需要調整刷新率,平台會使用這個標記。這樣一來,供應商就能在特定設定變更可能導致明顯視覺瑕疵時,禁止這些變更。如果無法順利變更設定,且 seamlessRequired 已設為 true,則實作應會傳回 SEAMLESS_NOT_POSSIBLE 做為傳回碼,並在可順利變更相同設定時呼叫新的 onSeamlessPossible 回呼。

實作成功後,實作會傳回 VsyncPeriodChangeTimeline,告知平台何時會發生更新率變更。當新螢幕開始在新顯示同步期間開始重新整理時,newVsyncAppliedTimeNanos 參數必須設為 CLOCK_MONOTONIC 中的時間。這項功能與 desiredTimeNanos 搭配使用,可讓平台事先規劃螢幕更新率切換作業,並提前開始為應用程式啟用新螢幕更新率。這樣就能流暢轉換螢幕刷新率。

有些實作項目必須先傳送重新整理影格,才能傳送刷新率。為此,HAL 提供 refreshRequired 參數,用於指出需要刷新影格,並提供 refreshTimeNanos,用於指出需要在哪個 vsync 之後傳送刷新影格。

onVsyncPeriodTimingChanged [回呼]
HAL 可呼叫的新回呼,向平台指出時間軸的部分參數已變更,且平台必須調整時間軸。如果因 HAL 處理時間過長或刷新影格延遲,導致舊時間軸遺漏,則會呼叫這個回呼。

平台如何決定變更刷新率?

系統會在下列兩個系統服務中選取更新率:

DisplayManager
DisplayManager 會設定刷新率的高層級政策。它會設定預設顯示設定,這與作曲家 HAL 設定相同。此外,它會為 SurfaceFlinger 設定最小值和最大值範圍,以便選擇做為更新率。
SurfaceFlinger
如要決定刷新率,請設置設定,該設定與預設設定位於相同的設定群組中,且重新整理頻率在下限/上限範圍內。

顯示管理工具會按照下列步驟判斷政策:

  • 透過查詢 SurfaceFlinger 中的有效設定,找出預設設定 ID
  • 透過迭代系統條件,限制最小和最大值的範圍
    • 預設重新整理頻率設定:預設重新整理頻率值會在 R.integer.config_defaultRefreshRate 設定重疊圖層中設定。這個值可用來決定動畫和觸控互動功能的標準裝置更新率。
    • 最高刷新率設定:最高刷新率值會從 Settings.System.PEAK_REFRESH_RATE 讀取。這個值會在執行階段變更,以反映目前的裝置設定 (例如來自選單選項)。預設值會在 R.integer.config_defaultPeakRefreshRate 設定疊加層中設定。
    • 最小刷新率設定:最小刷新率值會從 Settings.System.MIN_REFRESH_RATE 讀取。這個值可在執行階段變更,以反映目前的裝置設定 (例如來自選單選項)。預設值為 0,因此沒有預設最小值。
    • 應用程式要求 ModeId:應用程式可設定 WindowManager.LayoutParams.preferredDisplayModeId,以反映螢幕應運作的偏好設定。在大多數情況下,DisplayManager 會依據情況設定預設設定 ID,並將最小和最大更新率設為與設定的更新率相符。
    • 省電模式:裝置處於省電模式時,螢幕更新率會限制在 60Hz 以下,這會透過 Settings.Global.LOW_POWER_MODE. 表示

DisplayManager 設定政策後,SurfaceFlinger 會根據有效圖層 (排入佇列的幀更新圖層) 設定更新率。如果圖層擁有者設定了「影格速率」,SurfaceFlinger 會嘗試將刷新率設為該速率的倍數。舉例來說,如果兩個有效圖層將影格速率設為 24 和 60,SurfaceFlinger 會選擇 120Hz (如果可用)。如果 SurfaceFlinger 無法使用這類更新率,就會嘗試挑選最能降低影格速率誤差的更新率。詳情請參閱 developer.android.com 的開發人員說明文件。

SurfaceFlinger 會維護下列標記,以控制決定更新率的方式:

  • ro.surface_flinger.use_content_detection_for_refresh_rate: 如果已設定,系統會根據有效圖層決定更新率,即使未設定影格速率也一樣。SurfaceFlinger 會維持一種啟發式,透過查看附加至緩衝區的呈現時間戳記,找出圖層發布緩衝區的平均 FPS。
  • ro.surface_flinger.set_touch_timer_ms:如果大於 0,則當使用者在設定的逾時期限內輕觸螢幕時,系統就會使用預設的刷新率。這樣就能使用動畫的預設刷新率了。
  • ro.surface_flinger.set_idle_timer_ms:如果大於 0,在設定的逾時期間內,如果沒有任何螢幕更新,系統就會使用最小更新率。
  • ro.surface_flinger.set_display_power_timer_ms:如果 > 0,系統會在開啟螢幕 (或退出 AOD) 時,使用預設的重新整理率,直到設定的逾時時間為止。

畫面更新率 API

影格速率 API 可讓應用程式向 Android 平台告知其預期的影格速率,並適用於指定 Android 11 為目標版本的應用程式。如要進一步瞭解影格速率 API,請參閱 developer.android.com 的開發人員說明文件。

開發人員選項

選單中新增了一個開發人員選項,可切換顯示目前刷新率的疊加層。新選項位於「設定」 >「系統」 >「開發人員選項」 >「顯示更新率」