Merge "SurfaceFlinger: frame rate heuristic during config change" into rvc-dev am: 36725c77ca

Change-Id: I899cf48235bb79097b2198401bbe9ab66aa99c0c
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index a1ae35c..d5bebf6 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -52,6 +52,8 @@
     // Sets the display size. Client is responsible for synchronization.
     virtual void setDisplayArea(uint32_t displayArea) = 0;
 
+    virtual void setConfigChangePending(bool pending) = 0;
+
     // Marks the layer as active, and records the given state to its history.
     virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
 
@@ -78,6 +80,8 @@
 
     void setDisplayArea(uint32_t /*displayArea*/) override {}
 
+    void setConfigChangePending(bool /*pending*/) override {}
+
     // Marks the layer as active, and records the given state to its history.
     void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
 
@@ -134,6 +138,8 @@
     // Sets the display size. Client is responsible for synchronization.
     void setDisplayArea(uint32_t displayArea) override { mDisplayArea = displayArea; }
 
+    void setConfigChangePending(bool pending) override { mConfigChangePending = pending; }
+
     // Marks the layer as active, and records the given state to its history.
     void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
 
@@ -178,6 +184,9 @@
 
     // Whether to use priority sent from WindowManager to determine the relevancy of the layer.
     const bool mUseFrameRatePriority;
+
+    // Whether a config change is in progress or not
+    std::atomic<bool> mConfigChangePending = false;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index 120a60f..afc8c4f 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -103,7 +103,7 @@
     LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
 
     const auto& info = it->second;
-    info->setLastPresentTime(presentTime, now);
+    info->setLastPresentTime(presentTime, now, mConfigChangePending);
 
     // Activate layer if inactive.
     if (const auto end = activeLayers().end(); it >= end) {
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index 255eac6..c16387a 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -34,12 +34,15 @@
         mDefaultVote(defaultVote),
         mLayerVote({defaultVote, 0.0f}) {}
 
-void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
+void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now,
+                                     bool pendingConfigChange) {
     lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
 
     mLastUpdatedTime = std::max(lastPresentTime, now);
 
-    FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime};
+    FrameTimeData frameTime = {.presetTime = lastPresentTime,
+                               .queueTime = mLastUpdatedTime,
+                               .pendingConfigChange = pendingConfigChange};
 
     mFrameTimes.push_back(frameTime);
     if (mFrameTimes.size() > HISTORY_SIZE) {
@@ -80,21 +83,20 @@
     return true;
 }
 
-std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
-    static constexpr float MARGIN = 1.0f; // 1Hz
-
-    if (!hasEnoughDataForHeuristic()) {
-        ALOGV("Not enough data");
-        return std::nullopt;
-    }
-
-    // Calculate the refresh rate by finding the average delta between frames
+std::pair<nsecs_t, bool> LayerInfoV2::calculateAverageFrameTime() const {
     nsecs_t totalPresentTimeDeltas = 0;
     nsecs_t totalQueueTimeDeltas = 0;
-    auto missingPresentTime = false;
+    bool missingPresentTime = false;
+    int numFrames = 0;
     for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+        // Ignore frames captured during a config change
+        if (it->pendingConfigChange || (it + 1)->pendingConfigChange) {
+            continue;
+        }
+
         totalQueueTimeDeltas +=
                 std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod);
+        numFrames++;
 
         if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
             missingPresentTime = true;
@@ -105,11 +107,6 @@
                 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
     }
 
-    // If there are no presentation timestamps provided we can't calculate the refresh rate
-    if (missingPresentTime && mLastReportedRefreshRate == 0) {
-        return std::nullopt;
-    }
-
     // Calculate the average frame time based on presentation timestamps. If those
     // doesn't exist, we look at the time the buffer was queued only. We can do that only if
     // we calculated a refresh rate based on presentation timestamps in the past. The reason
@@ -117,13 +114,18 @@
     // when implementing render ahead for specific refresh rates. When hwui no longer provides
     // presentation timestamps we look at the queue time to see if the current refresh rate still
     // matches the content.
-    const float averageFrameTime =
+    const auto averageFrameTime =
             static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) /
-            (mFrameTimes.size() - 1);
+            numFrames;
+    return {static_cast<nsecs_t>(averageFrameTime), missingPresentTime};
+}
 
-    // Now once we calculated the refresh rate we need to make sure that all the frames we captured
-    // are evenly distributed and we don't calculate the average across some burst of frames.
+bool LayerInfoV2::isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const {
     for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+        // Ignore frames captured during a config change
+        if (it->pendingConfigChange || (it + 1)->pendingConfigChange) {
+            continue;
+        }
         const auto presentTimeDeltas = [&] {
             const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime
                                                   : (it + 1)->presetTime - it->presetTime;
@@ -131,10 +133,32 @@
         }();
 
         if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
-            return std::nullopt;
+            return false;
         }
     }
 
+    return true;
+}
+
+std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
+    static constexpr float MARGIN = 1.0f; // 1Hz
+
+    if (!hasEnoughDataForHeuristic()) {
+        ALOGV("Not enough data");
+        return std::nullopt;
+    }
+
+    const auto [averageFrameTime, missingPresentTime] = calculateAverageFrameTime();
+
+    // If there are no presentation timestamps provided we can't calculate the refresh rate
+    if (missingPresentTime && mLastReportedRefreshRate == 0) {
+        return std::nullopt;
+    }
+
+    if (!isRefreshRateStable(averageFrameTime, missingPresentTime)) {
+        return std::nullopt;
+    }
+
     const auto refreshRate = 1e9f / averageFrameTime;
     if (std::abs(refreshRate - mLastReportedRefreshRate) > MARGIN) {
         mLastReportedRefreshRate = refreshRate;
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 97c7017..ccd6be4 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -63,7 +63,7 @@
     // Records the last requested present time. It also stores information about when
     // the layer was last updated. If the present time is farther in the future than the
     // updated time, the updated time is the present time.
-    void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now);
+    void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange);
 
     // Sets an explicit layer vote. This usually comes directly from the application via
     // ANativeWindow_setFrameRate API
@@ -93,11 +93,14 @@
     struct FrameTimeData {
         nsecs_t presetTime; // desiredPresentTime, if provided
         nsecs_t queueTime;  // buffer queue time
+        bool pendingConfigChange;
     };
 
     bool isFrequent(nsecs_t now) const;
     bool hasEnoughDataForHeuristic() const;
     std::optional<float> calculateRefreshRateIfPossible();
+    std::pair<nsecs_t, bool> calculateAverageFrameTime() const;
+    bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const;
 
     const std::string mName;
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4eef81d..7c2af23 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -423,6 +423,12 @@
     }
 }
 
+void Scheduler::setConfigChangePending(bool pending) {
+    if (mLayerHistory) {
+        mLayerHistory->setConfigChangePending(pending);
+    }
+}
+
 void Scheduler::chooseRefreshRateForContent() {
     if (!mLayerHistory) return;
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 6eabfd2..066e9ca 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -119,6 +119,7 @@
     // Layers are registered on creation, and unregistered when the weak reference expires.
     void registerLayer(Layer*);
     void recordLayerHistory(Layer*, nsecs_t presentTime);
+    void setConfigChangePending(bool pending);
 
     // Detects content using layer history, and selects a matching refresh rate.
     void chooseRefreshRateForContent();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 18f789e..2d25319 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1010,6 +1010,7 @@
 
         mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
         mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+        mScheduler->setConfigChangePending(true);
     }
 
     if (mRefreshRateOverlay) {
@@ -1090,6 +1091,7 @@
     mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
     mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
     mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+    mScheduler->setConfigChangePending(false);
 }
 
 void SurfaceFlinger::performSetActiveConfig() {