diff options
7 files changed, 96 insertions, 32 deletions
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index cfdbd91e35..a7784e9315 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -76,6 +76,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, mSupportKernelTimer = support_kernel_idle_timer(false); mSetTouchTimerMs = set_touch_timer_ms(0); + mSetDisplayPowerTimerMs = set_display_power_timer_ms(0); char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.set_idle_timer_ms", value, "0"); @@ -110,10 +111,22 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, [this] { expiredTouchTimerCallback(); }); mTouchTimer->start(); } + + if (mSetDisplayPowerTimerMs > 0) { + mDisplayPowerTimer = + std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( + mSetDisplayPowerTimerMs), + [this] { resetDisplayPowerTimerCallback(); }, + [this] { + expiredDisplayPowerTimerCallback(); + }); + mDisplayPowerTimer->start(); + } } Scheduler::~Scheduler() { // Ensure the IdleTimer thread is joined before we start destroying state. + mDisplayPowerTimer.reset(); mTouchTimer.reset(); mIdleTimer.reset(); } @@ -419,8 +432,23 @@ void Scheduler::notifyTouchEvent() { mLayerHistory.clearHistory(); } +void Scheduler::setDisplayPowerState(bool normal) { + { + std::lock_guard<std::mutex> lock(mFeatureStateLock); + mIsDisplayPowerStateNormal = normal; + } + + if (mDisplayPowerTimer) { + mDisplayPowerTimer->reset(); + } + + // Display Power event will boost the refresh rate to performance. + // Clear Layer History to get fresh FPS detection + mLayerHistory.clearHistory(); +} + void Scheduler::resetTimerCallback() { - timerChangeRefreshRate(IdleTimerState::RESET); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false); ATRACE_INT("ExpiredIdleTimer", 0); } @@ -433,22 +461,30 @@ void Scheduler::resetKernelTimerCallback() { } void Scheduler::expiredTimerCallback() { - timerChangeRefreshRate(IdleTimerState::EXPIRED); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false); ATRACE_INT("ExpiredIdleTimer", 1); } void Scheduler::resetTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer is reset. - touchChangeRefreshRate(TouchState::ACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true); ATRACE_INT("TouchState", 1); } void Scheduler::expiredTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer expires. - touchChangeRefreshRate(TouchState::INACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true); ATRACE_INT("TouchState", 0); } +void Scheduler::resetDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 0); +} + +void Scheduler::expiredDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 1); +} + void Scheduler::expiredKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 1); // Disable HW Vsync if the timer expired, as we don't need it @@ -463,39 +499,23 @@ std::string Scheduler::doDump() { return stream.str(); } -void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) { - RefreshRateType newRefreshRateType; - { - std::lock_guard<std::mutex> lock(mFeatureStateLock); - if (mCurrentIdleTimerState == idleTimerState) { - return; - } - mCurrentIdleTimerState = idleTimerState; - newRefreshRateType = calculateRefreshRateType(); - if (mRefreshRateType == newRefreshRateType) { - return; - } - mRefreshRateType = newRefreshRateType; - } - changeRefreshRate(newRefreshRateType, ConfigEvent::None); -} - -void Scheduler::touchChangeRefreshRate(TouchState touchState) { +template <class T> +void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; RefreshRateType newRefreshRateType; { std::lock_guard<std::mutex> lock(mFeatureStateLock); - if (mCurrentTouchState == touchState) { + if (*currentState == newState) { return; } - mCurrentTouchState = touchState; + *currentState = newState; 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) { + if (eventOnContentDetection && + mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { event = ConfigEvent::Changed; } } @@ -508,6 +528,12 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return RefreshRateType::DEFAULT; } + // If Display Power is not in normal operation we want to be in performance mode. + // When coming back to normal mode, a grace period is given with DisplayPowerTimer + if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) { + return RefreshRateType::PERFORMANCE; + } + // As long as touch is active we want to be in performance mode if (mCurrentTouchState == TouchState::ACTIVE) { return RefreshRateType::PERFORMANCE; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index eaad37c3ee..39c39d7639 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -177,6 +177,9 @@ public: // Function that resets the touch timer. void notifyTouchEvent(); + // Function that sets whether display power mode is normal or not. + void setDisplayPowerState(bool normal); + // Returns relevant information about Scheduler for dumpsys purposes. std::string doDump(); @@ -197,6 +200,7 @@ private: enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF }; enum class IdleTimerState { EXPIRED, RESET }; enum class TouchState { INACTIVE, ACTIVE }; + enum class DisplayPowerTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&, @@ -221,12 +225,15 @@ private: void resetTouchTimerCallback(); // Function that is called when the touch timer expires. void expiredTouchTimerCallback(); + // Function that is called when the display power timer resets. + void resetDisplayPowerTimerCallback(); + // Function that is called when the display power timer expires. + void expiredDisplayPowerTimerCallback(); // Sets vsync period. void setVsyncPeriod(const nsecs_t period); - // Idle timer feature's function to change the refresh rate. - void timerChangeRefreshRate(IdleTimerState idleTimerState); - // Touch timer feature's function to change the refresh rate. - void touchChangeRefreshRate(TouchState touchState); + // handles various timer features to change the refresh rate. + template <class T> + void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection); // Calculate the new refresh rate type RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters. @@ -282,6 +289,10 @@ private: int64_t mSetTouchTimerMs = 0; std::unique_ptr<scheduler::IdleTimer> mTouchTimer; + // Timer used to monitor display power mode. + int64_t mSetDisplayPowerTimerMs = 0; + std::unique_ptr<scheduler::IdleTimer> mDisplayPowerTimer; + std::mutex mCallbackLock; ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); @@ -293,9 +304,12 @@ private: ContentFeatureState::CONTENT_DETECTION_OFF; IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET; TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE; + DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) = + DisplayPowerTimerState::EXPIRED; uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock); RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock); bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false; + bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true; const scheduler::RefreshRateConfigs& mRefreshRateConfigs; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 96d9e88c56..6c2032ddb0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4543,6 +4543,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); mRefreshRateStats.setPowerMode(mode); + mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL); } ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 237208d39f..768074a6cd 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -242,6 +242,14 @@ int32_t set_touch_timer_ms(int32_t defaultValue) { return defaultValue; } +int32_t set_display_power_timer_ms(int32_t defaultValue) { + auto temp = SurfaceFlingerProperties::set_display_power_timer_ms(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + bool use_smart_90_for_video(bool defaultValue) { auto temp = SurfaceFlingerProperties::use_smart_90_for_video(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index b5418d6538..5f88322f71 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -77,6 +77,8 @@ int32_t set_idle_timer_ms(int32_t defaultValue); int32_t set_touch_timer_ms(int32_t defaultValue); +int32_t set_display_power_timer_ms(int32_t defaultValue); + bool use_smart_90_for_video(bool defaultValue); bool enable_protected_contents(bool defaultValue); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index f18f33c727..74baf37731 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -323,6 +323,18 @@ prop { prop_name: "ro.surface_flinger.set_touch_timer_ms" } +# setDisplayPowerTimerMs indicates what is considered a timeout in milliseconds for Scheduler. +# This value is used by the Scheduler to trigger display power inactivity callbacks that will +# keep the display in peak refresh rate as long as display power is not in normal mode. +# Setting this property to 0 means there is no timer. +prop { + api_name: "set_display_power_timer_ms" + type: Integer + scope: System + access: Readonly + prop_name: "ro.surface_flinger.set_display_power_timer_ms" +} + # useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the # screen refresh rate based on that. prop { diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt index 89323c2ad0..79854b36a2 100644 --- a/services/surfaceflinger/sysprop/api/system-current.txt +++ b/services/surfaceflinger/sysprop/api/system-current.txt @@ -18,6 +18,7 @@ package android.sysprop { method public static java.util.Optional<java.lang.Long> present_time_offset_from_vsync_ns(); method public static java.util.Optional<android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values> primary_display_orientation(); method public static java.util.Optional<java.lang.Boolean> running_without_sync_framework(); + method public static java.util.Optional<java.lang.Integer> set_display_power_timer_ms(); method public static java.util.Optional<java.lang.Integer> set_idle_timer_ms(); method public static java.util.Optional<java.lang.Integer> set_touch_timer_ms(); method public static java.util.Optional<java.lang.Boolean> start_graphics_allocator_service(); |