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

Commit bd772df4 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "sf_ idle_screen_timeout" into main

* changes:
  SF: use DM setting for idle timer
  SF: import idle_screen_refresh_rate_timeout from DM
parents b3a14cec 67231728
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -115,9 +115,24 @@ void OneShotTimer::loop() {
            break;
        }

        auto triggerTime = mClock->now() + mInterval;
        auto triggerTime = mClock->now() + mInterval.load();
        state = TimerState::WAITING;
        while (true) {
            if (mPaused) {
                mWaiting = true;
                int result = sem_wait(&mSemaphore);
                if (result && errno != EINTR) {
                    std::stringstream ss;
                    ss << "sem_wait failed (" << errno << ")";
                    LOG_ALWAYS_FATAL("%s", ss.str().c_str());
                }

                mWaiting = false;
                state = checkForResetAndStop(state);
                if (state == TimerState::STOPPED) {
                    break;
                }
            }
            // Wait until triggerTime time to check if we need to reset or drop into the idle state.
            if (const auto triggerInterval = triggerTime - mClock->now(); triggerInterval > 0ns) {
                mWaiting = true;
@@ -137,14 +152,14 @@ void OneShotTimer::loop() {
                break;
            }

            if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= 0ns) {
            if (!mPaused && state == TimerState::WAITING && (triggerTime - mClock->now()) <= 0ns) {
                triggerTimeout = true;
                state = TimerState::IDLE;
                break;
            }

            if (state == TimerState::RESET) {
                triggerTime = mLastResetTime.load() + mInterval;
                triggerTime = mLastResetTime.load() + mInterval.load();
                state = TimerState::WAITING;
            }
        }
@@ -179,5 +194,15 @@ void OneShotTimer::reset() {
    }
}

void OneShotTimer::pause() {
    mPaused = true;
}

void OneShotTimer::resume() {
    if (mPaused.exchange(false)) {
        LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
    }
}

} // namespace scheduler
} // namespace android
+8 −2
Original line number Diff line number Diff line
@@ -43,7 +43,8 @@ public:
                 std::unique_ptr<android::Clock> clock = std::make_unique<SteadyClock>());
    ~OneShotTimer();

    Duration interval() const { return mInterval; }
    Duration interval() const { return mInterval.load(); }
    void setInterval(Interval value) { mInterval = value; }

    // Initializes and turns on the idle timer.
    void start();
@@ -51,6 +52,10 @@ public:
    void stop();
    // Resets the wakeup time and fires the reset callback.
    void reset();
    // Pauses the timer. reset calls will get ignored.
    void pause();
    // Resumes the timer.
    void resume();

private:
    // Enum to track in what state is the timer.
@@ -91,7 +96,7 @@ private:
    std::string mName;

    // Interval after which timer expires.
    const Interval mInterval;
    std::atomic<Interval> mInterval;

    // Callback that happens when timer resets.
    const ResetCallback mResetCallback;
@@ -105,6 +110,7 @@ private:
    std::atomic<bool> mResetTriggered = false;
    std::atomic<bool> mStopTriggered = false;
    std::atomic<bool> mWaiting = false;
    std::atomic<bool> mPaused = false;
    std::atomic<std::chrono::steady_clock::time_point> mLastResetTime;
};

+44 −9
Original line number Diff line number Diff line
@@ -285,11 +285,12 @@ struct RefreshRateSelector::RefreshRateScoreComparator {

std::string RefreshRateSelector::Policy::toString() const {
    return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
                              ", primaryRanges=%s, appRequestRanges=%s}",
                              ", primaryRanges=%s, appRequestRanges=%s idleScreenConfig=%s}",
                              ftl::to_underlying(defaultMode),
                              allowGroupSwitching ? "true" : "false",
                              to_string(primaryRanges).c_str(),
                              to_string(appRequestRanges).c_str());
                              to_string(primaryRanges).c_str(), to_string(appRequestRanges).c_str(),
                              idleScreenConfigOpt ? idleScreenConfigOpt->toString().c_str()
                                                  : "nullptr");
}

std::pair<nsecs_t, nsecs_t> RefreshRateSelector::getDisplayFrames(nsecs_t layerPeriod,
@@ -1255,14 +1256,14 @@ void RefreshRateSelector::setActiveMode(DisplayModeId modeId, Fps renderFrameRat
RefreshRateSelector::RefreshRateSelector(DisplayModes modes, DisplayModeId activeModeId,
                                         Config config)
      : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
    initializeIdleTimer();
    initializeIdleTimer(mConfig.legacyIdleTimerTimeout);
    FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId));
}

