SF: Toggle VSYNC in EventThread with state machine

This CL simplifies the logic to enable and disable VSYNC in the
EventThread loop.

Bug: 74619554
Test: libsurfaceflinger_unittest
Test: dumpsys SurfaceFlinger --vsync

Change-Id: I7637fcf1982d60cfced5dae68c74556f0ee67a0f
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 281f6b7..668dfd0 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -163,6 +163,7 @@
     if (src == nullptr) {
         mVSyncSource = mVSyncSourceUnique.get();
     }
+    mVSyncSource->setCallback(this);
 
     mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
         std::unique_lock<std::mutex> lock(mMutex);
@@ -185,9 +186,11 @@
 }
 
 EventThread::~EventThread() {
+    mVSyncSource->setCallback(nullptr);
+
     {
         std::lock_guard<std::mutex> lock(mMutex);
-        mKeepRunning = false;
+        mState = State::Quit;
         mCondition.notify_all();
     }
     mThread.join();
@@ -293,20 +296,18 @@
 void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
     DisplayEventConsumers consumers;
 
-    while (mKeepRunning) {
+    while (mState != State::Quit) {
         std::optional<DisplayEventReceiver::Event> event;
 
         // Determine next event to dispatch.
         if (!mPendingEvents.empty()) {
             event = mPendingEvents.front();
             mPendingEvents.pop_front();
-        }
 
-        const bool vsyncPending =
-                event && event->header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-
-        if (mInterceptVSyncsCallback && vsyncPending) {
-            mInterceptVSyncsCallback(event->header.timestamp);
+            if (mInterceptVSyncsCallback &&
+                event->header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+                mInterceptVSyncsCallback(event->header.timestamp);
+            }
         }
 
         bool vsyncRequested = false;
@@ -332,19 +333,21 @@
             consumers.clear();
         }
 
-        // Here we figure out if we need to enable or disable vsyncs
-        if (vsyncPending && !vsyncRequested) {
-            // we received a VSYNC but we have no clients
-            // don't report it, and disable VSYNC events
-            disableVSyncLocked();
-        } else if (!vsyncPending && vsyncRequested) {
-            // we have at least one client, so we want vsync enabled
-            // (TODO: this function is called right after we finish
-            // notifying clients of a vsync, so this call will be made
-            // at the vsync rate, e.g. 60fps.  If we can accurately
-            // track the current state we could avoid making this call
-            // so often.)
-            enableVSyncLocked();
+        State nextState;
+        if (vsyncRequested) {
+            nextState = mVSyncState.synthetic ? State::SyntheticVSync : State::VSync;
+        } else {
+            nextState = State::Idle;
+        }
+
+        if (mState != nextState) {
+            if (mState == State::VSync) {
+                mVSyncSource->setVSyncEnabled(false);
+            } else if (nextState == State::VSync) {
+                mVSyncSource->setVSyncEnabled(true);
+            }
+
+            mState = nextState;
         }
 
         if (event) {
@@ -352,19 +355,19 @@
         }
 
         // Wait for event or client registration/request.
-        if (vsyncRequested) {
+        if (mState == State::Idle) {
+            mCondition.wait(lock);
+        } else {
             // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
             // display is off, keep feeding clients at 60 Hz.
-            const auto timeout = mVSyncState.synthetic ? 16ms : 1000ms;
+            const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms;
             if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
-                ALOGW_IF(!mVSyncState.synthetic, "Faking VSYNC due to driver stall");
+                ALOGW_IF(mState == State::VSync, "Faking VSYNC due to driver stall");
 
                 mPendingEvents.push_back(makeVSync(mVSyncState.displayId,
                                                    systemTime(SYSTEM_TIME_MONOTONIC),
                                                    ++mVSyncState.count));
             }
-        } else {
-            mCondition.wait(lock);
         }
     }
 }
@@ -413,30 +416,11 @@
     }
 }
 
-void EventThread::enableVSyncLocked() {
-    if (!mVSyncState.synthetic) {
-        if (!mVsyncEnabled) {
-            mVsyncEnabled = true;
-            mVSyncSource->setCallback(this);
-            mVSyncSource->setVSyncEnabled(true);
-        }
-    }
-    mDebugVsyncEnabled = true;
-}
-
-void EventThread::disableVSyncLocked() {
-    if (mVsyncEnabled) {
-        mVsyncEnabled = false;
-        mVSyncSource->setVSyncEnabled(false);
-        mDebugVsyncEnabled = false;
-    }
-}
-
 void EventThread::dump(std::string& result) const {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    StringAppendF(&result, "%s: VSYNC %s\n", mThreadName, mDebugVsyncEnabled ? "on" : "off");
-    StringAppendF(&result, "  VSyncState{displayId=%u, count=%u%s}\n", mVSyncState.displayId,
+    StringAppendF(&result, "%s: state=%s", mThreadName, toCString(mState));
+    StringAppendF(&result, " VSyncState{displayId=%u, count=%u%s}\n", mVSyncState.displayId,
                   mVSyncState.count, mVSyncState.synthetic ? ", synthetic" : "");
 
     StringAppendF(&result, "  pending events (count=%zu):\n", mPendingEvents.size());
@@ -452,5 +436,18 @@
     }
 }
 
+const char* EventThread::toCString(State state) {
+    switch (state) {
+        case State::Idle:
+            return "Idle";
+        case State::Quit:
+            return "Quit";
+        case State::SyntheticVSync:
+            return "SyntheticVSync";
+        case State::VSync:
+            return "VSync";
+    }
+}
+
 } // namespace impl
 } // namespace android