複数のリフレッシュ レート

Android 11 では、デバイスに対する複数のリフレッシュ レートのサポートが追加されています。この機能には、次の 3 つの主要コンポーネントがあります。

  • android.hardware.graphics.composer@2.4 で導入された新しい HAL API。
  • リフレッシュ レートに応じてデバイス構成を解析し、必要なリフレッシュ レートを設定するプラットフォーム コード
  • 目的のフレームレートをアプリが設定できるようにする新しい SDK と NDK の API

実装

リフレッシュ レートの切り替え専用のサポートを android.hardware.graphics.composer@2.4 HAL に追加しました。Composer HAL の以前のバージョンでは、リフレッシュ レートの切り替えのサポートが制限されているため、このバージョンを使用することを強くおすすめします。

構成グループ

新しい属性 CONFIG_GROUPIComposerClient::Attribute に追加され、getDisplayAttribute_2_4 API を使用してクエリできるようになりました。この属性を使用して、ベンダーは画面の構成をグループ化することができます。同じグループ内にある構成であれば、ほとんどの場合、シームレスに切り替えることができます。プラットフォームは、構成グループを使用して、相互に切り替えることができるさまざまな構成を区別し、他の構成の属性ではなくリフレッシュ レートを切り替えます。

4 種類の画面構成をサポートするデバイスで構成グループを使用するメリットについて、次の例で説明します。

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

デバイスが 48Hz、60Hz、72Hz、90Hz のリフレッシュ レートをサポートしていても、画面は別のモードで動作します。60Hz から 72Hz に切り替えると、画面構成が 1080p から 1080i に変更されますが、これは意図した動作ではない可能性があります。この問題は構成グループを使用することで解決します。60 Hz と 90 Hz の構成を 1 つの構成グループに配置し、48Hz と 72Hz の構成を別の構成グループに配置します。プラットフォームは、60 Hz から 90 Hz モードに切り替えることができ、48 Hz から 72 Hz に切り替えることもできますが、60 Hz から 72 Hz に切り替えることはできません。これは、単にリフレッシュ レートを変更するだけでなく構成を変更するためです。

Composer API の更新

getDisplayVsyncPeriod
リフレッシュ レートを変更する際の制御と予測可能性を向上させるため、getDisplayVsyncPeriod を追加しました。getDisplayVsyncPeriod は、画面が動作する現在のリフレッシュ レート(vsync 期間単位)を返します。これは、リフレッシュ レートの移行中に、プラットフォームが現在のリフレッシュ レートを取得して、次のフレームをいつ開始するかを決定する必要がある場合に特に役立ちます。
setActiveConfigWithConstraints
setActiveConfigWithConstraints メソッドは既存の setActiveConfig メソッドの新しい拡張であり、構成の変更に関する詳細情報を提供します。制約は vsyncPeriodChangeConstraints パラメータの一部として指定され、以下のパラメータを含みます。
    desiredTimeNanos
    CLOCK_MONOTONIC の時間であり、この時間の後に vsync 期間が変更される場合があります(つまり、vsync 期間はこの時間以前に変更することはできません)。これは、プラットフォームがリフレッシュ レートの変更を事前に計画する必要があるが、表示のためにキューにすでにいくつかのバッファがある場合に役立ちます。プラットフォームはこれらのバッファを考慮して、この時間を適宜設定し、リフレッシュ レートの移行が可能な限りスムーズになるようにします。
    seamlessRequired
    true の場合、vsync 期間は、明らかな視覚的なアーティファクトを伴わずにシームレスに変更する必要があります。コンテンツの変更によりリフレッシュ レートを変更する必要がある場合(たとえば、デバイスがアイドル状態でアニメーションの再生が開始される場合)、プラットフォームはこのフラグを使用します。これにより、ベンダーは、視覚的に明らかなアーティファクトを引き起こす可能性のある特定の構成変更を回避できます。構成をシームレスに変更できず、seamlessRequiredtrue に設定されている場合、実装はリターンコードとして SEAMLESS_NOT_POSSIBLE を返し、新しい onSeamlessPossible コールバックを呼び出す必要があります。これにより、同じ構成変更をシームレスに完了できます。

