SF: Clean up API for refresh rate selection

Define types for each step: ScoredRefreshRate, RefreshRateRanking,
RankedRefreshRates, DisplayModeChoice, and DisplayModeRequest. The
last will replace DisplayDevice::ActiveModeInfo in a follow-up CL.

Add Scheduler::mLeaderDisplayId (always the primary display for now)
and provisionally use its DisplayModeChoice until Scheduler::Policy
is tracked per display.

Rewrite multi-display tests, which relied on each DisplayMode having
the same PhysicalDisplayId, and did not actually verify mode/display
association (`expectedDisplays` was unused). Test RefreshRateRanking
ordering by descending score.

Bug: 241285191
Test: libsurfaceflinger_unittest
Change-Id: I1d24d6a1fa9285aa7fc4bf2dd6654fa660d27b08
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 30f2c27..be3ebb7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -127,11 +127,19 @@
 }
 
 void Scheduler::registerDisplay(sp<const DisplayDevice> display) {
+    if (display->isPrimary()) {
+        mLeaderDisplayId = display->getPhysicalId();
+    }
+
     const bool ok = mDisplays.try_emplace(display->getPhysicalId(), std::move(display)).second;
     ALOGE_IF(!ok, "%s: Duplicate display", __func__);
 }
 
 void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
+    if (mLeaderDisplayId == displayId) {
+        mLeaderDisplayId.reset();
+    }
+
     mDisplays.erase(displayId);
 }
 
@@ -631,9 +639,8 @@
 
 template <typename S, typename T>
 auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
-    DisplayModePtr newMode;
+    std::vector<display::DisplayModeRequest> modeRequests;
     GlobalSignals consideredSignals;
-    std::vector<DisplayModeConfig> displayModeConfigs;
 
     bool refreshRateChanged = false;
     bool frameRateOverridesChanged;
@@ -646,42 +653,41 @@
         if (currentState == newState) return {};
         currentState = std::forward<T>(newState);
 
-        displayModeConfigs = getBestDisplayModeConfigs();
+        auto modeChoices = chooseDisplayModes();
 
-        // mPolicy holds the current mode, using the current mode we find out
-        // what display is currently being tracked through the policy and
-        // then find the DisplayModeConfig for that display. So that
-        // later we check if the policy mode has changed for the same display in policy.
-        // If mPolicy mode isn't available then we take the first display from the best display
-        // modes as the candidate for policy changes and frame rate overrides.
-        // TODO(b/240743786) Update the single display based assumptions and make mode changes
-        // and mPolicy per display.
-        const DisplayModeConfig& displayModeConfigForCurrentPolicy = mPolicy.mode
-                ? *std::find_if(displayModeConfigs.begin(), displayModeConfigs.end(),
-                                [&](const auto& displayModeConfig) REQUIRES(mPolicyLock) {
-                                    return displayModeConfig.displayModePtr
-                                                   ->getPhysicalDisplayId() ==
-                                            mPolicy.mode->getPhysicalDisplayId();
-                                })
-                : displayModeConfigs.front();
+        // TODO(b/240743786): The leader display's mode must change for any DisplayModeRequest to go
+        // through. Fix this by tracking per-display Scheduler::Policy and timers.
+        DisplayModePtr modePtr;
+        std::tie(modePtr, consideredSignals) =
+                modeChoices.get(*mLeaderDisplayId)
+                        .transform([](const DisplayModeChoice& choice) {
+                            return std::make_pair(choice.modePtr, choice.consideredSignals);
+                        })
+                        .value();
 
-        newMode = displayModeConfigForCurrentPolicy.displayModePtr;
-        consideredSignals = displayModeConfigForCurrentPolicy.signals;
-        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+        modeRequests.reserve(modeChoices.size());
+        for (auto& [id, choice] : modeChoices) {
+            modeRequests.emplace_back(
+                    display::DisplayModeRequest{.modePtr =
+                                                        ftl::as_non_null(std::move(choice.modePtr)),
+                                                .emitEvent = !choice.consideredSignals.idle});
+        }
 
