Loading services/surfaceflinger/Scheduler/Scheduler.cpp +29 −8 Original line number Diff line number Diff line Loading @@ -162,6 +162,7 @@ PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked( // The first display should be the new pacesetter if none of the displays are powered on. const auto& [firstDisplayId, firstDisplay] = *mDisplays.begin(); PhysicalDisplayId newPacesetterId = firstDisplayId; ui::DisplayConnectionType newPacesetterConnectionType = firstDisplay.connectionType; // Only assigning the actual refresh rate if the first display is powered on ensures that any // other powered-on display will take over the new pacesetter designation regardless of its // refresh rate. Loading @@ -179,24 +180,44 @@ PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked( const Fps displayVsyncRate = display.selectorPtr->getActiveMode().modePtr->getVsyncRate(); if (isStrictlyLess(newPacesetterVsyncRate, displayVsyncRate)) { newPacesetterId = id; newPacesetterConnectionType = display.connectionType; newPacesetterVsyncRate = displayVsyncRate; } } // The slack in the difference between refresh rate difference to consider them roughly equal // for pacesetter selection purposes. E.g. 59.98 and 60.02Hz Should be considered roughly equal. const auto isVsyncRateApproxEqual = [&](const Display& display, Fps otherFps) -> bool { constexpr float kRefreshRateEpsilon = 0.1f; const Fps displayVsyncRate = display.selectorPtr->getActiveMode().modePtr->getVsyncRate(); return std::abs(displayVsyncRate.getValue() - otherFps.getValue()) < kRefreshRateEpsilon; }; // If the current pacesetter display is powered on and its refresh rate is not too far off from // the newly selected pacesetter display, prefer to keep the current one to avoid churn. if (const auto pacesetterOpt = pacesetterDisplayLocked()) { const auto& pacesetter = pacesetterOpt->get(); if (pacesetter.powerMode == hal::PowerMode::ON) { const Fps currentPacesetterVsyncRate = if (isVsyncRateApproxEqual(pacesetter, newPacesetterVsyncRate)) { newPacesetterId = pacesetter.displayId; newPacesetterConnectionType = pacesetter.connectionType; newPacesetterVsyncRate = pacesetter.selectorPtr->getActiveMode().modePtr->getVsyncRate(); const float rateDiff = newPacesetterVsyncRate.getValue() - currentPacesetterVsyncRate.getValue(); constexpr float kRefreshRateEpsilon = 0.1f; } } } if (rateDiff < kRefreshRateEpsilon) { newPacesetterId = pacesetter.displayId; newPacesetterVsyncRate = currentPacesetterVsyncRate; // Prefer external displays as pacesetter, as it is more likely the external display will be the // user's main display. if (newPacesetterConnectionType != ui::DisplayConnectionType::External) { for (const auto& [id, display] : mDisplays) { if (display.powerMode != hal::PowerMode::ON || display.connectionType != ui::DisplayConnectionType::External) { continue; } if (isVsyncRateApproxEqual(display, newPacesetterVsyncRate)) { return id; } } } Loading services/surfaceflinger/tests/unittests/SchedulerTest.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -1539,6 +1539,26 @@ TEST_F(SelectPacesetterDisplayTest, TwoDisplaysWithinEpsilon) FTL_FAKE_GUARD(kMa EXPECT_EQ(mScheduler->pacesetterDisplayId(), kDisplayId1); } TEST_F(SelectPacesetterDisplayTest, SameRefreshRateOneInternalOneExternal) FTL_FAKE_GUARD(kMainThreadContext) { SET_FLAG_FOR_TEST(flags::pacesetter_selection, true); constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1; mScheduler->registerDisplay(kDisplayId1, ui::DisplayConnectionType::Internal, std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode60->getId()), kActiveDisplayId); mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON); auto selector2 = std::make_shared<RefreshRateSelector>(kDisplay2Modes, kDisplay2Mode60->getId()); mScheduler->registerDisplay(kDisplayId2, ui::DisplayConnectionType::External, selector2, kActiveDisplayId); mScheduler->setDisplayPowerMode(kDisplayId2, hal::PowerMode::ON); EXPECT_EQ(mScheduler->pacesetterDisplayId(), kDisplayId2); } TEST_F(SchedulerTest, selectorPtrForLayerStack) FTL_FAKE_GUARD(kMainThreadContext) { SET_FLAG_FOR_TEST(flags::follower_arbitrary_refresh_rate_selection, true); Loading Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +29 −8 Original line number Diff line number Diff line Loading @@ -162,6 +162,7 @@ PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked( // The first display should be the new pacesetter if none of the displays are powered on. const auto& [firstDisplayId, firstDisplay] = *mDisplays.begin(); PhysicalDisplayId newPacesetterId = firstDisplayId; ui::DisplayConnectionType newPacesetterConnectionType = firstDisplay.connectionType; // Only assigning the actual refresh rate if the first display is powered on ensures that any // other powered-on display will take over the new pacesetter designation regardless of its // refresh rate. Loading @@ -179,24 +180,44 @@ PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked( const Fps displayVsyncRate = display.selectorPtr->getActiveMode().modePtr->getVsyncRate(); if (isStrictlyLess(newPacesetterVsyncRate, displayVsyncRate)) { newPacesetterId = id; newPacesetterConnectionType = display.connectionType; newPacesetterVsyncRate = displayVsyncRate; } } // The slack in the difference between refresh rate difference to consider them roughly equal // for pacesetter selection purposes. E.g. 59.98 and 60.02Hz Should be considered roughly equal. const auto isVsyncRateApproxEqual = [&](const Display& display, Fps otherFps) -> bool { constexpr float kRefreshRateEpsilon = 0.1f; const Fps displayVsyncRate = display.selectorPtr->getActiveMode().modePtr->getVsyncRate(); return std::abs(displayVsyncRate.getValue() - otherFps.getValue()) < kRefreshRateEpsilon; }; // If the current pacesetter display is powered on and its refresh rate is not too far off from // the newly selected pacesetter display, prefer to keep the current one to avoid churn. if (const auto pacesetterOpt = pacesetterDisplayLocked()) { const auto& pacesetter = pacesetterOpt->get(); if (pacesetter.powerMode == hal::PowerMode::ON) { const Fps currentPacesetterVsyncRate = if (isVsyncRateApproxEqual(pacesetter, newPacesetterVsyncRate)) { newPacesetterId = pacesetter.displayId; newPacesetterConnectionType = pacesetter.connectionType; newPacesetterVsyncRate = pacesetter.selectorPtr->getActiveMode().modePtr->getVsyncRate(); const float rateDiff = newPacesetterVsyncRate.getValue() - currentPacesetterVsyncRate.getValue(); constexpr float kRefreshRateEpsilon = 0.1f; } } } if (rateDiff < kRefreshRateEpsilon) { newPacesetterId = pacesetter.displayId; newPacesetterVsyncRate = currentPacesetterVsyncRate; // Prefer external displays as pacesetter, as it is more likely the external display will be the // user's main display. if (newPacesetterConnectionType != ui::DisplayConnectionType::External) { for (const auto& [id, display] : mDisplays) { if (display.powerMode != hal::PowerMode::ON || display.connectionType != ui::DisplayConnectionType::External) { continue; } if (isVsyncRateApproxEqual(display, newPacesetterVsyncRate)) { return id; } } } Loading
services/surfaceflinger/tests/unittests/SchedulerTest.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -1539,6 +1539,26 @@ TEST_F(SelectPacesetterDisplayTest, TwoDisplaysWithinEpsilon) FTL_FAKE_GUARD(kMa EXPECT_EQ(mScheduler->pacesetterDisplayId(), kDisplayId1); } TEST_F(SelectPacesetterDisplayTest, SameRefreshRateOneInternalOneExternal) FTL_FAKE_GUARD(kMainThreadContext) { SET_FLAG_FOR_TEST(flags::pacesetter_selection, true); constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1; mScheduler->registerDisplay(kDisplayId1, ui::DisplayConnectionType::Internal, std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode60->getId()), kActiveDisplayId); mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON); auto selector2 = std::make_shared<RefreshRateSelector>(kDisplay2Modes, kDisplay2Mode60->getId()); mScheduler->registerDisplay(kDisplayId2, ui::DisplayConnectionType::External, selector2, kActiveDisplayId); mScheduler->setDisplayPowerMode(kDisplayId2, hal::PowerMode::ON); EXPECT_EQ(mScheduler->pacesetterDisplayId(), kDisplayId2); } TEST_F(SchedulerTest, selectorPtrForLayerStack) FTL_FAKE_GUARD(kMainThreadContext) { SET_FLAG_FOR_TEST(flags::follower_arbitrary_refresh_rate_selection, true); Loading