Multiple refresh rate

Android 11 adds support for devices with multiple refresh rates. There are three main components to this feature:

  • New HAL APIs introduced in android.hardware.graphics.composer@2.4.
  • Platform code to parse device configs for different refresh rates and set the desired refresh rate
  • New SDK and NDK APIs to allow apps to set their desired frame rate

Implementation

Dedicated support for refresh rate switching has been added to android.hardware.graphics.composer@2.4 HAL. We strongly recommend using this version since previous versions of composer HAL have limited support for refresh rate switching.

Config groups

A new attribute CONFIG_GROUP was added to IComposerClient::Attribute that is queryable using the getDisplayAttribute_2_4 API. This attribute allows vendors to group together display configurations. Configurations in the same group allows seamless switching between them in most of the cases. The config group is used by the platform to differentiate which configurations can be switched between them in order to switch the refresh rate and not other attributes for a config.

Consider the following example that demonstrates the benefits of using config groups with a device that supports four display configurations:

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

Even though the device supports 48Hz, 60Hz, 72Hz, and 90Hz refresh rates the display operates at a different mode and switching from 60Hz to 72Hz changes the display config from 1080p to 1080i, which might not be the desired behavior. This is solved by using config groups. By grouping 60Hz and 90Hz together in one config group and 48Hz and 72Hz in another config group. The platform knows that it can switch between 60Hz and 90Hz and between 48Hz and 72Hz but not between 60Hz and 72Hz as this will result in a config change rather than simply changing the refresh rate.

Composer API updates

getDisplayVsyncPeriod
For better control and predictability when changing refresh rates getDisplayVsyncPeriod has been added. getDisplayVsyncPeriod returns the current refresh rate (in terms of vsync period) the display operates at. This is especially useful while transitioning between refresh rate and the current refresh rate is needed by the platform to decide when to start the next frame.
setActiveConfigWithConstraints
The setActiveConfigWithConstraints method is a new extension to the existing setActiveConfig method and provides more information about the config change. The constraints are given as part of the vsyncPeriodChangeConstraints parameters and contain the following parameters.
    desiredTimeNanos
    The time in CLOCK_MONOTONIC after which the vsync period may change (that is the vsync period must not change before this time). This is useful when the platform wants to plan ahead for a refresh rate change but it already has some buffers in the queue to present. The platform sets this time accordingly to account for those buffers and make sure that the refresh rate transition will be as smooth as possible.
    seamlessRequired
    If true, requires that the vsync period change must happen seamlessly without a noticeable visual artifact. This flag is used by the platform when a refresh rate change is needed as a result of a content change (for example, the device is idle and animation starts). This gives the vendor the opportunity to not allow certain configuration changes when they might result in a noticeable visual artifact. If the configs can't be changed seamlessly and seamlessRequired is set to true, the implementation is expected to return SEAMLESS_NOT_POSSIBLE as the return code and call the new onSeamlessPossible callback when the same config change can be done seamlessly.

Upon success the implementation returns a VsyncPeriodChangeTimeline which tells the platform when to expect the refresh rate change to occur. newVsyncAppliedTimeNanos parameters need to be set to the time in CLOCK_MONOTONIC when the new display will start to refresh at the new vsync period. This, together with desiredTimeNanos allows the platform to plan in advance the refresh rate switch and start ticking apps for the new refresh rate in advance. This allows a seamless transition of the refresh rate.

Some implementations require a refresh frame to be sent before the refresh rate can be sent. For that, the HAL has the refreshRequired parameter to indicate that a refresh frame is needed and refreshTimeNanos to indicate the first vsync where a refresh frame needs to be sent after.

onVsyncPeriodTimingChanged [callback]
A new callback that can be called by the HAL to indicate to the platform that some parameter of the timeline changed and the platform needs to adjust its timeline. This callback is expected to be called if for some reason the old timeline was missed because of a long processing time on the HAL or a late refresh frame.

How does the platform decide to change the refresh rate?

The refresh rate selection happens in the following two system services:

DisplayManager
The DisplayManager sets the high level policy around the refresh rate. It sets a default display config, which is the same as the composer HAL config. Additionally, it sets a range of minimum and maximum values for SurfaceFlinger to choose as the refresh rate.
SurfaceFlinger
Determines the refresh rate by setting a config which is in the same config group as the default config and with a refresh rate within the min/max range.

The Display Manager runs through the following steps to determine the policy:

  • Finds the default config ID by querying the active config from SurfaceFlinger
  • Restricting the range of minimum and maximum values by iterating over the system conditions
    • Default refresh rate setting: The default refresh rate value is set in the R.integer.config_defaultRefreshRate config overlay. This value is used to determine the standard device refresh rate for animations and touch interactions.
    • Peak refresh rate setting: The peak refresh rate value is read from Settings.System.PEAK_REFRESH_RATE. This value is changed in runtime to reflect the current device setting (such as from a menu option). The default value is set in the R.integer.config_defaultPeakRefreshRate config overlay.
    • Minimum refresh rate setting: The minimum refresh rate value is read from Settings.System.MIN_REFRESH_RATE. This value can be changed in runtime to reflect the current device setting (such as from a menu option). The default value is 0, so there is no default minimum.
    • Application requested ModeId: Apps can set WindowManager.LayoutParams.preferredDisplayModeId to reflect a preferred config the display should operate at. In most conditions the DisplayManager sets the default config ID accordingly and sets the minimum and maximum refresh rate to match the config's refresh rate.
    • Battery Saver: The refresh rate is restricted to 60Hz or lower when the device is in low power mode, which is indicated through Settings.Global.LOW_POWER_MODE.

Once DisplayManager sets the policy, SurfaceFlinger sets the refresh rate based on the active layers (layers that queue frame updates). If the owner of the layer sets a frame rate, SurfaceFlinger tries to set the refresh rate to something that is a multiplier of that rate. For example if two active layers set their frame rate to 24 and 60 SurfaceFlinger will pick 120Hz if it is available. If such refresh rate is not available to SurfaceFlinger, it will try to pick the refresh rate which has the minimal error for the frame rate. For more information see the developer documentation on developer.android.com

SurfaceFlinger maintains the following flags to control how the refresh rate is decided:

  • ro.surface_flinger.use_content_detection_for_refresh_rate: If set the refresh rate is decided based on the active layers, even if a frame rate was not set. SurfaceFlinger maintains a heuristic where it finds the average fps the layer is posting buffers by looking at the presentation timestamp attached to the buffer.
  • ro.surface_flinger.set_touch_timer_ms: if > 0, the default refresh rate will be used when a user touches the screen for the configured timeout. This heuristic is done to be ready with the default refresh rate for animations.
  • ro.surface_flinger.set_idle_timer_ms: if > 0, min refresh rate will be used when there are no screen updates for the configured timeout.
  • ro.surface_flinger.set_display_power_timer_ms: if > 0, the default refresh rate will be used when turning on the display (or when going out of AOD) for the configured timeout.

Frame Rate API

The frame rate API lets apps inform the Android platform of their intended frame rate and is available on apps that target Android 11. To learn more about the frame rate API, check out the developer documentation on developer.android.com.

Developer options

A new developer option has been added to the menu that toggles an overlay on the display with the current refresh rate. The new option is under Settings > System > Developer options > Show refresh rate.