diff options
6 files changed, 128 insertions, 70 deletions
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index ffd3463296..086842c696 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -474,21 +474,23 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay } auto RefreshRateSelector::getRankedFrameRates(const std::vector<LayerRequirement>& layers, - GlobalSignals signals) const -> RankedFrameRates { + GlobalSignals signals, Fps pacesetterFps) const + -> RankedFrameRates { + GetRankedFrameRatesCache cache{layers, signals, pacesetterFps}; + std::lock_guard lock(mLock); - if (mGetRankedFrameRatesCache && - mGetRankedFrameRatesCache->arguments == std::make_pair(layers, signals)) { + if (mGetRankedFrameRatesCache && mGetRankedFrameRatesCache->matches(cache)) { return mGetRankedFrameRatesCache->result; } - const auto result = getRankedFrameRatesLocked(layers, signals); - mGetRankedFrameRatesCache = GetRankedFrameRatesCache{{layers, signals}, result}; - return result; + cache.result = getRankedFrameRatesLocked(layers, signals, pacesetterFps); + mGetRankedFrameRatesCache = std::move(cache); + return mGetRankedFrameRatesCache->result; } auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers, - GlobalSignals signals) const + GlobalSignals signals, Fps pacesetterFps) const -> RankedFrameRates { using namespace fps_approx_ops; ATRACE_CALL(); @@ -496,6 +498,24 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi const auto& activeMode = *getActiveModeLocked().modePtr; + if (pacesetterFps.isValid()) { + ALOGV("Follower display"); + + const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Descending, + std::nullopt, [&](FrameRateMode mode) { + return mode.modePtr->getPeakFps() == pacesetterFps; + }); + + if (!ranking.empty()) { + ATRACE_FORMAT_INSTANT("%s (Follower display)", + to_string(ranking.front().frameRateMode.fps).c_str()); + + return {ranking, kNoSignals, pacesetterFps}; + } + + ALOGW("Follower display cannot follow the pacesetter"); + } + // Keep the display at max frame rate for the duration of powering on the display. if (signals.powerOnImminent) { ALOGV("Power On Imminent"); diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 6051e8935d..a5000636ce 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -233,14 +233,18 @@ public: struct RankedFrameRates { FrameRateRanking ranking; // Ordered by descending score. GlobalSignals consideredSignals; + Fps pacesetterFps; bool operator==(const RankedFrameRates& other) const { - return ranking == other.ranking && consideredSignals == other.consideredSignals; + return ranking == other.ranking && consideredSignals == other.consideredSignals && + isApproxEqual(pacesetterFps, other.pacesetterFps); } }; - RankedFrameRates getRankedFrameRates(const std::vector<LayerRequirement>&, GlobalSignals) const - EXCLUDES(mLock); + // If valid, `pacesetterFps` (used by follower displays) filters the ranking to modes matching + // that refresh rate. + RankedFrameRates getRankedFrameRates(const std::vector<LayerRequirement>&, GlobalSignals, + Fps pacesetterFps = {}) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); @@ -415,7 +419,8 @@ private: const FrameRateMode& getActiveModeLocked() const REQUIRES(mLock); RankedFrameRates getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers, - GlobalSignals signals) const REQUIRES(mLock); + GlobalSignals signals, Fps pacesetterFps) const + REQUIRES(mLock); // Returns number of display frames and remainder when dividing the layer refresh period by // display refresh period. @@ -534,8 +539,16 @@ private: Config::FrameRateOverride mFrameRateOverrideConfig; struct GetRankedFrameRatesCache { - std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments; + std::vector<LayerRequirement> layers; + GlobalSignals signals; + Fps pacesetterFps; + RankedFrameRates result; + + bool matches(const GetRankedFrameRatesCache& other) const { + return layers == other.layers && signals == other.signals && + isApproxEqual(pacesetterFps, other.pacesetterFps); + } }; mutable std::optional<GetRankedFrameRatesCache> mGetRankedFrameRatesCache GUARDED_BY(mLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 3f9168252b..3b47f4080f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -1146,38 +1146,31 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { ATRACE_CALL(); - using RankedRefreshRates = RefreshRateSelector::RankedFrameRates; - ui::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking; + DisplayModeChoiceMap modeChoices; const auto globalSignals = makeGlobalSignals(); - Fps pacesetterFps; + + const Fps pacesetterFps = [&]() REQUIRES(mPolicyLock, mDisplayLock, kMainThreadContext) { + auto rankedFrameRates = + pacesetterSelectorPtrLocked()->getRankedFrameRates(mPolicy.contentRequirements, + globalSignals); + + const Fps pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps; + + modeChoices.try_emplace(*mPacesetterDisplayId, + DisplayModeChoice::from(std::move(rankedFrameRates))); + return pacesetterFps; + }(); for (const auto& [id, display] : mDisplays) { + if (id == *mPacesetterDisplayId) continue; + auto rankedFrameRates = - display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, - globalSignals); - if (id == *mPacesetterDisplayId) { - pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps; - } - perDisplayRanking.push_back(std::move(rankedFrameRates)); - } + display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals, + pacesetterFps); - DisplayModeChoiceMap modeChoices; - using fps_approx_ops::operator==; - - for (auto& [rankings, signals] : perDisplayRanking) { - const auto chosenFrameRateMode = - ftl::find_if(rankings, - [&](const auto& ranking) { - return ranking.frameRateMode.fps == pacesetterFps; - }) - .transform([](const auto& scoredFrameRate) { - return scoredFrameRate.get().frameRateMode; - }) - .value_or(rankings.front().frameRateMode); - - modeChoices.try_emplace(chosenFrameRateMode.modePtr->getPhysicalDisplayId(), - DisplayModeChoice{chosenFrameRateMode, signals}); + modeChoices.try_emplace(id, DisplayModeChoice::from(std::move(rankedFrameRates))); } + return modeChoices; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 09f75fdaca..2ed3d4c3c4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -402,6 +402,11 @@ private: DisplayModeChoice(FrameRateMode mode, GlobalSignals consideredSignals) : mode(std::move(mode)), consideredSignals(consideredSignals) {} + static DisplayModeChoice from(RefreshRateSelector::RankedFrameRates rankedFrameRates) { + return {rankedFrameRates.ranking.front().frameRateMode, + rankedFrameRates.consideredSignals}; + } + FrameRateMode mode; GlobalSignals consideredSignals; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index 0a6e3054dd..b4460538df 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -103,8 +103,9 @@ struct TestableRefreshRateSelector : RefreshRateSelector { auto& mutableGetRankedRefreshRatesCache() { return mGetRankedFrameRatesCache; } auto getRankedFrameRates(const std::vector<LayerRequirement>& layers, - GlobalSignals signals = {}) const { - const auto result = RefreshRateSelector::getRankedFrameRates(layers, signals); + GlobalSignals signals = {}, Fps pacesetterFps = {}) const { + const auto result = + RefreshRateSelector::getRankedFrameRates(layers, signals, pacesetterFps); EXPECT_TRUE(std::is_sorted(result.ranking.begin(), result.ranking.end(), ScoredFrameRate::DescendingScore{})); @@ -114,8 +115,8 @@ struct TestableRefreshRateSelector : RefreshRateSelector { auto getRankedRefreshRatesAsPair(const std::vector<LayerRequirement>& layers, GlobalSignals signals) const { - const auto [ranking, consideredSignals] = getRankedFrameRates(layers, signals); - return std::make_pair(ranking, consideredSignals); + const auto result = getRankedFrameRates(layers, signals); + return std::make_pair(result.ranking, result.consideredSignals); } FrameRateMode getBestFrameRateMode(const std::vector<LayerRequirement>& layers = {}, @@ -1343,7 +1344,7 @@ TEST_P(RefreshRateSelectorTest, getMaxRefreshRatesByPolicyOutsideTheGroup) { TEST_P(RefreshRateSelectorTest, powerOnImminentConsidered) { auto selector = createSelector(kModes_60_90, kModeId60); - auto [refreshRates, signals] = selector.getRankedFrameRates({}, {}); + auto [refreshRates, signals, _] = selector.getRankedFrameRates({}, {}); EXPECT_FALSE(signals.powerOnImminent); auto expectedRefreshRates = []() -> std::vector<FrameRateMode> { @@ -1427,10 +1428,32 @@ TEST_P(RefreshRateSelectorTest, powerOnImminentConsidered) { } } +TEST_P(RefreshRateSelectorTest, pacesetterConsidered) { + auto selector = createSelector(kModes_60_90, kModeId60); + constexpr RefreshRateSelector::GlobalSignals kNoSignals; + + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].vote = LayerVoteType::Min; + + // The pacesetterFps takes precedence over the LayerRequirement. + { + const auto result = selector.getRankedFrameRates(layers, {}, 90_Hz); + EXPECT_EQ(kMode90, result.ranking.front().frameRateMode.modePtr); + EXPECT_EQ(kNoSignals, result.consideredSignals); + } + + // The pacesetterFps takes precedence over GlobalSignals. + { + const auto result = selector.getRankedFrameRates(layers, {.touch = true}, 60_Hz); + EXPECT_EQ(kMode60, result.ranking.front().frameRateMode.modePtr); + EXPECT_EQ(kNoSignals, result.consideredSignals); + } +} + TEST_P(RefreshRateSelectorTest, touchConsidered) { auto selector = createSelector(kModes_60_90, kModeId60); - auto [_, signals] = selector.getRankedFrameRates({}, {}); + auto signals = selector.getRankedFrameRates({}, {}).consideredSignals; EXPECT_FALSE(signals.touch); std::tie(std::ignore, signals) = selector.getRankedRefreshRatesAsPair({}, {.touch = true}); @@ -1964,7 +1987,7 @@ TEST_P(RefreshRateSelectorTest, lr.name = "60Hz ExplicitDefault"; lr.focused = true; - const auto [rankedFrameRate, signals] = + const auto [rankedFrameRate, signals, _] = selector.getRankedFrameRates(layers, {.touch = true, .idle = true}); EXPECT_EQ(rankedFrameRate.begin()->frameRateMode.modePtr, kMode60); @@ -2188,7 +2211,7 @@ TEST_P(RefreshRateSelectorTest, EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId90, {k90, k90}, {k60_90, k60_90}})); - const auto [ranking, signals] = selector.getRankedFrameRates({}, {}); + const auto [ranking, signals, _] = selector.getRankedFrameRates({}, {}); EXPECT_EQ(ranking.front().frameRateMode.modePtr, kMode90); EXPECT_FALSE(signals.touch); @@ -2572,7 +2595,7 @@ TEST_P(RefreshRateSelectorTest, idle) { layers[0].vote = voteType; layers[0].desiredRefreshRate = 90_Hz; - const auto [ranking, signals] = + const auto [ranking, signals, _] = selector.getRankedFrameRates(layers, {.touch = touchActive, .idle = true}); // Refresh rate will be chosen by either touch state or idle state. @@ -2722,16 +2745,17 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ReadsCache) { auto selector = createSelector(kModes_30_60_72_90_120, kModeId60); using GlobalSignals = RefreshRateSelector::GlobalSignals; - const auto args = std::make_pair(std::vector<LayerRequirement>{}, - GlobalSignals{.touch = true, .idle = true}); - const RefreshRateSelector::RankedFrameRates result = {{RefreshRateSelector::ScoredFrameRate{ {90_Hz, kMode90}}}, GlobalSignals{.touch = true}}; - selector.mutableGetRankedRefreshRatesCache() = {args, result}; + selector.mutableGetRankedRefreshRatesCache() = {.layers = std::vector<LayerRequirement>{}, + .signals = GlobalSignals{.touch = true, + .idle = true}, + .result = result}; - EXPECT_EQ(result, selector.getRankedFrameRates(args.first, args.second)); + const auto& cache = *selector.mutableGetRankedRefreshRatesCache(); + EXPECT_EQ(result, selector.getRankedFrameRates(cache.layers, cache.signals)); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_WritesCache) { @@ -2739,15 +2763,18 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_WritesCache) { EXPECT_FALSE(selector.mutableGetRankedRefreshRatesCache()); - std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}}; - RefreshRateSelector::GlobalSignals globalSignals{.touch = true, .idle = true}; + const std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}}; + const RefreshRateSelector::GlobalSignals globalSignals{.touch = true, .idle = true}; + const Fps pacesetterFps = 60_Hz; - const auto result = selector.getRankedFrameRates(layers, globalSignals); + const auto result = selector.getRankedFrameRates(layers, globalSignals, pacesetterFps); const auto& cache = selector.mutableGetRankedRefreshRatesCache(); ASSERT_TRUE(cache); - EXPECT_EQ(cache->arguments, std::make_pair(layers, globalSignals)); + EXPECT_EQ(cache->layers, layers); + EXPECT_EQ(cache->signals, globalSignals); + EXPECT_EQ(cache->pacesetterFps, pacesetterFps); EXPECT_EQ(cache->result, result); } @@ -3674,7 +3701,7 @@ TEST_P(RefreshRateSelectorTest, idleWhenLowestRefreshRateIsNotDivisor) { layers[0].vote = voteType; layers[0].desiredRefreshRate = 90_Hz; - const auto [ranking, signals] = + const auto [ranking, signals, _] = selector.getRankedFrameRates(layers, {.touch = touchActive, .idle = true}); // Refresh rate will be chosen by either touch state or idle state. diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 10e2220ece..03c12d6f73 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -356,7 +356,7 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { globalSignals)(kDisplayId2, FrameRateMode{60_Hz, kDisplay2Mode60}, - globalSignals); + GlobalSignals{}); std::vector<RefreshRateSelector::LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}}; @@ -375,7 +375,7 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { globalSignals)(kDisplayId2, FrameRateMode{120_Hz, kDisplay2Mode120}, - globalSignals); + GlobalSignals{}); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); @@ -394,7 +394,7 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { globalSignals)(kDisplayId2, FrameRateMode{120_Hz, kDisplay2Mode120}, - globalSignals); + GlobalSignals{}); const auto actualChoices = mScheduler->chooseDisplayModes(); EXPECT_EQ(expectedChoices, actualChoices); @@ -416,10 +416,10 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { DisplayModeChoice>(kDisplayId1, FrameRateMode{120_Hz, kDisplay1Mode120}, globalSignals)(kDisplayId2, FrameRateMode{120_Hz, kDisplay2Mode120}, - globalSignals)(kDisplayId3, - FrameRateMode{60_Hz, - kDisplay3Mode60}, - globalSignals); + GlobalSignals{})(kDisplayId3, + FrameRateMode{60_Hz, + kDisplay3Mode60}, + GlobalSignals{}); const auto actualChoices = mScheduler->chooseDisplayModes(); EXPECT_EQ(expectedChoices, actualChoices); @@ -434,12 +434,12 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { expectedChoices = ftl::init::map< const PhysicalDisplayId&, DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60}, - globalSignals)(kDisplayId2, - FrameRateMode{60_Hz, kDisplay2Mode60}, - globalSignals)(kDisplayId3, - FrameRateMode{60_Hz, - kDisplay3Mode60}, - globalSignals); + GlobalSignals{})(kDisplayId2, + FrameRateMode{60_Hz, kDisplay2Mode60}, + GlobalSignals{})(kDisplayId3, + FrameRateMode{60_Hz, + kDisplay3Mode60}, + globalSignals); const auto actualChoices = mScheduler->chooseDisplayModes(); EXPECT_EQ(expectedChoices, actualChoices); |