-        if (mPolicy.mode == newMode) {
+        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modePtr->getFps());
+
+        if (mPolicy.mode != modePtr) {
+            mPolicy.mode = modePtr;
+            refreshRateChanged = true;
+        } else {
             // We don't need to change the display mode, but we might need to send an event
             // about a mode change, since it was suppressed if previously considered idle.
             if (!consideredSignals.idle) {
                 dispatchCachedReportedMode();
             }
-        } else {
-            mPolicy.mode = newMode;
-            refreshRateChanged = true;
         }
     }
     if (refreshRateChanged) {
-        mSchedulerCallback.requestDisplayModes(std::move(displayModeConfigs));
+        mSchedulerCallback.requestDisplayModes(std::move(modeRequests));
     }
     if (frameRateOverridesChanged) {
         mSchedulerCallback.triggerOnFrameRateOverridesChanged();
@@ -689,11 +695,11 @@
     return consideredSignals;
 }
 
-std::vector<DisplayModeConfig> Scheduler::getBestDisplayModeConfigs() const {
+auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap {
     ATRACE_CALL();
 
-    using Rankings = std::pair<std::vector<RefreshRateRanking>, GlobalSignals>;
-    display::PhysicalDisplayVector<Rankings> perDisplayRankings;
+    using RankedRefreshRates = RefreshRateConfigs::RankedRefreshRates;
+    display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking;
 
     // Tallies the score of a refresh rate across `displayCount` displays.
     struct RefreshRateTally {
@@ -710,11 +716,11 @@
     const auto globalSignals = makeGlobalSignals();
 
     for (const auto& [id, display] : mDisplays) {
-        auto [rankings, signals] =
+        auto rankedRefreshRates =
                 display->holdRefreshRateConfigs()
                         ->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals);
 
-        for (const auto& [modePtr, score] : rankings) {
+        for (const auto& [modePtr, score] : rankedRefreshRates.ranking) {
             const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score);
 
             if (!inserted) {
@@ -724,7 +730,7 @@
             }
         }
 
-        perDisplayRankings.emplace_back(std::move(rankings), signals);
+        perDisplayRanking.push_back(std::move(rankedRefreshRates));
     }
 
     auto maxScoreIt = refreshRateTallies.cbegin();
@@ -750,26 +756,27 @@
             ? std::make_optional(maxScoreIt->first)
             : std::nullopt;
 
-    std::vector<DisplayModeConfig> displayModeConfigs;
-    displayModeConfigs.reserve(mDisplays.size());
+    DisplayModeChoiceMap modeChoices;
 
     using fps_approx_ops::operator==;
 
-    for (const auto& [rankings, signals] : perDisplayRankings) {
+    for (auto& [ranking, signals] : perDisplayRanking) {
         if (!chosenFps) {
-            displayModeConfigs.emplace_back(signals, rankings.front().displayModePtr);
+            auto& [modePtr, _] = ranking.front();
+            modeChoices.try_emplace(modePtr->getPhysicalDisplayId(),
+                                    DisplayModeChoice{std::move(modePtr), signals});
             continue;
         }
 
-        for (const auto& ranking : rankings) {
-            const auto& modePtr = ranking.displayModePtr;
+        for (auto& [modePtr, _] : ranking) {
             if (modePtr->getFps() == *chosenFps) {
-                displayModeConfigs.emplace_back(signals, modePtr);
+                modeChoices.try_emplace(modePtr->getPhysicalDisplayId(),
+                                        DisplayModeChoice{std::move(modePtr), signals});
                 break;
             }
         }
     }
-    return displayModeConfigs;
+    return modeChoices;
 }
 
 GlobalSignals Scheduler::makeGlobalSignals() const {
@@ -787,11 +794,11 @@
     // Make sure the stored mode is up to date.
     if (mPolicy.mode) {
         const auto configs = holdRefreshRateConfigs();
-        const auto rankings =
+        const auto ranking =
                 configs->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals())
-                        .first;
+                        .ranking;
 
-        mPolicy.mode = rankings.front().displayModePtr;
+        mPolicy.mode = ranking.front().modePtr;
     }
     return mPolicy.mode;
 }