Loading services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +14 −4 Original line number Diff line number Diff line Loading @@ -506,6 +506,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi } int noVoteLayers = 0; // Layers that prefer the same mode ("no-op"). int noPreferenceLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; int explicitDefaultVoteLayers = 0; Loading Loading @@ -549,10 +551,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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: Loading Loading @@ -612,6 +611,16 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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(); Loading Loading @@ -643,6 +652,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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; } Loading services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +133 −10 Original line number Diff line number Diff line Loading @@ -295,6 +295,12 @@ protected: << "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); } } }; Loading Loading @@ -1534,7 +1540,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_30_60 {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}, Loading Loading @@ -1591,6 +1597,7 @@ TEST_P(RefreshRateSelectorTest, // Expected result Fps expectedFrameRate = 0_Hz; DisplayModeId expectedModeId = kModeId90; }; testFrameRateCategoryWithMultipleLayers( Loading @@ -1605,7 +1612,7 @@ TEST_P(RefreshRateSelectorTest, 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}, }, Loading @@ -1614,18 +1621,18 @@ TEST_P(RefreshRateSelectorTest, 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); } Loading @@ -1640,6 +1647,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategoryMultiL // Expected result Fps expectedFrameRate = 0_Hz; DisplayModeId expectedModeId = kModeId120; }; testFrameRateCategoryWithMultipleLayers(std::initializer_list< Loading Loading @@ -1969,6 +1977,122 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); } 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) { Loading @@ -1992,8 +2116,7 @@ TEST_P(RefreshRateSelectorTest, 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}, Loading Loading
services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +14 −4 Original line number Diff line number Diff line Loading @@ -506,6 +506,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi } int noVoteLayers = 0; // Layers that prefer the same mode ("no-op"). int noPreferenceLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; int explicitDefaultVoteLayers = 0; Loading Loading @@ -549,10 +551,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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: Loading Loading @@ -612,6 +611,16 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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(); Loading Loading @@ -643,6 +652,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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; } Loading
services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +133 −10 Original line number Diff line number Diff line Loading @@ -295,6 +295,12 @@ protected: << "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); } } }; Loading Loading @@ -1534,7 +1540,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_30_60 {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}, Loading Loading @@ -1591,6 +1597,7 @@ TEST_P(RefreshRateSelectorTest, // Expected result Fps expectedFrameRate = 0_Hz; DisplayModeId expectedModeId = kModeId90; }; testFrameRateCategoryWithMultipleLayers( Loading @@ -1605,7 +1612,7 @@ TEST_P(RefreshRateSelectorTest, 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}, }, Loading @@ -1614,18 +1621,18 @@ TEST_P(RefreshRateSelectorTest, 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); } Loading @@ -1640,6 +1647,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategoryMultiL // Expected result Fps expectedFrameRate = 0_Hz; DisplayModeId expectedModeId = kModeId120; }; testFrameRateCategoryWithMultipleLayers(std::initializer_list< Loading Loading @@ -1969,6 +1977,122 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); } 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) { Loading @@ -1992,8 +2116,7 @@ TEST_P(RefreshRateSelectorTest, 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}, Loading