Loading services/surfaceflinger/Scheduler/Scheduler.cpp +16 −62 Original line number Original line Diff line number Diff line Loading @@ -830,81 +830,35 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { using RankedRefreshRates = RefreshRateSelector::RankedFrameRates; using RankedRefreshRates = RefreshRateSelector::RankedFrameRates; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; // Tallies the score of a refresh rate across `displayCount` displays. struct RefreshRateTally { explicit RefreshRateTally(float score) : score(score) {} float score; size_t displayCount = 1; }; // Chosen to exceed a typical number of refresh rates across displays. constexpr size_t kStaticCapacity = 8; ftl::SmallMap<Fps, RefreshRateTally, kStaticCapacity, FpsApproxEqual> refreshRateTallies; const auto globalSignals = makeGlobalSignals(); const auto globalSignals = makeGlobalSignals(); Fps pacesetterFps; for (const auto& [id, display] : mDisplays) { for (const auto& [id, display] : mDisplays) { auto rankedFrameRates = auto rankedFrameRates = display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals); globalSignals); if (id == *mPacesetterDisplayId) { for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) { pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps; const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score); if (!inserted) { auto& tally = it->second; tally.score += score; tally.displayCount++; } } } perDisplayRanking.push_back(std::move(rankedFrameRates)); perDisplayRanking.push_back(std::move(rankedFrameRates)); } } auto maxScoreIt = refreshRateTallies.cbegin(); // Find the first refresh rate common to all displays. while (maxScoreIt != refreshRateTallies.cend() && maxScoreIt->second.displayCount != mDisplays.size()) { ++maxScoreIt; } if (maxScoreIt != refreshRateTallies.cend()) { // Choose the highest refresh rate common to all displays, if any. for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) { const auto [fps, tally] = *it; if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) { maxScoreIt = it; } } } const std::optional<Fps> chosenFps = maxScoreIt != refreshRateTallies.cend() ? std::make_optional(maxScoreIt->first) : std::nullopt; DisplayModeChoiceMap modeChoices; DisplayModeChoiceMap modeChoices; using fps_approx_ops::operator==; using fps_approx_ops::operator==; for (auto& [ranking, signals] : perDisplayRanking) { for (auto& [rankings, signals] : perDisplayRanking) { if (!chosenFps) { const auto chosenFrameRateMode = const auto& [frameRateMode, _] = ranking.front(); ftl::find_if(rankings, modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(), [&](const auto& ranking) { DisplayModeChoice{frameRateMode, signals}); return ranking.frameRateMode.fps == pacesetterFps; continue; }) } .transform([](const auto& scoredFrameRate) { return scoredFrameRate.get().frameRateMode; }) .value_or(rankings.front().frameRateMode); for (auto& [frameRateMode, _] : ranking) { modeChoices.try_emplace(chosenFrameRateMode.modePtr->getPhysicalDisplayId(), if (frameRateMode.fps == *chosenFps) { DisplayModeChoice{chosenFrameRateMode, signals}); modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(), DisplayModeChoice{frameRateMode, signals}); break; } } } } return modeChoices; return modeChoices; } } Loading services/surfaceflinger/tests/unittests/SchedulerTest.cpp +22 −1 Original line number Original line Diff line number Diff line Loading @@ -359,7 +359,8 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { EXPECT_EQ(expectedChoices, actualChoices); EXPECT_EQ(expectedChoices, actualChoices); } } { { // This display does not support 120 Hz, so we should choose 60 Hz despite the touch signal. // The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120 // Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz. mScheduler mScheduler ->registerDisplay(kDisplayId3, ->registerDisplay(kDisplayId3, std::make_shared<RefreshRateSelector>(kDisplay3Modes, std::make_shared<RefreshRateSelector>(kDisplay3Modes, Loading @@ -369,6 +370,26 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { mScheduler->replaceTouchTimer(10); mScheduler->replaceTouchTimer(10); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); expectedChoices = ftl::init::map< const PhysicalDisplayId&, DisplayModeChoice>(kDisplayId1, FrameRateMode{120_Hz, kDisplay1Mode120}, globalSignals)(kDisplayId2, FrameRateMode{120_Hz, kDisplay2Mode120}, globalSignals)(kDisplayId3, FrameRateMode{60_Hz, kDisplay3Mode60}, globalSignals); const auto actualChoices = mScheduler->chooseDisplayModes(); EXPECT_EQ(expectedChoices, actualChoices); } { // We should choose 60Hz despite the touch signal as pacesetter only supports 60Hz mScheduler->setPacesetterDisplay(kDisplayId3); const GlobalSignals globalSignals = {.touch = true}; mScheduler->replaceTouchTimer(10); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); expectedChoices = ftl::init::map< expectedChoices = ftl::init::map< const PhysicalDisplayId&, const PhysicalDisplayId&, DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60}, DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60}, Loading Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +16 −62 Original line number Original line Diff line number Diff line Loading @@ -830,81 +830,35 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { using RankedRefreshRates = RefreshRateSelector::RankedFrameRates; using RankedRefreshRates = RefreshRateSelector::RankedFrameRates; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; // Tallies the score of a refresh rate across `displayCount` displays. struct RefreshRateTally { explicit RefreshRateTally(float score) : score(score) {} float score; size_t displayCount = 1; }; // Chosen to exceed a typical number of refresh rates across displays. constexpr size_t kStaticCapacity = 8; ftl::SmallMap<Fps, RefreshRateTally, kStaticCapacity, FpsApproxEqual> refreshRateTallies; const auto globalSignals = makeGlobalSignals(); const auto globalSignals = makeGlobalSignals(); Fps pacesetterFps; for (const auto& [id, display] : mDisplays) { for (const auto& [id, display] : mDisplays) { auto rankedFrameRates = auto rankedFrameRates = display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals); globalSignals); if (id == *mPacesetterDisplayId) { for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) { pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps; const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score); if (!inserted) { auto& tally = it->second; tally.score += score; tally.displayCount++; } } } perDisplayRanking.push_back(std::move(rankedFrameRates)); perDisplayRanking.push_back(std::move(rankedFrameRates)); } } auto maxScoreIt = refreshRateTallies.cbegin(); // Find the first refresh rate common to all displays. while (maxScoreIt != refreshRateTallies.cend() && maxScoreIt->second.displayCount != mDisplays.size()) { ++maxScoreIt; } if (maxScoreIt != refreshRateTallies.cend()) { // Choose the highest refresh rate common to all displays, if any. for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) { const auto [fps, tally] = *it; if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) { maxScoreIt = it; } } } const std::optional<Fps> chosenFps = maxScoreIt != refreshRateTallies.cend() ? std::make_optional(maxScoreIt->first) : std::nullopt; DisplayModeChoiceMap modeChoices; DisplayModeChoiceMap modeChoices; using fps_approx_ops::operator==; using fps_approx_ops::operator==; for (auto& [ranking, signals] : perDisplayRanking) { for (auto& [rankings, signals] : perDisplayRanking) { if (!chosenFps) { const auto chosenFrameRateMode = const auto& [frameRateMode, _] = ranking.front(); ftl::find_if(rankings, modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(), [&](const auto& ranking) { DisplayModeChoice{frameRateMode, signals}); return ranking.frameRateMode.fps == pacesetterFps; continue; }) } .transform([](const auto& scoredFrameRate) { return scoredFrameRate.get().frameRateMode; }) .value_or(rankings.front().frameRateMode); for (auto& [frameRateMode, _] : ranking) { modeChoices.try_emplace(chosenFrameRateMode.modePtr->getPhysicalDisplayId(), if (frameRateMode.fps == *chosenFps) { DisplayModeChoice{chosenFrameRateMode, signals}); modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(), DisplayModeChoice{frameRateMode, signals}); break; } } } } return modeChoices; return modeChoices; } } Loading
services/surfaceflinger/tests/unittests/SchedulerTest.cpp +22 −1 Original line number Original line Diff line number Diff line Loading @@ -359,7 +359,8 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { EXPECT_EQ(expectedChoices, actualChoices); EXPECT_EQ(expectedChoices, actualChoices); } } { { // This display does not support 120 Hz, so we should choose 60 Hz despite the touch signal. // The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120 // Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz. mScheduler mScheduler ->registerDisplay(kDisplayId3, ->registerDisplay(kDisplayId3, std::make_shared<RefreshRateSelector>(kDisplay3Modes, std::make_shared<RefreshRateSelector>(kDisplay3Modes, Loading @@ -369,6 +370,26 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { mScheduler->replaceTouchTimer(10); mScheduler->replaceTouchTimer(10); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); expectedChoices = ftl::init::map< const PhysicalDisplayId&, DisplayModeChoice>(kDisplayId1, FrameRateMode{120_Hz, kDisplay1Mode120}, globalSignals)(kDisplayId2, FrameRateMode{120_Hz, kDisplay2Mode120}, globalSignals)(kDisplayId3, FrameRateMode{60_Hz, kDisplay3Mode60}, globalSignals); const auto actualChoices = mScheduler->chooseDisplayModes(); EXPECT_EQ(expectedChoices, actualChoices); } { // We should choose 60Hz despite the touch signal as pacesetter only supports 60Hz mScheduler->setPacesetterDisplay(kDisplayId3); const GlobalSignals globalSignals = {.touch = true}; mScheduler->replaceTouchTimer(10); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); expectedChoices = ftl::init::map< expectedChoices = ftl::init::map< const PhysicalDisplayId&, const PhysicalDisplayId&, DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60}, DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60}, Loading