Add shouldBeSeamless to setFrameRate

This CL adds a new parameter shouldBeSeamless to the existing
setFrameRate APIs. This parameter indicates whether the desired
refresh rate should be achieved only seamlessly or also switches
with visual interruptions for the user are allowed. The default
value of the new parameter is "true".

Test: atest RefreshRateConfigsTest
Test: atest SetFrameRateTest
Test: atest libsurfaceflinger_unittest
Test: atest libgui_test

Bug: 161776961
Change-Id: I0df16e09f77c8c198fd3733fb581a2aaadfed685
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 150f925..0646c7d 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -31,6 +31,12 @@
 using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
 using RefreshRate = RefreshRateConfigs::RefreshRate;
 
+std::string RefreshRate::toString() const {
+    return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
+                              getConfigId().value(), hwcConfig->getId(), getFps(),
+                              hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup());
+}
+
 std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
     switch (vote) {
         case LayerVoteType::NoVote:
@@ -125,7 +131,7 @@
         const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
         GlobalSignals* outSignalsConsidered) const {
     ATRACE_CALL();
-    ALOGV("getRefreshRateForContent %zu layers", layers.size());
+    ALOGV("getBestRefreshRate %zu layers", layers.size());
 
     if (outSignalsConsidered) *outSignalsConsidered = {};
     const auto setTouchConsidered = [&] {
@@ -148,6 +154,7 @@
     int explicitDefaultVoteLayers = 0;
     int explicitExactOrMultipleVoteLayers = 0;
     float maxExplicitWeight = 0;
+    int seamedLayers = 0;
     for (const auto& layer : layers) {
         if (layer.vote == LayerVoteType::NoVote) {
             noVoteLayers++;
@@ -162,6 +169,10 @@
             explicitExactOrMultipleVoteLayers++;
             maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
         }
+
+        if (!layer.shouldBeSeamless) {
+            seamedLayers++;
+        }
     }
 
     const bool hasExplicitVoteLayers =
@@ -206,6 +217,8 @@
         scores.emplace_back(refreshRate, 0.0f);
     }
 
+    const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig);
+
     for (const auto& layer : layers) {
         ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
               layerVoteTypeString(layer.vote).c_str(), layer.weight);
@@ -216,6 +229,30 @@
         auto weight = layer.weight;
 
         for (auto i = 0u; i < scores.size(); i++) {
+            // If there are no layers with shouldBeSeamless=false and the current
+            // config group is different from the default one, this means a layer with
+            // shouldBeSeamless=false has just disappeared and we should switch back to
+            // the default config group.
+            const bool isSeamlessSwitch = seamedLayers > 0
+                    ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup()
+                    : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup();
+
+            if (layer.shouldBeSeamless && !isSeamlessSwitch) {
+                ALOGV("%s (weight %.2f) ignores %s (group=%d) to avoid non-seamless switch."
+                      "Current config = %s",
+                      layer.name.c_str(), weight, scores[i].first->name.c_str(),
+                      scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str());
+                continue;
+            }
+
+            if (!layer.shouldBeSeamless && !isSeamlessSwitch && !layer.focused) {
+                ALOGV("%s (weight %.2f) ignores %s (group=%d) because it's not focused"
+                      " and the switch is going to be seamed. Current config = %s",
+                      layer.name.c_str(), weight, scores[i].first->name.c_str(),
+                      scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str());
+                continue;
+            }
+
             bool inPrimaryRange =
                     scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
             if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
@@ -292,10 +329,13 @@
 
                     return 1.0f / iter;
                 }();
+                // Slightly prefer seamless switches.
+                constexpr float kSeamedSwitchPenalty = 0.95f;
+                const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
                 ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
                       layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod,
                       scores[i].first->name.c_str(), layerScore);
-                scores[i].second += weight * layerScore;
+                scores[i].second += weight * layerScore * seamlessness;
                 continue;
             }
         }
@@ -367,6 +407,15 @@
 }
 
 const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+    for (auto refreshRate : mPrimaryRefreshRates) {
+        if (mCurrentRefreshRate->getConfigGroup() == refreshRate->getConfigGroup()) {
+            return *refreshRate;
+        }
+    }
+    ALOGE("Can't find min refresh rate by policy with the same config group"
+          " as the current config %s",
+          mCurrentRefreshRate->toString().c_str());
+    // Defaulting to the lowest refresh rate
     return *mPrimaryRefreshRates.front();
 }
 
@@ -376,6 +425,16 @@
 }
 
 const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+    for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) {
+        const auto& refreshRate = (**it);
+        if (mCurrentRefreshRate->getConfigGroup() == refreshRate.getConfigGroup()) {
+            return refreshRate;
+        }
+    }
+    ALOGE("Can't find max refresh rate by policy with the same config group"
+          " as the current config %s",
+          mCurrentRefreshRate->toString().c_str());
+    // Defaulting to the highest refresh rate
     return *mPrimaryRefreshRates.back();
 }
 
@@ -414,7 +473,7 @@
         const float fps = 1e9f / config->getVsyncPeriod();
         mRefreshRates.emplace(configId,
                               std::make_unique<RefreshRate>(configId, config,
-                                                            base::StringPrintf("%.0ffps", fps), fps,
+                                                            base::StringPrintf("%.2ffps", fps), fps,
                                                             RefreshRate::ConstructorTag(0)));
         if (configId == currentConfigId) {
             mCurrentRefreshRate = mRefreshRates.at(configId).get();