Split refresh rate range into two ranges
To prevent low-priority refresh rate considerations from overriding the
app frame rate as specified via the new setFrameRate() api, split the
display refresh rate range into "primary" and "app request" ranges. The
primary range includes the low priority considerations, while the app
request range removes two lower priority considerations.
In general, surface flinger will keep the display refresh rate within
the primary range, but layers with frame rate settings via the
setFrameRate() api may cause surface flinger to pick a refresh rate
outside the primary range. Surface flinger will never choose a refresh
rate outside the app request range specified by display manager.
Bug: 148978562
Test: - Added a new unit test to DisplayModeDirectorTest to verify that
display manager strips lower priority considerations when
deciding the app request range.
- Added a new unit test to RefreshRateConfigsTest to verify
RefreshRateConfigs handles the primary vs app request range
correctly.
- Manual test: Confirmed that with the "force 90Hz refresh rate" option
turned on, we don't switch to 60Hz when playing a 60Hz video.
- Manual test: Confirmed that with the "force 90Hz refresh rate" option
turned on, when an app calls setFrameRate(60), we stay at 60Hz.
- Manual test: Modified a Pixel 4 XL to prefer 60Hz in low brightness,
entered low brightness, and confirmed we don't touch boost to 90Hz.
- Manual test: Confirmed that Maps stays at 60Hz on Pixel 4.
- Manual test: Turned on verbose logs in RefreshRateConfigs.cpp,
confirmed they look good.
- Manual test: Inspected dumpsys output, confirmed the primary and
app request refresh rate ranges are printed correctly.
Change-Id: Ib16cc9b6158efa575cdbfbb7a0ad014008a3e5af
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2943499..c05d61c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1002,7 +1002,7 @@
} else {
const HwcConfigIndexType config(mode);
const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
- const scheduler::RefreshRateConfigs::Policy policy{config, fps, fps};
+ const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -4371,17 +4371,19 @@
scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
StringAppendF(&result,
"DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz",
- policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
+ policy.appRequestRange.min, policy.appRequestRange.max);
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
if (currentPolicy != policy) {
StringAppendF(&result,
"DesiredDisplayConfigSpecs (Override): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz\n\n",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+ currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+ currentPolicy.appRequestRange.max);
}
mScheduler->dump(mAppConnectionHandle, result);
@@ -5916,9 +5918,11 @@
}
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
- ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]"
+ " expandedRange: [%.0f %.0f]",
+ currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+ currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+ currentPolicy.appRequestRange.max);
// TODO(b/140204874): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
@@ -5951,8 +5955,11 @@
}
status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) {
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken) {
@@ -5970,7 +5977,9 @@
return INVALID_OPERATION;
} else {
using Policy = scheduler::RefreshRateConfigs::Policy;
- const Policy policy{HwcConfigIndexType(defaultConfig), minRefreshRate, maxRefreshRate};
+ const Policy policy{HwcConfigIndexType(defaultConfig),
+ {primaryRefreshRateMin, primaryRefreshRateMax},
+ {appRequestRefreshRateMin, appRequestRefreshRateMax}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -5982,11 +5991,14 @@
status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
ATRACE_CALL();
- if (!displayToken || !outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) {
+ if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
+ !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
return BAD_VALUE;
}
@@ -6000,8 +6012,10 @@
scheduler::RefreshRateConfigs::Policy policy =
mRefreshRateConfigs->getDisplayManagerPolicy();
*outDefaultConfig = policy.defaultConfig.value();
- *outMinRefreshRate = policy.minRefreshRate;
- *outMaxRefreshRate = policy.maxRefreshRate;
+ *outPrimaryRefreshRateMin = policy.primaryRange.min;
+ *outPrimaryRefreshRateMax = policy.primaryRange.max;
+ *outAppRequestRefreshRateMin = policy.appRequestRange.min;
+ *outAppRequestRefreshRateMax = policy.appRequestRange.max;
return NO_ERROR;
} else if (display->isVirtual()) {
return INVALID_OPERATION;
@@ -6011,8 +6025,10 @@
*outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId);
auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod();
- *outMinRefreshRate = 1e9f / vsyncPeriod;
- *outMaxRefreshRate = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod;
return NO_ERROR;
}
}