SF: add render frame rate to the scheduler

Schedule SF at the rate of the render frame rate instead of
the display refresh rate.

Test: SF unit tests
Bug: 257072060
Change-Id: Idaf9be5f25373d38c0ef6440f9f401dc90de7a91
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 0c541f9..7f8f600 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -174,7 +174,7 @@
 
 impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
     return [this](uid_t uid) {
-        const Fps refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
+        const Fps refreshRate = leaderSelectorPtr()->getActiveMode().fps;
         const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs();
 
         const auto frameRate = getFrameRateOverride(uid);
@@ -282,7 +282,7 @@
     thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
 }
 
-void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
     {
         std::lock_guard<std::mutex> lock(mPolicyLock);
         // Cache the last reported modes for primary display.
@@ -297,7 +297,7 @@
 
 void Scheduler::dispatchCachedReportedMode() {
     // Check optional fields first.
-    if (!mPolicy.mode) {
+    if (!mPolicy.modeOpt) {
         ALOGW("No mode ID found, not dispatching cached mode.");
         return;
     }
@@ -309,28 +309,28 @@
     // If the mode is not the current mode, this means that a
     // mode change is in progress. In that case we shouldn't dispatch an event
     // as it will be dispatched when the current mode changes.
-    if (leaderSelectorPtr()->getActiveModePtr() != mPolicy.mode) {
+    if (leaderSelectorPtr()->getActiveMode() != mPolicy.modeOpt) {
         return;
     }
 
     // If there is no change from cached mode, there is no need to dispatch an event
-    if (mPolicy.mode == mPolicy.cachedModeChangedParams->mode) {
+    if (*mPolicy.modeOpt == mPolicy.cachedModeChangedParams->mode) {
         return;
     }
 
-    mPolicy.cachedModeChangedParams->mode = mPolicy.mode;
+    mPolicy.cachedModeChangedParams->mode = *mPolicy.modeOpt;
     onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->handle,
                                    mPolicy.cachedModeChangedParams->mode);
 }
 
-void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
     android::EventThread* thread;
     {
         std::lock_guard<std::mutex> lock(mConnectionsLock);
         RETURN_IF_INVALID_HANDLE(handle);
         thread = mConnections[handle].thread.get();
     }
-    thread->onModeChanged(mode);
+    thread->onModeChanged(mode.modePtr.get());
 }
 
 size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
@@ -395,6 +395,24 @@
     setVsyncPeriod(refreshRate.getPeriodNsecs());
 }
 
+void Scheduler::setRenderRate(Fps renderFrameRate) {
+    const auto mode = leaderSelectorPtr()->getActiveMode();
+
+    using fps_approx_ops::operator!=;
+    LOG_ALWAYS_FATAL_IF(renderFrameRate != mode.fps,
+                        "Mismatch in render frame rates. Selector: %s, Scheduler: %s",
+                        to_string(mode.fps).c_str(), to_string(renderFrameRate).c_str());
+
+    ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(),
+          to_string(mode.modePtr->getFps()).c_str());
+
+    const auto divisor = RefreshRateSelector::getFrameRateDivisor(mode.modePtr->getFps(), mode.fps);
+    LOG_ALWAYS_FATAL_IF(divisor == 0, "%s <> %s -- not divisors", to_string(mode.fps).c_str(),
+                        to_string(mode.fps).c_str());
+
+    mVsyncSchedule->getTracker().setDivisor(static_cast<unsigned>(divisor));
+}
+
 void Scheduler::resync() {
     static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
 
@@ -402,7 +420,7 @@
     const nsecs_t last = mLastResyncTime.exchange(now);
 
     if (now - last > kIgnoreDelay) {
-        const auto refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
+        const auto refreshRate = leaderSelectorPtr()->getActiveMode().modePtr->getFps();
         resyncToHardwareVsync(false, refreshRate);
     }
 }
@@ -517,7 +535,7 @@
 
     // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
     // magic number
-    const Fps refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
+    const Fps refreshRate = leaderSelectorPtr()->getActiveMode().modePtr->getFps();
 
     constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
     using namespace fps_approx_ops;
@@ -657,7 +675,7 @@
         currentState = std::forward<T>(newState);
 
         DisplayModeChoiceMap modeChoices;
