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

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

Merge "SF: Simplify getBestRefreshRate caching"

parents d4520d56 a8626ecd
Loading
Loading
Loading
Loading
+30 −68
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@
namespace android::scheduler {
namespace {

constexpr RefreshRateConfigs::GlobalSignals kNoSignals;

std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
    return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(),
                              ftl::enum_string(layer.vote).c_str(), weight,
@@ -235,63 +237,26 @@ struct RefreshRateScore {
    float score;
};

RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
                                                   GlobalSignals globalSignals,
                                                   GlobalSignals* outSignalsConsidered) const {
auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
                                            GlobalSignals signals) const
        -> std::pair<RefreshRate, GlobalSignals> {
    std::lock_guard lock(mLock);

    if (auto cached = getCachedBestRefreshRate(layers, globalSignals, outSignalsConsidered)) {
        return *cached;
    if (mGetBestRefreshRateCache &&
        mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) {
        return mGetBestRefreshRateCache->result;
    }

    GlobalSignals signalsConsidered;
    RefreshRate result = getBestRefreshRateLocked(layers, globalSignals, &signalsConsidered);
    lastBestRefreshRateInvocation.emplace(
            GetBestRefreshRateInvocation{.layerRequirements = layers,
                                         .globalSignals = globalSignals,
                                         .outSignalsConsidered = signalsConsidered,
                                         .resultingBestRefreshRate = result});
    if (outSignalsConsidered) {
        *outSignalsConsidered = signalsConsidered;
    }
    const auto result = getBestRefreshRateLocked(layers, signals);
    mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result};
    return result;
}

std::optional<RefreshRate> RefreshRateConfigs::getCachedBestRefreshRate(
        const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals,
        GlobalSignals* outSignalsConsidered) const {
    const bool sameAsLastCall = lastBestRefreshRateInvocation &&
            lastBestRefreshRateInvocation->layerRequirements == layers &&
            lastBestRefreshRateInvocation->globalSignals == globalSignals;

    if (sameAsLastCall) {
        if (outSignalsConsidered) {
            *outSignalsConsidered = lastBestRefreshRateInvocation->outSignalsConsidered;
        }
        return lastBestRefreshRateInvocation->resultingBestRefreshRate;
    }

    return {};
}

RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
        const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals,
        GlobalSignals* outSignalsConsidered) const {
auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
                                                  GlobalSignals signals) const
        -> std::pair<RefreshRate, GlobalSignals> {
    ATRACE_CALL();
    ALOGV("getBestRefreshRate %zu layers", layers.size());

    if (outSignalsConsidered) *outSignalsConsidered = {};
    const auto setTouchConsidered = [&] {
        if (outSignalsConsidered) {
            outSignalsConsidered->touch = true;
        }
    };

    const auto setIdleConsidered = [&] {
        if (outSignalsConsidered) {
            outSignalsConsidered->idle = true;
        }
    };
    ALOGV("%s: %zu layers", __func__, layers.size());

    int noVoteLayers = 0;
    int minVoteLayers = 0;
@@ -301,6 +266,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
    int explicitExact = 0;
    float maxExplicitWeight = 0;
    int seamedFocusedLayers = 0;

    for (const auto& layer : layers) {
        switch (layer.vote) {
            case LayerVoteType::NoVote:
@@ -349,10 +315,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(

    // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
    // selected a refresh rate to see if we should apply touch boost.
    if (globalSignals.touch && !hasExplicitVoteLayers) {
    if (signals.touch && !hasExplicitVoteLayers) {
        ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
        setTouchConsidered();
        return getMaxRefreshRateByPolicyLocked(anchorGroup);
        return {getMaxRefreshRateByPolicyLocked(anchorGroup), GlobalSignals{.touch = true}};
    }

    // If the primary range consists of a single refresh rate then we can only
@@ -361,23 +326,21 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
    const bool primaryRangeIsSingleRate =
            isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);

    if (!globalSignals.touch && globalSignals.idle &&
        !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
    if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
        ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
        setIdleConsidered();
        return getMinRefreshRateByPolicyLocked();
        return {getMinRefreshRateByPolicyLocked(), GlobalSignals{.idle = true}};
    }

    if (layers.empty() || noVoteLayers == layers.size()) {
        const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
        ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str());
        return refreshRate;
        return {refreshRate, kNoSignals};
    }

    // Only if all layers want Min we should return Min
    if (noVoteLayers + minVoteLayers == layers.size()) {
        ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
        return getMinRefreshRateByPolicyLocked();
        return {getMinRefreshRateByPolicyLocked(), kNoSignals};
    }

    // Find the best refresh rate based on score
@@ -466,9 +429,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
                        [](RefreshRateScore score) { return score.score == 0; })) {
            const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
            ALOGV("layers not scored - choose %s", refreshRate.getName().c_str());
            return refreshRate;
            return {refreshRate, kNoSignals};
        } else {
            return *bestRefreshRate;
            return {*bestRefreshRate, kNoSignals};
        }
    }

