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