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

Commit ac782745 authored by Wiwit Rifa'i's avatar Wiwit Rifa'i Committed by Automerger Merge Worker
Browse files

Merge changes from topic "idle_timer_per_display" into sc-v2-dev am: 95720276 am: 75c72dea

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/15935887

Change-Id: Idcfc95ce0f44448aae7f217aa4f7501cb94af155
parents 1d07b101 75c72dea
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#pragma clang diagnostic ignored "-Wextra"

#include "RefreshRateConfigs.h"
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <utils/Trace.h>
#include <chrono>
@@ -714,9 +715,31 @@ void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) {
RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
                                       Config config)
      : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
    initializeIdleTimer();
    updateDisplayModes(modes, currentModeId);
}

void RefreshRateConfigs::initializeIdleTimer() {
    if (mConfig.idleTimerTimeoutMs > 0) {
        const auto getCallback = [this]() -> std::optional<IdleTimerCallbacks::Callbacks> {
            std::scoped_lock lock(mIdleTimerCallbacksMutex);
            if (!mIdleTimerCallbacks.has_value()) return {};
            return mConfig.supportKernelIdleTimer ? mIdleTimerCallbacks->kernel
                                                  : mIdleTimerCallbacks->platform;
        };

        mIdleTimer.emplace(
                "IdleTimer", std::chrono::milliseconds(mConfig.idleTimerTimeoutMs),
                [getCallback] {
                    if (const auto callback = getCallback()) callback->onReset();
                },
                [getCallback] {
                    if (const auto callback = getCallback()) callback->onExpired();
                });
        mIdleTimer->start();
    }
}

void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
                                            DisplayModeId currentModeId) {
    std::lock_guard lock(mLock);
@@ -990,6 +1013,9 @@ void RefreshRateConfigs::dump(std::string& result) const {

    base::StringAppendF(&result, "Supports Frame Rate Override: %s\n",
                        mSupportsFrameRateOverride ? "yes" : "no");
    base::StringAppendF(&result, "Idle timer: (%s) %s\n",
                        mConfig.supportKernelIdleTimer ? "kernel" : "platform",
                        mIdleTimer ? mIdleTimer->dump().c_str() : "off");
    result.append("\n");
}

+53 −2
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/HWComposer.h"
#include "Fps.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/SchedulerUtils.h"
#include "Scheduler/Seamlessness.h"
#include "Scheduler/StrongTyping.h"
@@ -305,11 +306,19 @@ public:
        // or heuristic, such that refresh rates higher than this value will not be voted for. 0 if
        // no threshold is set.
        int frameRateMultipleThreshold = 0;

        // The Idle Timer timeout. 0 timeout means no idle timer.
        int32_t idleTimerTimeoutMs = 0;

        // Whether to use idle timer callbacks that support the kernel timer.
        bool supportKernelIdleTimer = false;
    };

    RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
    RefreshRateConfigs(const DisplayModes&, DisplayModeId,
                       Config config = {.enableFrameRateOverride = false,
                                        .frameRateMultipleThreshold = 0});
                                        .frameRateMultipleThreshold = 0,
                                        .idleTimerTimeoutMs = 0,
                                        .supportKernelIdleTimer = false});

    // Returns whether switching modes (refresh rate or resolution) is possible.
    // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only
@@ -349,6 +358,30 @@ public:
                                                 Fps displayFrameRate, bool touch) const
            EXCLUDES(mLock);

    bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; }

    void setIdleTimerCallbacks(std::function<void()> platformTimerReset,
                               std::function<void()> platformTimerExpired,
                               std::function<void()> kernelTimerReset,
                               std::function<void()> kernelTimerExpired) {
        std::scoped_lock lock(mIdleTimerCallbacksMutex);
        mIdleTimerCallbacks.emplace();
        mIdleTimerCallbacks->platform.onReset = platformTimerReset;
        mIdleTimerCallbacks->platform.onExpired = platformTimerExpired;
        mIdleTimerCallbacks->kernel.onReset = kernelTimerReset;
        mIdleTimerCallbacks->kernel.onExpired = kernelTimerExpired;
    }

    void resetIdleTimer(bool kernelOnly) {
        if (!mIdleTimer) {
            return;
        }
        if (kernelOnly && !mConfig.supportKernelIdleTimer) {
            return;
        }
        mIdleTimer->reset();
    };

    void dump(std::string& result) const EXCLUDES(mLock);

    RefreshRateConfigs(const RefreshRateConfigs&) = delete;
@@ -414,6 +447,8 @@ private:

    void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);

    void initializeIdleTimer();

    // The list of refresh rates, indexed by display modes ID. This may change after this
    // object is initialized.
    AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