@@ -490,14 +453,13 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(

    using fps_approx_ops::operator<;

    if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
    if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
        bestRefreshRate->getFps() < touchRefreshRate.getFps()) {
        setTouchConsidered();
        ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
        return touchRefreshRate;
        return {touchRefreshRate, GlobalSignals{.touch = true}};
    }

    return *bestRefreshRate;
    return {*bestRefreshRate, kNoSignals};
}

std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
@@ -699,7 +661,7 @@ void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) {

    // Invalidate the cached invocation to getBestRefreshRate. This forces
    // the refresh rate to be recomputed on the next call to getBestRefreshRate.
    lastBestRefreshRateInvocation.reset();
    mGetBestRefreshRateCache.reset();

    mCurrentRefreshRate = mRefreshRates.at(modeId).get();
}
@@ -741,7 +703,7 @@ void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,

    // Invalidate the cached invocation to getBestRefreshRate. This forces
    // the refresh rate to be recomputed on the next call to getBestRefreshRate.
    lastBestRefreshRateInvocation.reset();
    mGetBestRefreshRateCache.reset();

    mRefreshRates.clear();
    for (const auto& mode : modes) {
@@ -800,7 +762,7 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
        ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
        return BAD_VALUE;
    }
    lastBestRefreshRateInvocation.reset();
    mGetBestRefreshRateCache.reset();
    Policy previousPolicy = *getCurrentPolicyLocked();
    mDisplayManagerPolicy = policy;
    if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -815,7 +777,7 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli
    if (policy && !isPolicyValidLocked(*policy)) {
        return BAD_VALUE;
    }
    lastBestRefreshRateInvocation.reset();
    mGetBestRefreshRateCache.reset();
    Policy previousPolicy = *getCurrentPolicyLocked();
    mOverridePolicy = policy;
    if (*getCurrentPolicyLocked() == previousPolicy) {
+11 −19
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <numeric>
#include <optional>
#include <type_traits>
#include <utility>

#include <android-base/stringprintf.h>
#include <gui/DisplayEventReceiver.h>
@@ -249,11 +250,10 @@ public:
        }
    };

    // Returns the refresh rate that best fits the given layers. outSignalsConsidered returns
    // whether the refresh rate was chosen based on touch boost and/or idle timer.
    RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals,
                                   GlobalSignals* outSignalsConsidered = nullptr) const
            EXCLUDES(mLock);
    // Returns the refresh rate that best fits the given layers, and whether the refresh rate was
    // chosen based on touch boost and/or idle timer.
    std::pair<RefreshRate, GlobalSignals> getBestRefreshRate(const std::vector<LayerRequirement>&,
                                                             GlobalSignals) const EXCLUDES(mLock);

    FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
        std::lock_guard lock(mLock);
@@ -403,13 +403,8 @@ private:
            const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
            std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock);

    std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>&,
                                                        GlobalSignals,
                                                        GlobalSignals* outSignalsConsidered) const
            REQUIRES(mLock);

    RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>&, GlobalSignals,
                                         GlobalSignals* outSignalsConsidered) const REQUIRES(mLock);
    std::pair<RefreshRate, GlobalSignals> getBestRefreshRateLocked(
            const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock);

    // Returns the refresh rate with the highest score in the collection specified from begin
    // to end. If there are more than one with the same highest refresh rate, the first one is
@@ -497,14 +492,11 @@ private:
    const Config mConfig;
    bool mSupportsFrameRateOverrideByContent;

    struct GetBestRefreshRateInvocation {
        std::vector<LayerRequirement> layerRequirements;
        GlobalSignals globalSignals;
        GlobalSignals outSignalsConsidered;
        RefreshRate resultingBestRefreshRate;
    struct GetBestRefreshRateCache {
        std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
        std::pair<RefreshRate, GlobalSignals> result;
    };
    mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation
            GUARDED_BY(mLock);
    mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock);

    // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed.
    std::mutex mIdleTimerCallbacksMutex;
