SurfaceFlinger: always turn HWVsync off when display is off

Maintain a state in SF about what is the latest HWVsync state in HWC
and what it should be. Apply the desired state when screen turns on and
always disabled HWVsync when the display is off.

Test: display power on/off
Bug: 134965007
Change-Id: I9c23d09ea2e32efa0b1f30a3999a08d15d7f35a6
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 87c1bf9..3cb0ce9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1540,14 +1540,12 @@
 void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
     ATRACE_CALL();
 
+    mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable;
+
     if (const auto displayId = getInternalDisplayIdLocked()) {
         sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
         if (display && display->isPoweredOn()) {
-            getHwComposer().setVsyncEnabled(*displayId,
-                                            enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
-        } else {
-            // Cache the latest vsync state and apply it when screen is on again
-            mEnableHWVsyncScreenOn = enabled;
+            setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
         }
     }
 }
@@ -4420,6 +4418,13 @@
             new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
 }
 
+void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) {
+    if (mHWCVsyncState != enabled) {
+        getHwComposer().setVsyncEnabled(displayId, enabled);
+        mHWCVsyncState = enabled;
+    }
+}
+
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
     if (display->isVirtual()) {
         ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4446,11 +4451,7 @@
         // Turn on the display
         getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
-            if (mEnableHWVsyncScreenOn) {
-                setPrimaryVsyncEnabledInternal(mEnableHWVsyncScreenOn);
-                mEnableHWVsyncScreenOn = false;
-            }
-
+            setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
         }
@@ -4476,6 +4477,9 @@
             mScheduler->onScreenReleased(mAppConnectionHandle);
         }
 
+        // Make sure HWVsync is disabled before turning off the display
+        setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable);
+
         getHwComposer().setPowerMode(*displayId, mode);
         mVisibleRegionsDirty = true;
         // from this point on, SF will stop drawing on this display
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 46fc4d2..8e835bf 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -838,6 +838,7 @@
     }
 
     bool previousFrameMissed();
+    void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
 
     /*
      * Debugging & dumpsys
@@ -1172,8 +1173,9 @@
     // be any issues with a raw pointer referencing an invalid object.
     std::unordered_set<Layer*> mOffscreenLayers;
 
-    // Flag to indicate whether to re-enable HWVsync when screen is on
-    bool mEnableHWVsyncScreenOn = false;
+    // Flags to capture the state of Vsync in HWC
+    HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable;
+    HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable;
 };
 
 } // namespace android