Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6fe2c17e authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: add display power state timer

Coming out of DOZE mode might result in unstable HWVsync which may
confuse FPS detection logic to set the desired refresh rate.
To mitigate that, this change introduces a new timer that will provide
a grace period when coming out of DOZE while in this grace period refresh
rate will stay in PERFORMANCE.

Test: Toggle DOZE by hitting the power button and collect systrace
Bug: 135550670
Change-Id: Ib8ec3c9550336d691dd3868405d20b98aa983302
parent b9ce711f
Loading
Loading
Loading
Loading
+51 −28
Original line number Diff line number Diff line
@@ -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");
@@ -105,10 +106,19 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
                [this] { expiredTouchTimerCallback(); });
        mTouchTimer->start();
    }

    if (mSetDisplayPowerTimerMs > 0) {
        mDisplayPowerTimer = std::make_unique<scheduler::OneShotTimer>(
                std::chrono::milliseconds(mSetDisplayPowerTimerMs),
                [this] { resetDisplayPowerTimerCallback(); },
                [this] { expiredDisplayPowerTimerCallback(); });
        mDisplayPowerTimer->start();
    }
}

Scheduler::~Scheduler() {
    // Ensure the OneShotTimer threads are joined before we start destroying state.
    mDisplayPowerTimer.reset();
    mTouchTimer.reset();
    mIdleTimer.reset();
}
@@ -414,8 +424,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);
}

@@ -428,22 +453,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
@@ -458,39 +491,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;
        }
    }
@@ -503,6 +520,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;
+18 −4
Original line number Diff line number Diff line
@@ -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::OneShotTimer> mTouchTimer;

    // Timer used to monitor display power mode.
    int64_t mSetDisplayPowerTimerMs = 0;
    std::unique_ptr<scheduler::OneShotTimer> 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;

+1 −0
Original line number Diff line number Diff line
@@ -4542,6 +4542,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());
+8 −0
Original line number Diff line number Diff line
@@ -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()) {
+2 −0
Original line number Diff line number Diff line
@@ -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);
Loading