実装が成功すると、システムは VsyncPeriodChangeTimeline を返し、リフレッシュ レートの変更が予想されるタイミングをプラットフォームに通知します。新しい画面が新しい vsync 期間に更新を開始するとき、パラメータ newVsyncAppliedTimeNanosCLOCK_MONOTONIC の時間に設定する必要があります。このパラメータを desiredTimeNanos と一緒に使用すると、プラットフォームは事前にリフレッシュ レートの切り替えを計画でき、事前にアプリが新しいリフレッシュ レートに備えてカウントダウンできるようになります。これにより、リフレッシュ レートのシームレスな移行を実現できます。

一部の実装では、更新フレームをリフレッシュ レートの前に送信する必要があります。そのため、HAL には、更新フレームが必要であることを示す refreshRequired パラメータと、更新フレームの後で送信される最初の vsync を示す refreshTimeNanos があります。

onVsyncPeriodTimingChanged [callback]
HAL が呼び出せる新しいコールバック。タイムラインの一部のパラメータが変更され、プラットフォームがタイムラインを調整する必要があることをプラットフォームに通知するために使用されます。このコールバックは、HAL の処理時間が長いか、更新フレームの遅延が原因で古いタイムラインが失われた場合に呼び出す必要があります。

プラットフォームがリフレッシュ レートを変更するルール

リフレッシュ レートの選択は、次の 2 つのシステム サービスで実施されます。

DisplayManager
DisplayManager は、リフレッシュ レートに関する高レベルのポリシーを設定します。具体的には、Composer HAL 構成と同じデフォルトの画面構成を設定します。また、リフレッシュ レートとして選択するための SurfaceFlinger の最小値と最大値の範囲も設定します。
SurfaceFlinger
デフォルト構成と同じ構成グループ内にあり、リフレッシュ レートが最小範囲または最大範囲内にある構成を設定することで、リフレッシュ レートを決定します。

ディスプレイ マネージャーは、次のステップを実行してポリシーを決定します。

  • SurfaceFlinger からアクティブな構成をクエリして、デフォルトの構成 ID を見つける
  • システム条件に対して反復処理を行うことで、最小値と最大値の範囲を制限する
    • デフォルトのリフレッシュ レートの設定: デフォルトのリフレッシュ レートは R.integer.config_defaultRefreshRate 構成オーバーレイで設定されます。この値は、アニメーションとタッチ操作に対する標準デバイスのリフレッシュ レートを決定するために使用されます。
    • ピーク時のリフレッシュ レート設定: ピーク時のリフレッシュ レート値を Settings.System.PEAK_REFRESH_RATE から読み取ります。この値は、現在のデバイス設定を(メニュー オプションなどから)反映するように、実行時に変更されます。デフォルト値は R.integer.config_defaultPeakRefreshRate 構成オーバーレイで設定されます。
    • 最小リフレッシュ レートの設定: 最小リフレッシュ レート値を Settings.System.MIN_REFRESH_RATE から読み取ります。この値は、現在のデバイス設定(メニュー オプションなど)を反映するように、実行時に変更できます。デフォルト値は 0 です。つまりデフォルトの最小値はありません。
    • Application requested ModeId: アプリは、画面が動作する必要のある優先構成を反映するように WindowManager.LayoutParams.preferredDisplayModeId を設定できます。それに応じて、ほとんどの場合、DisplayManager はデフォルトの構成 ID を設定し、構成されたリフレッシュ レートと一致するように最小リフレッシュ レートと最大リフレッシュ レートを設定します。
    • バッテリー セーバー: デバイスが省電力モード(Settings.Global.LOW_POWER_MODE. で示される)の場合、リフレッシュ レートは 60 Hz 以下に制限されます。

DisplayManager がポリシーを設定すると、SurfaceFlinger はアクティブなレイヤ(フレームのアップデートを並べ替えるレイヤ)に基づいてリフレッシュ レートを設定します。レイヤの所有者がフレームレートを設定した場合、SurfaceFlinger はリフレッシュ レートをこのレートの倍数に設定しようとします。たとえば、2 つのアクティブ レイヤのフレームレートが 24 と 60 に設定されている場合、SurfaceFlinger は 120 Hz を選択します(使用可能な場合)。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 プラットフォームに通知でき、フレームレート API は Android 11 を対象とするアプリで利用できるようになります。フレームレート API について詳しくは、developer.android.com のデベロッパー向けドキュメントをご覧ください。

開発者向けオプション

現在のリフレッシュ レートで画面上のオーバーレイを切り替えることができる開発者向けオプションがメニューに新しく追加されました。新しいオプションは、[設定] > [システム] > [開発者向けオプション] > [リフレッシュ レートの表示] にあります。