+25 −23
Original line number Diff line number Diff line
@@ -537,18 +537,19 @@ void Scheduler::chooseRefreshRateForContent() {

    ATRACE_CALL();

    const auto refreshRateConfigs = holdRefreshRateConfigs();
    scheduler::LayerHistory::Summary summary =
            mLayerHistory.summarize(*refreshRateConfigs, systemTime());
    scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
    DisplayModePtr newMode;
    GlobalSignals consideredSignals;

    bool frameRateChanged;
    bool frameRateOverridesChanged;

    const auto refreshRateConfigs = holdRefreshRateConfigs();
    LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime());
    {
        std::lock_guard<std::mutex> lock(mPolicyLock);
        mPolicy.contentRequirements = summary;
        mPolicy.contentRequirements = std::move(summary);

        newMode = calculateRefreshRateModeId(&consideredSignals);
        std::tie(newMode, consideredSignals) = chooseDisplayMode();
        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());

        if (mPolicy.mode == newMode) {
@@ -678,8 +679,7 @@ void Scheduler::dumpVsync(std::string& out) const {
    mVsyncSchedule->dump(out);
}

bool Scheduler::updateFrameRateOverrides(
        scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) {
bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
    const auto refreshRateConfigs = holdRefreshRateConfigs();
    if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) {
        return false;
@@ -697,9 +697,11 @@ bool Scheduler::updateFrameRateOverrides(
template <class T>
bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
    DisplayModePtr newMode;
    GlobalSignals consideredSignals;

    bool refreshRateChanged = false;
    bool frameRateOverridesChanged;
    scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;

    const auto refreshRateConfigs = holdRefreshRateConfigs();
    {
        std::lock_guard<std::mutex> lock(mPolicyLock);
@@ -707,7 +709,7 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
            return false;
        }
        *currentState = newState;
        newMode = calculateRefreshRateModeId(&consideredSignals);
        std::tie(newMode, consideredSignals) = chooseDisplayMode();
        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
        if (mPolicy.mode == newMode) {
            // We don't need to change the display mode, but we might need to send an event
@@ -733,33 +735,33 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
    return consideredSignals.touch;
}

DisplayModePtr Scheduler::calculateRefreshRateModeId(
        scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) {
auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
    ATRACE_CALL();
    if (consideredSignals) *consideredSignals = {};

    const auto refreshRateConfigs = holdRefreshRateConfigs();
    const auto configs = holdRefreshRateConfigs();

    // 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 (mDisplayPowerTimer &&
        (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) {
        return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode();
        constexpr GlobalSignals kNoSignals;
        return {configs->getMaxRefreshRateByPolicy().getMode(), kNoSignals};
    }

    const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active;
    const bool idle = mPolicy.idleTimer == TimerState::Expired;
    const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
                                .idle = mPolicy.idleTimer == TimerState::Expired};

    const auto [refreshRate, consideredSignals] =
            configs->getBestRefreshRate(mPolicy.contentRequirements, signals);

    return refreshRateConfigs
            ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle},
                                 consideredSignals)
            .getMode();
    return {refreshRate.getMode(), consideredSignals};
}

DisplayModePtr Scheduler::getPreferredDisplayMode() {
    std::lock_guard<std::mutex> lock(mPolicyLock);
    // Make sure that the default mode ID is first updated, before returned.
    // Make sure the stored mode is up to date.
    if (mPolicy.mode) {
        mPolicy.mode = calculateRefreshRateModeId();
        mPolicy.mode = chooseDisplayMode().first;
    }
    return mPolicy.mode;
}
+6 −7
Original line number Diff line number Diff line
@@ -269,15 +269,14 @@ private:

    void setVsyncPeriod(nsecs_t period);

    // This function checks whether individual features that are affecting the refresh rate
    // selection were initialized, prioritizes them, and calculates the DisplayModeId
    // for the suggested refresh rate.
    DisplayModePtr calculateRefreshRateModeId(
            RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock);
    using GlobalSignals = RefreshRateConfigs::GlobalSignals;

    // Returns the display mode that fulfills the policy, and the signals that were considered.
    std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock);

    bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);

    void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock);
    bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate)
            REQUIRES(mPolicyLock);

    impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const
            EXCLUDES(mRefreshRateConfigsLock);
+260 −273

File changed.

Preview size limit exceeded, changes collapsed.