@@ -457,6 +492,22 @@ private:
    };
    mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation
            GUARDED_BY(mLock);

    // Timer that records time between requests for next vsync.
    std::optional<scheduler::OneShotTimer> mIdleTimer;

    struct IdleTimerCallbacks {
        struct Callbacks {
            std::function<void()> onReset;
            std::function<void()> onExpired;
        };

        Callbacks platform;
        Callbacks kernel;
    };

    std::mutex mIdleTimerCallbacksMutex;
    std::optional<IdleTimerCallbacks> mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex);
};

} // namespace android::scheduler
+9 −25
Original line number Diff line number Diff line
@@ -120,28 +120,15 @@ private:
Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
                     ISchedulerCallback& callback)
      : Scheduler(configs, callback,
                  {.supportKernelTimer = sysprop::support_kernel_idle_timer(false),
                   .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
                  {.useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
}

Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
                     ISchedulerCallback& callback, Options options)
      : Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback,
      : Scheduler(createVsyncSchedule(configs->supportsKernelIdleTimer()), configs, callback,
                  createLayerHistory(), options) {
    using namespace sysprop;

    const int setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms"s, 0);

    if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
        const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback
                                                          : &Scheduler::idleTimerCallback;
        mIdleTimer.emplace(
                "IdleTimer", std::chrono::milliseconds(millis),
                [this, callback] { std::invoke(callback, this, TimerState::Reset); },
                [this, callback] { std::invoke(callback, this, TimerState::Expired); });
        mIdleTimer->start();
    }

    if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
        // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
        mTouchTimer.emplace(
@@ -168,11 +155,11 @@ Scheduler::Scheduler(VsyncSchedule schedule,
        mVsyncSchedule(std::move(schedule)),
        mLayerHistory(std::move(layerHistory)),
        mSchedulerCallback(schedulerCallback),
        mRefreshRateConfigs(configs),
        mPredictedVsyncTracer(
                base::GetBoolProperty("debug.sf.show_predicted_vsync", false)
                        ? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch)
                        : nullptr) {
    setRefreshRateConfigs(configs);
    mSchedulerCallback.setVsyncEnabled(false);
}

@@ -180,7 +167,7 @@ Scheduler::~Scheduler() {
    // Ensure the OneShotTimer threads are joined before we start destroying state.
    mDisplayPowerTimer.reset();
    mTouchTimer.reset();
    mIdleTimer.reset();
    mRefreshRateConfigs.reset();
}

Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) {
@@ -672,18 +659,16 @@ void Scheduler::chooseRefreshRateForContent() {
}

void Scheduler::resetIdleTimer() {
    if (mIdleTimer) {
        mIdleTimer->reset();
    }
    std::scoped_lock lock(mRefreshRateConfigsLock);
    mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ false);
}

void Scheduler::onTouchHint() {
    if (mTouchTimer) {
        mTouchTimer->reset();

        if (mOptions.supportKernelTimer && mIdleTimer) {
            mIdleTimer->reset();
        }
        std::scoped_lock lock(mRefreshRateConfigsLock);
        mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ true);
    }
}

@@ -755,7 +740,6 @@ void Scheduler::displayPowerTimerCallback(TimerState state) {
void Scheduler::dump(std::string& result) const {
    using base::StringAppendF;

    StringAppendF(&result, "+  Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off");
    StringAppendF(&result, "+  Touch timer: %s\n",
                  mTouchTimer ? mTouchTimer->dump().c_str() : "off");
    StringAppendF(&result, "+  Content detection: %s %s\n\n",
@@ -867,7 +851,7 @@ DisplayModePtr Scheduler::calculateRefreshRateModeId(
    }

    const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
    const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;
    const bool idle = mFeatures.idleTimer == TimerState::Expired;

    return refreshRateConfigs
            ->getBestRefreshRate(mFeatures.contentRequirements,
+9 −5
Original line number Diff line number Diff line
@@ -136,7 +136,6 @@ public:
    // Detects content using layer history, and selects a matching refresh rate.
    void chooseRefreshRateForContent() EXCLUDES(mRefreshRateConfigsLock);

    bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
    void resetIdleTimer();

    // Indicates that touch interaction is taking place.
@@ -187,6 +186,15 @@ public:
            EXCLUDES(mRefreshRateConfigsLock) {
        std::scoped_lock lock(mRefreshRateConfigsLock);
        mRefreshRateConfigs = std::move(refreshRateConfigs);
        mRefreshRateConfigs->setIdleTimerCallbacks(
                [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Reset); },
                [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Expired); },
                [this] {
                    std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Reset);
                },
                [this] {
                    std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Expired);
                });
    }

    nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
@@ -206,8 +214,6 @@ private:
    enum class TouchState { Inactive, Active };

    struct Options {
        // Whether to use idle timer callbacks that support the kernel timer.
        bool supportKernelTimer;
        // Whether to use content detection at all.
        bool useContentDetection;
    };
@@ -293,8 +299,6 @@ private:
    // Used to choose refresh rate if content detection is enabled.
    std::unique_ptr<LayerHistory> mLayerHistory;

    // Timer that records time between requests for next vsync.
    std::optional<scheduler::OneShotTimer> mIdleTimer;
    // Timer used to monitor touch events.
    std::optional<scheduler::OneShotTimer> mTouchTimer;
    // Timer used to monitor display power mode.
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker,
      : mClock(std::move(clock)),
        mTracker(tracker),
        mPendingLimit(pendingFenceLimit),
        // TODO(adyabr): change mSupportKernelIdleTimer when the active display changes
        mSupportKernelIdleTimer(supportKernelIdleTimer) {}

VSyncReactor::~VSyncReactor() = default;
Loading