-        DisplayModePtr modePtr;
+        ftl::Optional<FrameRateMode> modeOpt;
         {
             std::scoped_lock lock(mDisplayLock);
             ftl::FakeGuard guard(kMainThreadContext);
@@ -666,10 +684,10 @@
 
             // 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.
-            std::tie(modePtr, consideredSignals) =
+            std::tie(modeOpt, consideredSignals) =
                     modeChoices.get(*mLeaderDisplayId)
                             .transform([](const DisplayModeChoice& choice) {
-                                return std::make_pair(choice.modePtr, choice.consideredSignals);
+                                return std::make_pair(choice.mode, choice.consideredSignals);
                             })
                             .value();
         }
@@ -677,15 +695,14 @@
         modeRequests.reserve(modeChoices.size());
         for (auto& [id, choice] : modeChoices) {
             modeRequests.emplace_back(
-                    display::DisplayModeRequest{.modePtr =
-                                                        ftl::as_non_null(std::move(choice.modePtr)),
+                    display::DisplayModeRequest{.mode = std::move(choice.mode),
                                                 .emitEvent = !choice.consideredSignals.idle});
         }
 
-        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modePtr->getFps());
+        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modeOpt->fps);
 
-        if (mPolicy.mode != modePtr) {
-            mPolicy.mode = modePtr;
+        if (mPolicy.modeOpt != modeOpt) {
+            mPolicy.modeOpt = modeOpt;
             refreshRateChanged = true;
         } else {
             // We don't need to change the display mode, but we might need to send an event
@@ -725,12 +742,11 @@
     const auto globalSignals = makeGlobalSignals();
 
     for (const auto& [id, selectorPtr] : mRefreshRateSelectors) {
-        auto rankedRefreshRates =
+        auto rankedFrameRates =
                 selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals);
 
-        for (const auto& [frameRateMode, score] : rankedRefreshRates.ranking) {
-            const auto& modePtr = frameRateMode.modePtr;
-            const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score);
+        for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) {
+            const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score);
 
             if (!inserted) {
                 auto& tally = it->second;
@@ -739,7 +755,7 @@
             }
         }
 
-        perDisplayRanking.push_back(std::move(rankedRefreshRates));
+        perDisplayRanking.push_back(std::move(rankedFrameRates));
     }
 
     auto maxScoreIt = refreshRateTallies.cbegin();
@@ -773,17 +789,15 @@
     for (auto& [ranking, signals] : perDisplayRanking) {
         if (!chosenFps) {
             const auto& [frameRateMode, _] = ranking.front();
-            const auto& modePtr = frameRateMode.modePtr;
-            modeChoices.try_emplace(modePtr->getPhysicalDisplayId(),
-                                    DisplayModeChoice{modePtr, signals});
+            modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
+                                    DisplayModeChoice{frameRateMode, signals});
             continue;
         }
 
         for (auto& [frameRateMode, _] : ranking) {
-            const auto& modePtr = frameRateMode.modePtr;
-            if (modePtr->getFps() == *chosenFps) {
-                modeChoices.try_emplace(modePtr->getPhysicalDisplayId(),
-                                        DisplayModeChoice{modePtr, signals});
+            if (frameRateMode.fps == *chosenFps) {
+                modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
+                                        DisplayModeChoice{frameRateMode, signals});
                 break;
             }
         }
@@ -801,18 +815,18 @@
             .powerOnImminent = powerOnImminent};
 }
 
-DisplayModePtr Scheduler::getPreferredDisplayMode() {
+ftl::Optional<FrameRateMode> Scheduler::getPreferredDisplayMode() {
     std::lock_guard<std::mutex> lock(mPolicyLock);
     // Make sure the stored mode is up to date.
-    if (mPolicy.mode) {
+    if (mPolicy.modeOpt) {
         const auto ranking =
                 leaderSelectorPtr()
                         ->getRankedFrameRates(mPolicy.contentRequirements, makeGlobalSignals())
                         .ranking;
 
-        mPolicy.mode = ranking.front().frameRateMode.modePtr;
+        mPolicy.modeOpt = ranking.front().frameRateMode;
     }
-    return mPolicy.mode;
+    return mPolicy.modeOpt;
 }
 
 void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {