SF: Complete mode change immediately if refresh is not required

Bug: 190982486
Test: atest libsurfaceflinger_unittest
Change-Id: I4be91274c6570c5e9304098d5d6c3d30c41c4e6e
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 095d5a8..9f0ab02 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1201,6 +1201,8 @@
 void SurfaceFlinger::setActiveModeInHwcIfNeeded() {
     ATRACE_CALL();
 
+    std::optional<PhysicalDisplayId> displayToUpdateImmediately;
+
     for (const auto& iter : mDisplays) {
         const auto& display = iter.second;
         if (!display || !display->isInternal()) {
@@ -1265,8 +1267,26 @@
         }
         mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
 
-        // Scheduler will submit an empty frame to HWC if needed.
-        mSetActiveModePending = true;
+        if (outTimeline.refreshRequired) {
+            // Scheduler will submit an empty frame to HWC.
+            mSetActiveModePending = true;
+        } else {
+            // Updating the internal state should be done outside the loop,
+            // because it can recreate a DisplayDevice and modify mDisplays
+            // which will invalidate the iterator.
+            displayToUpdateImmediately = display->getPhysicalId();
+        }
+    }
+
+    if (displayToUpdateImmediately) {
+        updateInternalStateWithChangedMode();
+
+        const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately);
+        const auto desiredActiveMode = display->getDesiredActiveMode();
+        if (desiredActiveMode &&
+            display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) {
+            desiredActiveModeChangeDone(display);
+        }
     }
 }