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

Commit 1fe71429 authored by Alec Mouri's avatar Alec Mouri Committed by android-build-merger
Browse files

Merge changes from topic "sf-kernel-idle-timeout" into qt-dev

am: 0e7098cf

Change-Id: I10d605fc4bc7eb0dc60a2927ebd6840463866b0c
parents a39d4166 0e7098cf
Loading
Loading
Loading
Loading
+33 −1
Original line number Original line Diff line number Diff line
@@ -64,6 +64,7 @@ public:
    DispSyncThread(const char* name, bool showTraceDetailedInfo)
    DispSyncThread(const char* name, bool showTraceDetailedInfo)
          : mName(name),
          : mName(name),
            mStop(false),
            mStop(false),
            mModelLocked(false),
            mPeriod(0),
            mPeriod(0),
            mPhase(0),
            mPhase(0),
            mReferenceTime(0),
            mReferenceTime(0),
@@ -78,6 +79,11 @@ public:
        Mutex::Autolock lock(mMutex);
        Mutex::Autolock lock(mMutex);


        mPhase = phase;
        mPhase = phase;
        if (mReferenceTime != referenceTime) {
            for (auto& eventListener : mEventListeners) {
                eventListener.mHasFired = false;
            }
        }
        mReferenceTime = referenceTime;
        mReferenceTime = referenceTime;
        if (mPeriod != 0 && mPeriod != period && mReferenceTime != 0) {
        if (mPeriod != 0 && mPeriod != period && mReferenceTime != 0) {
            // Inflate the reference time to be the most recent predicted
            // Inflate the reference time to be the most recent predicted
@@ -106,6 +112,16 @@ public:
        mCond.signal();
        mCond.signal();
    }
    }


    void lockModel() {
        Mutex::Autolock lock(mMutex);
        mModelLocked = true;
    }

    void unlockModel() {
        Mutex::Autolock lock(mMutex);
        mModelLocked = false;
    }

    virtual bool threadLoop() {
    virtual bool threadLoop() {
        status_t err;
        status_t err;
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -288,6 +304,7 @@ private:
        nsecs_t mLastEventTime;
        nsecs_t mLastEventTime;
        nsecs_t mLastCallbackTime;
        nsecs_t mLastCallbackTime;
        DispSync::Callback* mCallback;
        DispSync::Callback* mCallback;
        bool mHasFired = false;
    };
    };


    struct CallbackInvocation {
    struct CallbackInvocation {
@@ -335,6 +352,12 @@ private:
                          eventListener.mName);
                          eventListener.mName);
                    continue;
                    continue;
                }
                }
                if (eventListener.mHasFired && !mModelLocked) {
                    eventListener.mLastEventTime = t;
                    ALOGV("[%s] [%s] Skipping event due to already firing", mName,
                          eventListener.mName);
                    continue;
                }
                CallbackInvocation ci;
                CallbackInvocation ci;
                ci.mCallback = eventListener.mCallback;
                ci.mCallback = eventListener.mCallback;
                ci.mEventTime = t;
                ci.mEventTime = t;
@@ -343,6 +366,7 @@ private:
                callbackInvocations.push_back(ci);
                callbackInvocations.push_back(ci);
                eventListener.mLastEventTime = t;
                eventListener.mLastEventTime = t;
                eventListener.mLastCallbackTime = now;
                eventListener.mLastCallbackTime = now;
                eventListener.mHasFired = true;
            }
            }
        }
        }


@@ -410,6 +434,7 @@ private:
    const char* const mName;
    const char* const mName;


    bool mStop;
    bool mStop;
    bool mModelLocked;


    nsecs_t mPeriod;
    nsecs_t mPeriod;
    nsecs_t mPhase;
    nsecs_t mPhase;
@@ -497,6 +522,7 @@ void DispSync::resetLocked() {
    mNumResyncSamples = 0;
    mNumResyncSamples = 0;
    mFirstResyncSample = 0;
    mFirstResyncSample = 0;
    mNumResyncSamplesSincePresent = 0;
    mNumResyncSamplesSincePresent = 0;
    mThread->unlockModel();
    resetErrorLocked();
    resetErrorLocked();
}
}


@@ -519,6 +545,7 @@ bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
void DispSync::beginResync() {
void DispSync::beginResync() {
    Mutex::Autolock lock(mMutex);
    Mutex::Autolock lock(mMutex);
    ALOGV("[%s] beginResync", mName);
    ALOGV("[%s] beginResync", mName);
    mThread->unlockModel();
    mModelUpdated = false;
    mModelUpdated = false;
    mNumResyncSamples = 0;
    mNumResyncSamples = 0;
}
}
@@ -581,10 +608,15 @@ bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) {
    // resync again
    // resync again
    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0;
    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0;
    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
    if (modelLocked) {
        mThread->lockModel();
    }
    return !modelLocked;
    return !modelLocked;
}
}


