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 existingsetActiveConfig
method and provides more information about the config change. The constraints are given as part of thevsyncPeriodChangeConstraints
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 totrue
, the implementation is expected to returnSEAMLESS_NOT_POSSIBLE
as the return code and call the newonSeamlessPossible
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 inCLOCK_MONOTONIC
when the new display will start to refresh at the new vsync period. This, together withdesiredTimeNanos
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 andrefreshTimeNanos
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 forSurfaceFlinger
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 theR.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 theDisplayManager
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.
- Default refresh rate setting: The default refresh rate value
is set in the
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.