NoPreference frame rate category is no-op
Change NoPreference frame rate category to behave like a no-op.
When all layers are NoPreference votes, the current frame rate should be
used, instead of choosing Min.
This also allows idle timer to trigger.
Bug: 328084518
Test: atest libsurfaceflinger_unittest
Test: Manual sysui jank suit
Change-Id: Ibe25ab8427367c5b86a1eaf0ed43434b6d270691
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index ad59f1a..56c29e2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -506,6 +506,8 @@
}
int noVoteLayers = 0;
+ // Layers that prefer the same mode ("no-op").
+ int noPreferenceLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
int explicitDefaultVoteLayers = 0;
@@ -549,10 +551,7 @@
explicitCategoryVoteLayers++;
}
if (layer.frameRateCategory == FrameRateCategory::NoPreference) {
- // Count this layer for Min vote as well. The explicit vote avoids
- // touch boost and idle for choosing a category, while Min vote is for correct
- // behavior when all layers are Min or no vote.
- minVoteLayers++;
+ noPreferenceLayers++;
}
break;
case LayerVoteType::Heuristic:
@@ -612,6 +611,16 @@
return {ranking, kNoSignals};
}
+ // If all layers are category NoPreference, use the current config.
+ if (noPreferenceLayers + noVoteLayers == layers.size()) {
+ ALOGV("All layers NoPreference");
+ const auto ascendingWithPreferred =
+ rankFrameRates(anchorGroup, RefreshRateOrder::Ascending, activeMode.getId());
+ ATRACE_FORMAT_INSTANT("%s (All layers NoPreference)",
+ to_string(ascendingWithPreferred.front().frameRateMode.fps).c_str());
+ return {ascendingWithPreferred, kNoSignals};
+ }
+
const bool smoothSwitchOnly = categorySmoothSwitchOnlyLayers > 0;
const DisplayModeId activeModeId = activeMode.getId();
@@ -643,6 +652,7 @@
ftl::enum_string(layer.frameRateCategory).c_str());
if (layer.isNoVote() || layer.frameRateCategory == FrameRateCategory::NoPreference ||
layer.vote == LayerVoteType::Min) {
+ ALOGV("%s scoring skipped due to vote", formatLayerInfo(layer, layer.weight).c_str());
continue;
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index fe0e3d1..a155f5d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -295,6 +295,12 @@
<< "Did not get expected frame rate for frameRate="
<< to_string(testCase.desiredFrameRate)
<< " category=" << ftl::enum_string(testCase.frameRateCategory);
+ EXPECT_EQ(testCase.expectedModeId,
+ selector.getBestFrameRateMode(layers).modePtr->getId())
+ << "Did not get expected DisplayModeId for modeId="
+ << ftl::to_underlying(testCase.expectedModeId)
+ << " frameRate=" << to_string(testCase.desiredFrameRate)
+ << " category=" << ftl::enum_string(testCase.frameRateCategory);
}
}
};
@@ -1534,7 +1540,7 @@
{0_Hz, FrameRateCategory::High, 90_Hz},
{0_Hz, FrameRateCategory::Normal, 60_Hz},
{0_Hz, FrameRateCategory::Low, 30_Hz},
- {0_Hz, FrameRateCategory::NoPreference, 30_Hz},
+ {0_Hz, FrameRateCategory::NoPreference, 60_Hz},
// Cases that have both desired frame rate and frame rate category requirements.
{24_Hz, FrameRateCategory::High, 120_Hz},
@@ -1591,6 +1597,7 @@
// Expected result
Fps expectedFrameRate = 0_Hz;
+ DisplayModeId expectedModeId = kModeId90;
};
testFrameRateCategoryWithMultipleLayers(
@@ -1605,7 +1612,7 @@
testFrameRateCategoryWithMultipleLayers(
std::initializer_list<Case>{
- {0_Hz, FrameRateCategory::Normal, 60_Hz},
+ {0_Hz, FrameRateCategory::Normal, 60_Hz, kModeId60},
{0_Hz, FrameRateCategory::High, 90_Hz},
{0_Hz, FrameRateCategory::NoPreference, 90_Hz},
},
@@ -1614,18 +1621,18 @@
testFrameRateCategoryWithMultipleLayers(
std::initializer_list<Case>{
{30_Hz, FrameRateCategory::High, 90_Hz},
- {24_Hz, FrameRateCategory::High, 120_Hz},
- {12_Hz, FrameRateCategory::Normal, 120_Hz},
- {30_Hz, FrameRateCategory::NoPreference, 120_Hz},
+ {24_Hz, FrameRateCategory::High, 120_Hz, kModeId120},
+ {12_Hz, FrameRateCategory::Normal, 120_Hz, kModeId120},
+ {30_Hz, FrameRateCategory::NoPreference, 120_Hz, kModeId120},
},
selector);
testFrameRateCategoryWithMultipleLayers(
std::initializer_list<Case>{
- {24_Hz, FrameRateCategory::Default, 120_Hz},
- {30_Hz, FrameRateCategory::Default, 120_Hz},
- {120_Hz, FrameRateCategory::Default, 120_Hz},
+ {24_Hz, FrameRateCategory::Default, 120_Hz, kModeId120},
+ {30_Hz, FrameRateCategory::Default, 120_Hz, kModeId120},
+ {120_Hz, FrameRateCategory::Default, 120_Hz, kModeId120},
},
selector);
}
@@ -1640,6 +1647,7 @@
// Expected result
Fps expectedFrameRate = 0_Hz;
+ DisplayModeId expectedModeId = kModeId120;
};
testFrameRateCategoryWithMultipleLayers(std::initializer_list<
@@ -1970,6 +1978,122 @@
}
TEST_P(RefreshRateSelectorTest,
+ getBestFrameRateMode_withFrameRateCategory_idleTimer_60_120_nonVrr) {
+ SET_FLAG_FOR_TEST(flags::vrr_config, false);
+ using KernelIdleTimerAction = RefreshRateSelector::KernelIdleTimerAction;
+ struct LayerArg {
+ // Params
+ FrameRateCategory frameRateCategory = FrameRateCategory::Default;
+ LayerVoteType voteType = LayerVoteType::ExplicitDefault;
+
+ // Expected result
+ Fps expectedFrameRate = 0_Hz;
+ DisplayModeId expectedModeId = kModeId60;
+ };
+
+ const auto runTest = [&](const TestableRefreshRateSelector& selector,
+ const std::initializer_list<LayerArg>& layerArgs,
+ const RefreshRateSelector::GlobalSignals& signals) {
+ std::vector<LayerRequirement> layers;
+ for (auto testCase : layerArgs) {
+ ALOGI("**** %s: Testing frameRateCategory=%s", __func__,
+ ftl::enum_string(testCase.frameRateCategory).c_str());
+
+ if (testCase.frameRateCategory != FrameRateCategory::Default) {
+ std::stringstream ss;
+ ss << "ExplicitCategory (" << ftl::enum_string(testCase.frameRateCategory) << ")";
+ LayerRequirement layer = {.name = ss.str(),
+ .vote = LayerVoteType::ExplicitCategory,
+ .frameRateCategory = testCase.frameRateCategory,
+ .weight = 1.f};
+ layers.push_back(layer);
+ }
+
+ if (testCase.voteType != LayerVoteType::ExplicitDefault) {
+ std::stringstream ss;
+ ss << ftl::enum_string(testCase.voteType);
+ LayerRequirement layer = {.name = ss.str(),
+ .vote = testCase.voteType,
+ .weight = 1.f};
+ layers.push_back(layer);
+ }
+
+ EXPECT_EQ(testCase.expectedFrameRate,
+ selector.getBestFrameRateMode(layers, signals).modePtr->getPeakFps())
+ << "Did not get expected frame rate for"
+ << " category=" << ftl::enum_string(testCase.frameRateCategory);
+ EXPECT_EQ(testCase.expectedModeId,
+ selector.getBestFrameRateMode(layers, signals).modePtr->getId())
+ << "Did not get expected DisplayModeId for modeId="
+ << ftl::to_underlying(testCase.expectedModeId)
+ << " category=" << ftl::enum_string(testCase.frameRateCategory);
+ }
+ };
+
+ {
+ // IdleTimer not configured
+ auto selector = createSelector(makeModes(kMode60, kMode120), kModeId120);
+ ASSERT_EQ(0ms, selector.getIdleTimerTimeout());
+
+ runTest(selector,
+ std::initializer_list<LayerArg>{
+ // Rate does not change due to NoPreference.
+ {.frameRateCategory = FrameRateCategory::NoPreference,
+ .expectedFrameRate = 120_Hz,
+ .expectedModeId = kModeId120},
+ {.voteType = LayerVoteType::NoVote,
+ .expectedFrameRate = 120_Hz,
+ .expectedModeId = kModeId120},
+ {.frameRateCategory = FrameRateCategory::NoPreference,
+ .expectedFrameRate = 120_Hz,
+ .expectedModeId = kModeId120},
+ },
+ {.idle = false});
+ }
+
+ // IdleTimer configured
+ constexpr std::chrono::milliseconds kIdleTimerTimeoutMs = 10ms;
+ auto selector = createSelector(makeModes(kMode60, kMode120), kModeId120,
+ Config{
+ .idleTimerTimeout = kIdleTimerTimeoutMs,
+ });
+ ASSERT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction());
+ ASSERT_EQ(kIdleTimerTimeoutMs, selector.getIdleTimerTimeout());
+ runTest(selector,
+ std::initializer_list<LayerArg>{
+ // Rate won't change immediately and will stay 120 due to NoPreference, as
+ // idle timer did not timeout yet.
+ {.frameRateCategory = FrameRateCategory::NoPreference,
+ .expectedFrameRate = 120_Hz,
+ .expectedModeId = kModeId120},
+ {.voteType = LayerVoteType::NoVote,
+ .expectedFrameRate = 120_Hz,
+ .expectedModeId = kModeId120},
+ {.frameRateCategory = FrameRateCategory::NoPreference,
+ .expectedFrameRate = 120_Hz,
+ .expectedModeId = kModeId120},
+ },
+ {.idle = false});
+
+ // Idle timer is triggered using GlobalSignals.
+ ASSERT_EQ(KernelIdleTimerAction::TurnOn, selector.getIdleTimerAction());
+ ASSERT_EQ(kIdleTimerTimeoutMs, selector.getIdleTimerTimeout());
+ runTest(selector,
+ std::initializer_list<LayerArg>{
+ {.frameRateCategory = FrameRateCategory::NoPreference,
+ .expectedFrameRate = 60_Hz,
+ .expectedModeId = kModeId60},
+ {.voteType = LayerVoteType::NoVote,
+ .expectedFrameRate = 60_Hz,
+ .expectedModeId = kModeId60},
+ {.frameRateCategory = FrameRateCategory::NoPreference,
+ .expectedFrameRate = 60_Hz,
+ .expectedModeId = kModeId60},
+ },
+ {.idle = true});
+}
+
+TEST_P(RefreshRateSelectorTest,
getBestFrameRateMode_withFrameRateCategory_smoothSwitchOnly_60_120_nonVrr) {
if (GetParam() != Config::FrameRateOverride::Enabled) {
return;
@@ -1992,8 +2116,7 @@
const std::initializer_list<Case> testCases = {
// These layers may switch modes because smoothSwitchOnly=false.
{FrameRateCategory::Default, false, 120_Hz, kModeId120},
- // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate.
- {FrameRateCategory::NoPreference, false, 60_Hz, kModeId60},
+ {FrameRateCategory::NoPreference, false, 120_Hz, kModeId120},
{FrameRateCategory::Low, false, 30_Hz, kModeId60},
{FrameRateCategory::Normal, false, 60_Hz, kModeId60},
{FrameRateCategory::High, false, 120_Hz, kModeId120},