void DispSync::endResync() {}
void DispSync::endResync() {
    mThread->lockModel();
}


status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback,
status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback,
                                    nsecs_t lastCallbackTime) {
                                    nsecs_t lastCallbackTime) {
+5 −2
Original line number Original line Diff line number Diff line
@@ -84,7 +84,10 @@ void IdleTimer::loop() {
                constexpr auto zero = std::chrono::steady_clock::duration::zero();
                constexpr auto zero = std::chrono::steady_clock::duration::zero();
                auto waitTime = triggerTime - std::chrono::steady_clock::now();
                auto waitTime = triggerTime - std::chrono::steady_clock::now();
                if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
                if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
                if (mState == TimerState::WAITING &&
                if (mState == TimerState::RESET) {
                    triggerTime = std::chrono::steady_clock::now() + mInterval;
                    mState = TimerState::WAITING;
                } else if (mState == TimerState::WAITING &&
                           (triggerTime - std::chrono::steady_clock::now()) <= zero) {
                           (triggerTime - std::chrono::steady_clock::now()) <= zero) {
                    triggerTimeout = true;
                    triggerTimeout = true;
                    mState = TimerState::IDLE;
                    mState = TimerState::IDLE;
+20 −1
Original line number Original line Diff line number Diff line
@@ -39,13 +39,31 @@ public:
              const TimeoutCallback& timeoutCallback);
              const TimeoutCallback& timeoutCallback);
    ~IdleTimer();
    ~IdleTimer();


    // Initializes and turns on the idle timer.
    void start();
    void start();
    // Stops the idle timer and any held resources.
    void stop();
    void stop();
    // Resets the wakeup time and fires the reset callback.
    void reset();
    void reset();


private:
private:
    // Enum to track in what state is the timer.
    // Enum to track in what state is the timer.
    enum class TimerState { STOPPED = 0, RESET = 1, WAITING = 2, IDLE = 3 };
    enum class TimerState {
        // The internal timer thread has been destroyed, and no state is
        // tracked.
        // Possible state transitions: RESET
        STOPPED = 0,
        // An external thread has just reset this timer.
        // If there is a reset callback, then that callback is fired.
        // Possible state transitions: STOPPED, WAITING
        RESET = 1,
        // This timer is waiting for the timeout interval to expire.
        // Possible state transaitions: STOPPED, RESET, IDLE
        WAITING = 2,
        // The timeout interval has expired, so we are sleeping now.
        // Possible state transaitions: STOPPED, RESET
        IDLE = 3
    };


    // Function that loops until the condition for stopping is met.
    // Function that loops until the condition for stopping is met.
    void loop();
    void loop();
@@ -59,6 +77,7 @@ private:
    // Lock used for synchronizing the waiting thread with the application thread.
    // Lock used for synchronizing the waiting thread with the application thread.
    std::mutex mMutex;
    std::mutex mMutex;


    // Current timer state
    TimerState mState GUARDED_BY(mMutex) = TimerState::RESET;
    TimerState mState GUARDED_BY(mMutex) = TimerState::RESET;


    // Interval after which timer expires.
    // Interval after which timer expires.
+35 −6
Original line number Original line Diff line number Diff line
@@ -73,6 +73,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
    mEventControlThread = std::make_unique<impl::EventControlThread>(function);
    mEventControlThread = std::make_unique<impl::EventControlThread>(function);


    mSetIdleTimerMs = set_idle_timer_ms(0);
    mSetIdleTimerMs = set_idle_timer_ms(0);
    mSupportKernelTimer = support_kernel_idle_timer(false);


    char value[PROPERTY_VALUE_MAX];
    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.set_idle_timer_ms", value, "0");
    property_get("debug.sf.set_idle_timer_ms", value, "0");
@@ -82,10 +83,20 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
    }
    }


    if (mSetIdleTimerMs > 0) {
    if (mSetIdleTimerMs > 0) {
        if (mSupportKernelTimer) {
            mIdleTimer =
            mIdleTimer =
                std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetIdleTimerMs),
                    std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
                                                                   mSetIdleTimerMs),
                                                           [this] { resetKernelTimerCallback(); },
                                                           [this] {
                                                               expiredKernelTimerCallback();
                                                           });
        } else {
            mIdleTimer = std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
                                                                        mSetIdleTimerMs),
                                                                [this] { resetTimerCallback(); },
                                                                [this] { resetTimerCallback(); },
                                                                [this] { expiredTimerCallback(); });
                                                                [this] { expiredTimerCallback(); });
        }
        mIdleTimer->start();
        mIdleTimer->start();
    }
    }
}
}
@@ -354,6 +365,11 @@ void Scheduler::setChangeRefreshRateCallback(
    mChangeRefreshRateCallback = changeRefreshRateCallback;
    mChangeRefreshRateCallback = changeRefreshRateCallback;
}
}


