Lock display refresh rate when primary range is a single rate.
When DMS enforces a fixed refresh rate to hide user-visible flickering,
we must respect that refresh rate to avoid unnecessary switches during
scenarios such as idle and touch boost.
We must still respect app votes when they explicitly provide a frame
rate.
Bug: 156315203
Test: Exoplayer
Test: Modified version of SetFrameRateTest to simulate 60hz video
Test: libsurfaceflinger_unittest
Change-Id: I5fe974ddaff30e2f02e381cb63e0a6418834fdb5
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 4a4f9c8..e181c12 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -128,15 +128,24 @@
}
}
+ const bool hasExplicitVoteLayers =
+ explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0;
+
// Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
// selected a refresh rate to see if we should apply touch boost.
- if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
+ if (touchActive && !hasExplicitVoteLayers) {
ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
if (touchConsidered) *touchConsidered = true;
return getMaxRefreshRateByPolicyLocked();
}
- if (!touchActive && idle) {
+ // If the primary range consists of a single refresh rate then we can only
+ // move out the of range if layers explicitly request a different refresh
+ // rate.
+ const Policy* policy = getCurrentPolicyLocked();
+ const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
+
+ if (!touchActive && idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
return getMinRefreshRateByPolicyLocked();
}
@@ -150,8 +159,6 @@
return getMinRefreshRateByPolicyLocked();
}
- const Policy* policy = getCurrentPolicyLocked();
-
// Find the best refresh rate based on score
std::vector<std::pair<const RefreshRate*, float>> scores;
scores.reserve(mAppRequestRefreshRates.size());
@@ -171,7 +178,8 @@
for (auto i = 0u; i < scores.size(); i++) {
bool inPrimaryRange =
scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
- if (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault &&
+ if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
+ layer.vote != LayerVoteType::ExplicitDefault &&
layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
// Only layers with explicit frame rate settings are allowed to score refresh rates
// outside the primary range.
@@ -263,11 +271,23 @@
? getBestRefreshRate(scores.rbegin(), scores.rend())
: getBestRefreshRate(scores.begin(), scores.end());
+ if (primaryRangeIsSingleRate) {
+ // If we never scored any layers, then choose the rate from the primary
+ // range instead of picking a random score from the app range.
+ if (std::all_of(scores.begin(), scores.end(),
+ [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
+ return getMaxRefreshRateByPolicyLocked();
+ } else {
+ return *bestRefreshRate;
+ }
+ }
+
// Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
// interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
// vote we should not change it if we get a touch event. Only apply touch boost if it will
// actually increase the refresh rate over the normal selection.
const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
+
if (touchActive && explicitDefaultVoteLayers == 0 &&
bestRefreshRate->fps < touchRefreshRate.fps) {
if (touchConsidered) *touchConsidered = true;
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 692f71f..c919e93 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1205,6 +1205,121 @@
}
}
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+ 0);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ bool touchConsidered = false;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true, /*idle*/ false,
+ &touchConsidered));
+ EXPECT_EQ(false, touchConsidered);
+
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz ExplicitDefault";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true, /*idle*/ false,
+ &touchConsidered));
+ EXPECT_EQ(false, touchConsidered);
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+ 0);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ bool touchConsidered = false;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.desiredRefreshRate = 90.0f;
+ lr.name = "90Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ true,
+ &touchConsidered));
+
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = 90.0f;
+ lr.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ true,
+ &touchConsidered));
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitLayers) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+ 0);
+
+ bool touchConsidered = false;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate({}, /*touchActive*/ false, /*idle*/ false,
+ &touchConsidered));
+ EXPECT_EQ(false, touchConsidered);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+ &touchConsidered));
+
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz ExplicitDefault";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+ &touchConsidered));
+
+ lr.vote = LayerVoteType::Heuristic;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+ &touchConsidered));
+
+ lr.vote = LayerVoteType::Max;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+ &touchConsidered));
+
+ lr.vote = LayerVoteType::Min;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Min";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+ &touchConsidered));
+}
+
TEST_F(RefreshRateConfigsTest, groupSwitching) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
@@ -1234,7 +1349,7 @@
TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(m60_90Device,
+ std::make_unique<RefreshRateConfigs>(m30_60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
@@ -1253,7 +1368,7 @@
};
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+ {HWC_CONFIG_ID_60, {30.f, 60.f}, {30.f, 90.f}}),
0);
bool touchConsidered;
EXPECT_EQ(HWC_CONFIG_ID_60,
@@ -1262,7 +1377,7 @@
&touchConsidered)
.getConfigId());
EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90.f));
EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));