void RefreshRateSelector::initializeIdleTimer() {
    if (mConfig.idleTimerTimeout > 0ms) {
void RefreshRateSelector::initializeIdleTimer(std::chrono::milliseconds timeout) {
    if (timeout > 0ms) {
        mIdleTimer.emplace(
                "IdleTimer", mConfig.idleTimerTimeout,
                "IdleTimer", timeout,
                [this] {
                    std::scoped_lock lock(mIdleTimerCallbacksMutex);
                    if (const auto callbacks = getIdleTimerCallbacks()) {
@@ -1385,9 +1386,40 @@ auto RefreshRateSelector::setPolicy(const PolicyVariant& policy) -> SetPolicyRes

        mGetRankedFrameRatesCache.reset();

        if (*getCurrentPolicyLocked() == oldPolicy) {
        const auto& idleScreenConfigOpt = getCurrentPolicyLocked()->idleScreenConfigOpt;
        if (idleScreenConfigOpt != oldPolicy.idleScreenConfigOpt) {
            if (!idleScreenConfigOpt.has_value()) {
                // fallback to legacy timer if existed, otherwise pause the old timer
                LOG_ALWAYS_FATAL_IF(!mIdleTimer);
                if (mConfig.legacyIdleTimerTimeout > 0ms) {
                    mIdleTimer->setInterval(mConfig.legacyIdleTimerTimeout);
                    mIdleTimer->resume();
                } else {
                    mIdleTimer->pause();
                }
            } else if (idleScreenConfigOpt->timeoutMillis > 0) {
                // create a new timer or reconfigure
                const auto timeout = std::chrono::milliseconds{idleScreenConfigOpt->timeoutMillis};
                if (!mIdleTimer) {
                    initializeIdleTimer(timeout);
                    if (mIdleTimerStarted) {
                        mIdleTimer->start();
                    }
                } else {
                    mIdleTimer->setInterval(timeout);
                    mIdleTimer->resume();
                }
            } else {
                if (mIdleTimer) {
                    mIdleTimer->pause();
                }
            }
        }

        if (getCurrentPolicyLocked()->similarExceptIdleConfig(oldPolicy)) {
            return SetPolicyResult::Unchanged;
        }

        constructAvailableRefreshRates();

        displayId = getActiveModeLocked().modePtr->getPhysicalDisplayId();
@@ -1589,7 +1621,10 @@ void RefreshRateSelector::dump(utils::Dumper& dumper) const {
}

std::chrono::milliseconds RefreshRateSelector::getIdleTimerTimeout() {
    return mConfig.idleTimerTimeout;
    if (FlagManager::getInstance().idle_screen_refresh_rate_timeout() && mIdleTimer) {
        return std::chrono::duration_cast<std::chrono::milliseconds>(mIdleTimer->interval());
    }
    return mConfig.legacyIdleTimerTimeout;
}

// TODO(b/293651105): Extract category FpsRange mapping to OEM-configurable config.
+26 −10
Original line number Diff line number Diff line
@@ -67,26 +67,32 @@ public:
        FpsRanges primaryRanges;
        // The app request refresh rate ranges. @see DisplayModeSpecs.aidl for details.
        FpsRanges appRequestRanges;
        // The idle timer configuration, if provided.
        std::optional<gui::DisplayModeSpecs::IdleScreenRefreshRateConfig> idleScreenConfigOpt;

        Policy() = default;

        Policy(DisplayModeId defaultMode, FpsRange range,
               bool allowGroupSwitching = kAllowGroupSwitchingDefault)
               bool allowGroupSwitching = kAllowGroupSwitchingDefault,
               const std::optional<gui::DisplayModeSpecs::IdleScreenRefreshRateConfig>&
                       idleScreenConfigOpt = std::nullopt)
              : Policy(defaultMode, FpsRanges{range, range}, FpsRanges{range, range},
                       allowGroupSwitching) {}
                       allowGroupSwitching, idleScreenConfigOpt) {}

        Policy(DisplayModeId defaultMode, FpsRanges primaryRanges, FpsRanges appRequestRanges,
               bool allowGroupSwitching = kAllowGroupSwitchingDefault)
               bool allowGroupSwitching = kAllowGroupSwitchingDefault,
               const std::optional<gui::DisplayModeSpecs::IdleScreenRefreshRateConfig>&
                       idleScreenConfigOpt = std::nullopt)
              : defaultMode(defaultMode),
                allowGroupSwitching(allowGroupSwitching),
                primaryRanges(primaryRanges),
                appRequestRanges(appRequestRanges) {}
                appRequestRanges(appRequestRanges),
                idleScreenConfigOpt(idleScreenConfigOpt) {}

        bool operator==(const Policy& other) const {
            using namespace fps_approx_ops;
            return defaultMode == other.defaultMode && primaryRanges == other.primaryRanges &&
                    appRequestRanges == other.appRequestRanges &&
                    allowGroupSwitching == other.allowGroupSwitching;
            return similarExceptIdleConfig(other) &&
                    idleScreenConfigOpt == other.idleScreenConfigOpt;
        }

        bool operator!=(const Policy& other) const { return !(*this == other); }
@@ -95,6 +101,13 @@ public:
            return isApproxEqual(primaryRanges.physical.min, primaryRanges.physical.max);
        }

        bool similarExceptIdleConfig(const Policy& updated) const {
            using namespace fps_approx_ops;
            return defaultMode == updated.defaultMode && primaryRanges == updated.primaryRanges &&
                    appRequestRanges == updated.appRequestRanges &&
                    allowGroupSwitching == updated.allowGroupSwitching;
        }

        std::string toString() const;
    };

@@ -291,7 +304,7 @@ public:
        int frameRateMultipleThreshold = 0;

        // The Idle Timer timeout. 0 timeout means no idle timer.
        std::chrono::milliseconds idleTimerTimeout = 0ms;
        std::chrono::milliseconds legacyIdleTimerTimeout = 0ms;

        // The controller representing how the kernel idle timer will be configured
        // either on the HWC api or sysprop.
@@ -302,7 +315,7 @@ public:
            DisplayModes, DisplayModeId activeModeId,
            Config config = {.enableFrameRateOverride = Config::FrameRateOverride::Disabled,
                             .frameRateMultipleThreshold = 0,
                             .idleTimerTimeout = 0ms,
                             .legacyIdleTimerTimeout = 0ms,
                             .kernelIdleTimerController = {}});

    RefreshRateSelector(const RefreshRateSelector&) = delete;
@@ -383,12 +396,14 @@ public:
    }

    void startIdleTimer() {
        mIdleTimerStarted = true;
        if (mIdleTimer) {
            mIdleTimer->start();
        }
    }

    void stopIdleTimer() {
        mIdleTimerStarted = false;
        if (mIdleTimer) {
            mIdleTimer->stop();
        }
@@ -481,7 +496,7 @@ private:
    void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock)
            REQUIRES(kMainThreadContext);

    void initializeIdleTimer();
    void initializeIdleTimer(std::chrono::milliseconds timeout);

    std::optional<IdleTimerCallbacks::Callbacks> getIdleTimerCallbacks() const
            REQUIRES(mIdleTimerCallbacksMutex) {
@@ -562,6 +577,7 @@ private:
    std::optional<IdleTimerCallbacks> mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex);
    // Used to detect (lack of) frame activity.
    ftl::Optional<scheduler::OneShotTimer> mIdleTimer;
    std::atomic<bool> mIdleTimerStarted = false;
};

} // namespace android::scheduler
+7 −2
Original line number Diff line number Diff line
@@ -3588,7 +3588,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
                {.enableFrameRateOverride = enableFrameRateOverride,
                 .frameRateMultipleThreshold =
                         base::GetIntProperty("debug.sf.frame_rate_multiple_threshold"s, 0),
                 .idleTimerTimeout = idleTimerTimeoutMs,
                 .legacyIdleTimerTimeout = idleTimerTimeoutMs,
                 .kernelIdleTimerController = kernelIdleTimerController};

        creationArgs.refreshRateSelector =
@@ -8639,8 +8639,13 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs(const sp<IBinder>& displayTo
            return INVALID_OPERATION;
        } else {
            using Policy = scheduler::RefreshRateSelector::DisplayManagerPolicy;
            const auto idleScreenConfigOpt =
                    FlagManager::getInstance().idle_screen_refresh_rate_timeout()
                    ? specs.idleScreenRefreshRateConfig
                    : std::nullopt;
            const Policy policy{DisplayModeId(specs.defaultMode), translate(specs.primaryRanges),
                                translate(specs.appRequestRanges), specs.allowGroupSwitching};
                                translate(specs.appRequestRanges), specs.allowGroupSwitching,
                                idleScreenConfigOpt};

            return setDesiredDisplayModeSpecsInternal(display, policy);
        }
Loading