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

Commit 04c2e480 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "b:140112642:5" into qt-surfaceflinger-dev

* changes:
  SurfaceFlinger: clamp frame refresh duration to min refresh duration
  SurfaceFlinger: calculate expected present once
  [SurfaceFlinger] Exclude first vsync duration from period calculation
  SurfaceFlinger: tune LayerHistory to be less aggressive
  [SurfaceFlinger] Don't touch hw vsync in DEFAULT RR with kernel timeout
  SurfaceFlinger: add display power state timer
parents 306dc899 4344553c
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -668,7 +668,13 @@ void DispSync::updateModelLocked() {
        nsecs_t durationSum = 0;
        nsecs_t minDuration = INT64_MAX;
        nsecs_t maxDuration = 0;
        for (size_t i = 1; i < mNumResyncSamples; i++) {
        // We skip the first 2 samples because the first vsync duration on some
        // devices may be much more inaccurate than on other devices, e.g. due
        // to delays in ramping up from a power collapse. By doing so this
        // actually increases the accuracy of the DispSync model even though
        // we're effectively relying on fewer sample points.
        static constexpr size_t numSamplesSkipped = 2;
        for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
            size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
            size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
            nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
@@ -679,15 +685,14 @@ void DispSync::updateModelLocked() {

        // Exclude the min and max from the average
        durationSum -= minDuration + maxDuration;
        mPeriod = durationSum / (mNumResyncSamples - 3);
        mPeriod = durationSum / (mNumResyncSamples - numSamplesSkipped - 2);

        ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));

        double sampleAvgX = 0;
        double sampleAvgY = 0;
        double scale = 2.0 * M_PI / double(mPeriod);
        // Intentionally skip the first sample
        for (size_t i = 1; i < mNumResyncSamples; i++) {
        for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
            size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
            nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
            double samplePhase = double(sample % mPeriod) * scale;
@@ -695,8 +700,8 @@ void DispSync::updateModelLocked() {
            sampleAvgY += sin(samplePhase);
        }

        sampleAvgX /= double(mNumResyncSamples - 1);
        sampleAvgY /= double(mNumResyncSamples - 1);
        sampleAvgX /= double(mNumResyncSamples - numSamplesSkipped);
        sampleAvgY /= double(mNumResyncSamples - numSamplesSkipped);

        mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);

+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) {
    mLastPresentTime = lastPresentTime;
    // Ignore time diff that are too high - those are stale values
    if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
    const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
    const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration);
    const int fps = 1e9f / refreshDuration;
    mRefreshRateHistory.insertRefreshRate(fps);
}
+2 −2
Original line number Diff line number Diff line
@@ -129,8 +129,8 @@ class LayerInfo {

    private:
        std::deque<nsecs_t> mElements;
        static constexpr size_t HISTORY_SIZE = 10;
        static constexpr std::chrono::nanoseconds HISTORY_TIME = 500ms;
        static constexpr size_t HISTORY_SIZE = 90;
        static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
    };

public:
+77 −34
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");
@@ -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();
}
@@ -380,11 +393,17 @@ void Scheduler::updateFpsBasedOnContent() {
}

void Scheduler::setChangeRefreshRateCallback(
        const ChangeRefreshRateCallback& changeRefreshRateCallback) {
        const ChangeRefreshRateCallback&& changeRefreshRateCallback) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mChangeRefreshRateCallback = changeRefreshRateCallback;
}

void Scheduler::setGetCurrentRefreshRateTypeCallback(
        const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
}

void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mGetVsyncPeriod = getVsyncPeriod;
@@ -419,42 +438,76 @@ 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);
}

void Scheduler::resetKernelTimerCallback() {
    ATRACE_INT("ExpiredKernelIdleTimer", 0);
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mGetVsyncPeriod) {
    if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
        // If we're not in performance mode then the kernel timer shouldn't do
        // anything, as the refresh rate during DPU power collapse will be the
        // same.
        if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
            resyncToHardwareVsync(true, mGetVsyncPeriod());
        }
    }
}

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() {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    ATRACE_INT("ExpiredKernelIdleTimer", 1);
    if (mGetCurrentRefreshRateTypeCallback) {
        if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
            // Disable HW Vsync if the timer expired, as we don't need it
    // enabled if we're not pushing frames.
            // enabled if we're not pushing frames, and if we're in PERFORMANCE
            // mode then we'll need to re-update the DispSync model anyways.
            disableHardwareVsync(false);
        }
    }
}

std::string Scheduler::doDump() {
    std::ostringstream stream;
@@ -463,39 +516,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 +545,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;
+23 −5
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ public:
    }

    using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
    using GetCurrentRefreshRateTypeCallback = std::function<RefreshRateType()>;
    using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
    using GetVsyncPeriod = std::function<nsecs_t()>;

@@ -165,7 +166,9 @@ public:
    // Updates FPS based on the most content presented.
    void updateFpsBasedOnContent();
    // Callback that gets invoked when Scheduler wants to change the refresh rate.
    void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
    void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback);
    void setGetCurrentRefreshRateTypeCallback(
            const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType);
    void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod);

    // Returns whether idle timer is enabled or not
@@ -177,6 +180,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 +203,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 +228,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,7 +292,12 @@ 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;
    GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock);
    ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
    GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock);

@@ -293,9 +308,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;

Loading