DisplayEventDispatcher: optimize binder calls
Use DisplayEventReciever::setVsyncRate instead of
DisplayEventReciever::requestNextVsync to accommodate a one-time
registration to vsync events when the app registers back to back
callbacks. With this approach we can save all the binder calls during
a running animation.
Test: run TouchLatency test app and observe systrace
Bug: 162096692
Change-Id: Ib415f2aade40a3d23a2b4c77e5746e5e13666d23
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index c6c9a8f..2ad484a 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,7 +36,9 @@
DisplayEventDispatcher::DisplayEventDispatcher(
const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration)
- : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
+ : mLooper(looper),
+ mReceiver(vsyncSource, eventRegistration),
+ mVsyncState(VsyncState::Unregistered) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
@@ -66,26 +68,37 @@
}
status_t DisplayEventDispatcher::scheduleVsync() {
- if (!mWaitingForVsync) {
- ALOGV("dispatcher %p ~ Scheduling vsync.", this);
+ switch (mVsyncState) {
+ case VsyncState::Unregistered: {
+ ALOGV("dispatcher %p ~ Scheduling vsync.", this);
- // Drain all pending events.
- nsecs_t vsyncTimestamp;
- PhysicalDisplayId vsyncDisplayId;
- uint32_t vsyncCount;
- VsyncEventData vsyncEventData;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
- ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
- ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
+ // Drain all pending events.
+ nsecs_t vsyncTimestamp;
+ PhysicalDisplayId vsyncDisplayId;
+ uint32_t vsyncCount;
+ VsyncEventData vsyncEventData;
+ if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount,
+ &vsyncEventData)) {
+ ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
+ this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
+ }
+
+ status_t status = mReceiver.setVsyncRate(1);
+ if (status) {
+ ALOGW("Failed to set vsync rate, status=%d", status);
+ return status;
+ }
+
+ mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
+ break;
}
-
- status_t status = mReceiver.requestNextVsync();
- if (status) {
- ALOGW("Failed to request next vsync, status=%d", status);
- return status;
+ case VsyncState::Registered: {
+ mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
+ break;
}
-
- mWaitingForVsync = true;
+ case VsyncState::RegisteredAndWaitingForVsync: {
+ break;
+ }
}
return OK;
}
@@ -123,8 +136,23 @@
", displayId=%s, count=%d, vsyncId=%" PRId64,
this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
vsyncEventData.id);
- mWaitingForVsync = false;
- dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
+ switch (mVsyncState) {
+ case VsyncState::Unregistered:
+ ALOGW("Received unexpected VSYNC event");
+ break;
+ case VsyncState::RegisteredAndWaitingForVsync:
+ mVsyncState = VsyncState::Registered;
+ dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
+ break;
+ case VsyncState::Registered:
+ status_t status = mReceiver.setVsyncRate(0);
+ if (status) {
+ ALOGW("Failed to reset vsync rate, status=%d", status);
+ return status;
+ }
+ mVsyncState = VsyncState::Unregistered;
+ break;
+ }
}
return 1; // keep the callback
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 5587acf..4c2b08b 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -52,7 +52,20 @@
private:
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
- bool mWaitingForVsync;
+ // The state of vsync event registration and whether the client is expecting
+ // an event or not.
+ enum class VsyncState {
+ // The dispatcher is not registered for vsync events.
+ Unregistered,
+ // The dispatcher is registered to receive vsync events but should not dispatch it to the
+ // client as the client is not expecting a vsync event.
+ Registered,
+
+ // The dispatcher is registered to receive vsync events and supposed to dispatch it to
+ // the client.
+ RegisteredAndWaitingForVsync,
+ };
+ VsyncState mVsyncState;
std::vector<FrameRateOverride> mFrameRateOverrides;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index c12a7b1..f90c130 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -303,6 +303,10 @@
std::lock_guard<std::mutex> lock(mMutex);
const auto request = rate == 0 ? VSyncRequest::None : static_cast<VSyncRequest>(rate);
+ if (request != VSyncRequest::None && connection->resyncCallback) {
+ connection->resyncCallback();
+ }
+
if (connection->vsyncRequest != request) {
connection->vsyncRequest = request;
mCondition.notify_all();