void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mGetVsyncPeriod = getVsyncPeriod;
}

void Scheduler::updateFrameSkipping(const int64_t skipCount) {
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
    ATRACE_INT("FrameSkipCount", skipCount);
    ATRACE_INT("FrameSkipCount", skipCount);
    if (mSkipCount != skipCount) {
    if (mSkipCount != skipCount) {
@@ -370,17 +386,30 @@ void Scheduler::resetIdleTimer() {
}
}


void Scheduler::resetTimerCallback() {
void Scheduler::resetTimerCallback() {
    // We do not notify the applications about config changes when idle timer is reset.
    timerChangeRefreshRate(IdleTimerState::RESET);
    timerChangeRefreshRate(IdleTimerState::RESET);
    ATRACE_INT("ExpiredIdleTimer", 0);
    ATRACE_INT("ExpiredIdleTimer", 0);
}
}


void Scheduler::resetKernelTimerCallback() {
    ATRACE_INT("ExpiredKernelIdleTimer", 0);
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mGetVsyncPeriod) {
        resyncToHardwareVsync(false, mGetVsyncPeriod());
    }
}

void Scheduler::expiredTimerCallback() {
void Scheduler::expiredTimerCallback() {
    // We do not notify the applications about config changes when idle timer expires.
    timerChangeRefreshRate(IdleTimerState::EXPIRED);
    timerChangeRefreshRate(IdleTimerState::EXPIRED);
    ATRACE_INT("ExpiredIdleTimer", 1);
    ATRACE_INT("ExpiredIdleTimer", 1);
}
}


void Scheduler::expiredKernelTimerCallback() {
    ATRACE_INT("ExpiredKernelIdleTimer", 1);
    // Disable HW Vsync if the timer expired, as we don't need it
    // enabled if we're not pushing frames.
    disableHardwareVsync(false);
}

std::string Scheduler::doDump() {
std::string Scheduler::doDump() {
    std::ostringstream stream;
    std::ostringstream stream;
    stream << "+  Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
    stream << "+  Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
+13 −0
Original line number Original line Diff line number Diff line
@@ -160,6 +160,7 @@ public:
    void updateFpsBasedOnContent();
    void updateFpsBasedOnContent();
    // Callback that gets invoked when Scheduler wants to change the refresh rate.
    // Callback that gets invoked when Scheduler wants to change the refresh rate.
    void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
    void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
    void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod);


    // Returns whether idle timer is enabled or not
    // Returns whether idle timer is enabled or not
    bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
    bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
@@ -194,6 +195,14 @@ private:
    void resetTimerCallback();
    void resetTimerCallback();
    // Function that is called when the timer expires.
    // Function that is called when the timer expires.
    void expiredTimerCallback();
    void expiredTimerCallback();
    // Function that is called when the timer resets when paired with a display
    // driver timeout in the kernel. This enables hardware vsync when we move
    // out from idle.
    void resetKernelTimerCallback();
    // Function that is called when the timer expires when paired with a display
    // driver timeout in the kernel. This disables hardware vsync when we move
    // into idle.
    void expiredKernelTimerCallback();
    // Sets vsync period.
    // Sets vsync period.
    void setVsyncPeriod(const nsecs_t period);
    void setVsyncPeriod(const nsecs_t period);
    // Idle timer feature's function to change the refresh rate.
    // Idle timer feature's function to change the refresh rate.
@@ -245,9 +254,13 @@ private:
    // interval, a callback is fired. Set this variable to >0 to use this feature.
    // interval, a callback is fired. Set this variable to >0 to use this feature.
    int64_t mSetIdleTimerMs = 0;
    int64_t mSetIdleTimerMs = 0;
    std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
    std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
    // Enables whether to use idle timer callbacks that support the kernel
    // timer.
    bool mSupportKernelTimer;


    std::mutex mCallbackLock;
    std::mutex mCallbackLock;
    ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
    ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
    GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock);


    // In order to make sure that the features don't override themselves, we need a state machine
    // In order to make sure that the features don't override themselves, we need a state machine
    // to keep track which feature requested the config change.
    // to keep track which feature requested the config change.
Loading