SurfaceFlinger: Add touch events to Scheduler
Add the notion of Touch Events to Scheduler to enhance the algorithm
to move to Performance refresh rate.
Scheduler selects Performance when:
- There is a touch event
- There is a buffer to HWC
This change also removes the behavior of Scheduler to move to Performance
on Choreographer callbacks.
Test: Switch between apps using gesture navigation
Bug: 131906818
Change-Id: I588cfc32449e87744e829dc7c5261a2e4151a8f8
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 3f9a88d..513436a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -75,6 +75,8 @@
mSetIdleTimerMs = set_idle_timer_ms(0);
mSupportKernelTimer = support_kernel_idle_timer(false);
+ mSetTouchTimerMs = set_touch_timer_ms(0);
+
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.set_idle_timer_ms", value, "0");
int int_value = atoi(value);
@@ -99,10 +101,20 @@
}
mIdleTimer->start();
}
+
+ if (mSetTouchTimerMs > 0) {
+ // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
+ mTouchTimer =
+ std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetTouchTimerMs),
+ [this] { resetTouchTimerCallback(); },
+ [this] { expiredTouchTimerCallback(); });
+ mTouchTimer->start();
+ }
}
Scheduler::~Scheduler() {
// Ensure the IdleTimer thread is joined before we start destroying state.
+ mTouchTimer.reset();
mIdleTimer.reset();
}
@@ -136,8 +148,7 @@
sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
ResyncCallback&& resyncCallback) {
- return eventThread->createEventConnection(std::move(resyncCallback),
- [this] { resetIdleTimer(); });
+ return eventThread->createEventConnection(std::move(resyncCallback));
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
@@ -385,6 +396,16 @@
}
}
+void Scheduler::notifyTouchEvent() {
+ if (mTouchTimer) {
+ mTouchTimer->reset();
+ }
+
+ if (mSupportKernelTimer) {
+ resetIdleTimer();
+ }
+}
+
void Scheduler::resetTimerCallback() {
timerChangeRefreshRate(IdleTimerState::RESET);
ATRACE_INT("ExpiredIdleTimer", 0);
@@ -403,6 +424,18 @@
ATRACE_INT("ExpiredIdleTimer", 1);
}
+void Scheduler::resetTouchTimerCallback() {
+ // We do not notify the applications about config changes when idle timer is reset.
+ touchChangeRefreshRate(TouchState::ACTIVE);
+ ATRACE_INT("TouchState", 1);
+}
+
+void Scheduler::expiredTouchTimerCallback() {
+ // We do not notify the applications about config changes when idle timer expires.
+ touchChangeRefreshRate(TouchState::INACTIVE);
+ ATRACE_INT("TouchState", 0);
+}
+
void Scheduler::expiredKernelTimerCallback() {
ATRACE_INT("ExpiredKernelIdleTimer", 1);
// Disable HW Vsync if the timer expired, as we don't need it
@@ -413,6 +446,7 @@
std::string Scheduler::doDump() {
std::ostringstream stream;
stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
+ stream << "+ Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl;
return stream.str();
}
@@ -433,14 +467,41 @@
changeRefreshRate(newRefreshRateType, ConfigEvent::None);
}
+void Scheduler::touchChangeRefreshRate(TouchState touchState) {
+ ConfigEvent event = ConfigEvent::None;
+ RefreshRateType newRefreshRateType;
+ {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ if (mCurrentTouchState == touchState) {
+ return;
+ }
+ mCurrentTouchState = touchState;
+ newRefreshRateType = calculateRefreshRateType();
+ if (mRefreshRateType == newRefreshRateType) {
+ return;
+ }
+ mRefreshRateType = newRefreshRateType;
+ // Send an event in case that content detection is on as touch has a higher priority
+ if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
+ event = ConfigEvent::Changed;
+ }
+ }
+ changeRefreshRate(newRefreshRateType, event);
+}
+
Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
- // First check if timer has expired as it means there is no new content on the screen
- if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
+ // HDR content is not supported on PERFORMANCE mode
+ if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
return RefreshRateType::DEFAULT;
}
- // HDR content is not supported on PERFORMANCE mode
- if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
+ // As long as touch is active we want to be in performance mode
+ if (mCurrentTouchState == TouchState::ACTIVE) {
+ return RefreshRateType::PERFORMANCE;
+ }
+
+ // If timer has expired as it means there is no new content on the screen
+ if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
return RefreshRateType::DEFAULT;
}