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

Commit d72ba16b authored by ramindani's avatar ramindani
Browse files

[MD] Return list of scored refresh rates based on overallscore.

The sorted list returns the refresh rates in the
descending order of priority and their
overallscore.

This overall score will be used and called for multiple displays
and will be used to make the final selection in the
DisplayModeController for all the displays.

BUG: 240743471
Test: atest libsurfaceflinger_unittest
Change-Id: I8355425e89452f5ce73858a6173c53be9f3753ef
parent cc8be8c3
Loading
Loading
Loading
Loading
+130 −92
Original line number Diff line number Diff line
@@ -48,24 +48,6 @@ struct RefreshRateScore {
    } fixedRateBelowThresholdLayersScore;
};

template <typename Iterator>
const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) {
    const auto it =
            std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) {
                const auto& [modeIt, overallScore, _] = current;

                std::string name = to_string(modeIt->second->getFps());
                ALOGV("%s scores %.2f", name.c_str(), overallScore);

                ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));

                constexpr float kEpsilon = 0.0001f;
                return overallScore > max.overallScore * (1 + kEpsilon);
            });

    return it->modeIt->second;
}

constexpr RefreshRateConfigs::GlobalSignals kNoSignals;

std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
@@ -137,6 +119,34 @@ bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& so

} // namespace

struct RefreshRateConfigs::RefreshRateScoreComparator {
    bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const {
        const auto& [modeIt, overallScore, _] = lhs;

        std::string name = to_string(modeIt->second->getFps());
        ALOGV("%s sorting scores %.2f", name.c_str(), overallScore);

        ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));

        constexpr float kEpsilon = 0.0001f;
        if (std::abs(overallScore - rhs.overallScore) > kEpsilon) {
            return overallScore > rhs.overallScore;
        }

        // If overallScore tie we will pick the higher refresh rate if
        // high refresh rate is the priority else the lower refresh rate.
        if (refreshRateOrder == RefreshRateOrder::Descending) {
            using fps_approx_ops::operator>;
            return modeIt->second->getFps() > rhs.modeIt->second->getFps();
        } else {
            using fps_approx_ops::operator<;
            return modeIt->second->getFps() < rhs.modeIt->second->getFps();
        }
    }

    const RefreshRateOrder refreshRateOrder;
};

std::string RefreshRateConfigs::Policy::toString() const {
    return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
                              ", primaryRange=%s, appRequestRange=%s}",
@@ -218,6 +228,13 @@ float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerR
    return 0;
}

float RefreshRateConfigs::calculateRefreshRateScoreForFps(Fps refreshRate) const {
    const float ratio =
            refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue();
    // Use ratio^2 to get a lower score the more we get further from peak
    return ratio * ratio;
}

float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
                                                    bool isSeamlessSwitch) const {
    // Slightly prefer seamless switches.
@@ -226,10 +243,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye

    // If the layer wants Max, give higher score to the higher refresh rate
    if (layer.vote == LayerVoteType::Max) {
        const auto& maxRefreshRate = mAppRequestRefreshRates.back()->second;
        const auto ratio = refreshRate.getValue() / maxRefreshRate->getFps().getValue();
        // use ratio^2 to get a lower score the more we get further from peak
        return ratio * ratio;
        return calculateRefreshRateScoreForFps(refreshRate);
    }

    if (layer.vote == LayerVoteType::ExplicitExact) {
@@ -258,24 +272,24 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
            kNonExactMatchingPenalty;
}

auto RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers,
                                               GlobalSignals signals) const
        -> std::pair<DisplayModePtr, GlobalSignals> {
        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
    std::lock_guard lock(mLock);

    if (mGetBestRefreshRateCache &&
        mGetBestRefreshRateCache->arguments == std::make_pair(layers, signals)) {
        return mGetBestRefreshRateCache->result;
    if (mGetRankedRefreshRatesCache &&
        mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) {
        return mGetRankedRefreshRatesCache->result;
    }

    const auto result = getBestRefreshRateLocked(layers, signals);
    mGetBestRefreshRateCache = GetBestRefreshRateCache{{layers, signals}, result};
    const auto result = getRankedRefreshRatesLocked(layers, signals);
    mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result};
    return result;
}

auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers,
                                                     GlobalSignals signals) const
        -> std::pair<DisplayModePtr, GlobalSignals> {
        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
    using namespace fps_approx_ops;
    ATRACE_CALL();
    ALOGV("%s: %zu layers", __func__, layers.size());
@@ -285,8 +299,8 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
    // Keep the display at max refresh rate for the duration of powering on the display.
    if (signals.powerOnImminent) {
        ALOGV("Power On Imminent");
        const auto& max = getMaxRefreshRateByPolicyLocked(activeMode.getGroup());
        return {max, GlobalSignals{.powerOnImminent = true}};
        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending),
                GlobalSignals{.powerOnImminent = true}};
    }

    int noVoteLayers = 0;
@@ -295,7 +309,6 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
    int explicitDefaultVoteLayers = 0;
    int explicitExactOrMultipleVoteLayers = 0;
    int explicitExact = 0;
    float maxExplicitWeight = 0;
    int seamedFocusedLayers = 0;

    for (const auto& layer : layers) {
@@ -311,15 +324,12 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
                break;
            case LayerVoteType::ExplicitDefault:
                explicitDefaultVoteLayers++;
                maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
                break;
            case LayerVoteType::ExplicitExactOrMultiple:
                explicitExactOrMultipleVoteLayers++;
                maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
                break;
            case LayerVoteType::ExplicitExact:
                explicitExact++;
                maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
                break;
            case LayerVoteType::Heuristic:
                break;
@@ -348,9 +358,9 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
    // 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 (signals.touch && !hasExplicitVoteLayers) {
        const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
        ALOGV("TouchBoost - choose %s", to_string(max->getFps()).c_str());
        return {max, GlobalSignals{.touch = true}};
        ALOGV("Touch Boost");
        return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
                GlobalSignals{.touch = true}};
    }

    // If the primary range consists of a single refresh rate then we can only
@@ -360,22 +370,22 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
            isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);

    if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
        const DisplayModePtr& min = getMinRefreshRateByPolicyLocked();
        ALOGV("Idle - choose %s", to_string(min->getFps()).c_str());
        return {min, GlobalSignals{.idle = true}};
        ALOGV("Idle");
        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending),
                GlobalSignals{.idle = true}};
    }

    if (layers.empty() || noVoteLayers == layers.size()) {
        const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
        ALOGV("no layers with votes - choose %s", to_string(max->getFps()).c_str());
        return {max, kNoSignals};
        ALOGV("No layers with votes");
        return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
                kNoSignals};
    }

    // Only if all layers want Min we should return Min
    if (noVoteLayers + minVoteLayers == layers.size()) {
        const DisplayModePtr& min = getMinRefreshRateByPolicyLocked();
        ALOGV("all layers Min - choose %s", to_string(min->getFps()).c_str());
        return {min, kNoSignals};
        ALOGV("All layers Min");
        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending),
                kNoSignals};
    }

    // Find the best refresh rate based on score
@@ -522,22 +532,29 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
    }

    // Now that we scored all the refresh rates we need to pick the one that got the highest
    // overallScore. In case of a tie we will pick the higher refresh rate if any of the layers
    // wanted Max, or the lower otherwise.
    const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0
            ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend())
            : getMaxScoreRefreshRate(scores.begin(), scores.end());
    // overallScore. Sort the scores based on their overallScore in descending order of priority.
    const RefreshRateOrder refreshRateOrder =
            maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending;
    std::sort(scores.begin(), scores.end(),
              RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder});
    std::vector<RefreshRateRanking> rankedRefreshRates;
    rankedRefreshRates.reserve(scores.size());

    std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates),
                   [](const RefreshRateScore& score) {
                       return RefreshRateRanking{score.modeIt->second, score.overallScore};
                   });

    if (primaryRangeIsSingleRate) {
        // If we never scored any layers, then choose the rate from the primary
        // range instead of picking a random score from the app range.
        if (std::all_of(scores.begin(), scores.end(),
                        [](RefreshRateScore score) { return score.overallScore == 0; })) {
            const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
            ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str());
            return {max, kNoSignals};
            ALOGV("Layers not scored");
            return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
                    kNoSignals};
        } else {
            return {bestRefreshRate, kNoSignals};
            return {rankedRefreshRates, kNoSignals};
        }
    }

@@ -545,8 +562,6 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
    // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
    // vote we should not change it if we get a touch event. Only apply touch boost if it will
    // actually increase the refresh rate over the normal selection.
    const DisplayModePtr& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);

    const bool touchBoostForExplicitExact = [&] {
        if (mSupportsFrameRateOverrideByContent) {
            // Enable touch boost if there are other layers besides exact
@@ -557,15 +572,18 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequire
        }
    }();

    const auto& touchRefreshRates =
            getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending);
    using fps_approx_ops::operator<;

    if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
        bestRefreshRate->getFps() < touchRefreshRate->getFps()) {
        ALOGV("TouchBoost - choose %s", to_string(touchRefreshRate->getFps()).c_str());
        return {touchRefreshRate, GlobalSignals{.touch = true}};
        scores.front().modeIt->second->getFps() <
                touchRefreshRates.front().displayModePtr->getFps()) {
        ALOGV("Touch Boost");
        return {touchRefreshRates, GlobalSignals{.touch = true}};
    }

    return {bestRefreshRate, kNoSignals};
    return {rankedRefreshRates, kNoSignals};
}

std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
@@ -670,11 +688,13 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr
            continue;
        }

        // Now that we scored all the refresh rates we need to pick the one that got the highest
        // score.
        // Now that we scored all the refresh rates we need to pick the lowest refresh rate
        // that got the highest score.
        const DisplayModePtr& bestRefreshRate =
                getMaxScoreRefreshRate(scores.begin(), scores.end());

                std::min_element(scores.begin(), scores.end(),
                                 RefreshRateScoreComparator{.refreshRateOrder =
                                                                    RefreshRateOrder::Ascending})
                        ->modeIt->second;
        frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
    }

@@ -715,16 +735,6 @@ const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() cons
    return mPrimaryRefreshRates.front()->second;
}

DisplayModePtr RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
    std::lock_guard lock(mLock);
    return getMaxRefreshRateByPolicyLocked();
}

const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
    const int anchorGroup = getActiveModeItLocked()->second->getGroup();
    return getMaxRefreshRateByPolicyLocked(anchorGroup);
}

const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
    for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) {
        const auto& mode = (*it)->second;
@@ -733,14 +743,41 @@ const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int an
        }
    }

    const auto& activeMode = *getActiveModeItLocked()->second;
    ALOGE("Can't find max refresh rate by policy with the same mode group as the current mode %s",
          to_string(activeMode).c_str());
    ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup);

    // Default to the highest refresh rate.
    return mPrimaryRefreshRates.back()->second;
}

std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked(
        std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const {
    std::vector<RefreshRateRanking> rankings;
    const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) {
        const auto& mode = it->second;
        const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending);
        const float score = calculateRefreshRateScoreForFps(mode->getFps());
        if (!anchorGroupOpt || mode->getGroup() == anchorGroupOpt) {
            rankings.push_back(RefreshRateRanking{mode, inverseScore ? 1.0f / score : score});
        }
    };

    if (refreshRateOrder == RefreshRateOrder::Ascending) {
        std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking);
    } else {
        std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking);
    }

    if (!rankings.empty() || !anchorGroupOpt) {
        return rankings;
    }

    ALOGW("Can't find %s refresh rate by policy with the same mode group"
          " as the mode group %d",
          refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value());

    return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder);
}

DisplayModePtr RefreshRateConfigs::getActiveModePtr() const {
    std::lock_guard lock(mLock);
    return getActiveModeItLocked()->second;
@@ -760,9 +797,9 @@ DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const {
void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) {
    std::lock_guard lock(mLock);

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

    mActiveModeIt = mDisplayModes.find(modeId);
    LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
@@ -797,9 +834,9 @@ void RefreshRateConfigs::initializeIdleTimer() {
void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) {
    std::lock_guard lock(mLock);

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

    mDisplayModes = std::move(modes);
    mActiveModeIt = mDisplayModes.find(activeModeId);
@@ -843,7 +880,7 @@ status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
        ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
        return BAD_VALUE;
    }
    mGetBestRefreshRateCache.reset();
    mGetRankedRefreshRatesCache.reset();
    Policy previousPolicy = *getCurrentPolicyLocked();
    mDisplayManagerPolicy = policy;
    if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -858,7 +895,7 @@ status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& poli
    if (policy && !isPolicyValidLocked(*policy)) {
        return BAD_VALUE;
    }
    mGetBestRefreshRateCache.reset();
    mGetRankedRefreshRatesCache.reset();
    Policy previousPolicy = *getCurrentPolicyLocked();
    mOverridePolicy = policy;
    if (*getCurrentPolicyLocked() == previousPolicy) {
@@ -958,7 +995,8 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction
        return KernelIdleTimerAction::TurnOff;
    }

    const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked();
    const DisplayModePtr& maxByPolicy =
            getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup());
    if (minByPolicy == maxByPolicy) {
        // Turn on the timer when the min of the primary range is below the device min.
        if (const Policy* currentPolicy = getCurrentPolicyLocked();
+28 −12
Original line number Diff line number Diff line
@@ -44,6 +44,15 @@ inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) {
    return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs));
}

struct RefreshRateRanking {
    DisplayModePtr displayModePtr;
    float score = 0.0f;

    bool operator==(const RefreshRateRanking& ranking) const {
        return displayModePtr == ranking.displayModePtr && score == ranking.score;
    }
};

using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;

/**
@@ -195,9 +204,9 @@ public:
        }
    };

    // 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<DisplayModePtr, GlobalSignals> getBestRefreshRate(
    // Returns the list in the descending order of refresh rates desired
    // based on their overall score, and the GlobalSignals that were considered.
    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRates(
            const std::vector<LayerRequirement>&, GlobalSignals) const EXCLUDES(mLock);

    FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
@@ -208,10 +217,6 @@ public:
    std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId,
                                            bool timerExpired) const EXCLUDES(mLock);

    // Returns the highest refresh rate according to the current policy. May change at runtime. Only
    // uses the primary range, not the app request range.
    DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock);

    void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext);

    // See mActiveModeIt for thread safety.
@@ -343,7 +348,7 @@ private:
    // See mActiveModeIt for thread safety.
    DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock);

    std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked(
    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedRefreshRatesLocked(
            const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock);

    // Returns number of display frames and remainder when dividing the layer refresh period by
@@ -356,12 +361,23 @@ private:

    // Returns the highest refresh rate according to the current policy. May change at runtime. Only
    // uses the primary range, not the app request range.
    const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
    const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock);

    struct RefreshRateScoreComparator;

    enum class RefreshRateOrder { Ascending, Descending };

    // Returns the rankings in RefreshRateOrder. May change at runtime.
    // Only uses the primary range, not the app request range.
    std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked(std::optional<int> anchorGroupOpt,
                                                                  RefreshRateOrder) const
            REQUIRES(mLock);

    const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
    bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);

    // Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1.
    float calculateRefreshRateScoreForFps(Fps refreshRate) const REQUIRES(mLock);
    // calculates a score for a layer. Used to determine the display refresh rate
    // and the frame rate override for certains applications.
    float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate,
@@ -410,11 +426,11 @@ private:
    const Config mConfig;
    bool mSupportsFrameRateOverrideByContent;

    struct GetBestRefreshRateCache {
    struct GetRankedRefreshRatesCache {
        std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
        std::pair<DisplayModePtr, GlobalSignals> result;
        std::pair<std::vector<RefreshRateRanking>, GlobalSignals> result;
    };
    mutable std::optional<GetBestRefreshRateCache> mGetBestRefreshRateCache GUARDED_BY(mLock);
    mutable std::optional<GetRankedRefreshRatesCache> mGetRankedRefreshRatesCache GUARDED_BY(mLock);

    // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed.
    std::mutex mIdleTimerCallbacksMutex;
+7 −4
Original line number Diff line number Diff line
@@ -674,7 +674,9 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals
        if (currentState == newState) return {};
        currentState = std::forward<T>(newState);

        std::tie(newMode, consideredSignals) = chooseDisplayMode();
        const auto [rankings, signals] = getRankedDisplayModes();
        newMode = rankings.front().displayModePtr;
        consideredSignals = signals;
        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());

        if (mPolicy.mode == newMode) {
@@ -699,7 +701,8 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals
    return consideredSignals;
}

auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
auto Scheduler::getRankedDisplayModes()
        -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
    ATRACE_CALL();

    const auto configs = holdRefreshRateConfigs();
@@ -712,14 +715,14 @@ auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals>
                                .idle = mPolicy.idleTimer == TimerState::Expired,
                                .powerOnImminent = powerOnImminent};

    return configs->getBestRefreshRate(mPolicy.contentRequirements, signals);
    return configs->getRankedRefreshRates(mPolicy.contentRequirements, signals);
}

DisplayModePtr Scheduler::getPreferredDisplayMode() {
    std::lock_guard<std::mutex> lock(mPolicyLock);
    // Make sure the stored mode is up to date.
    if (mPolicy.mode) {
        mPolicy.mode = chooseDisplayMode().first;
        mPolicy.mode = getRankedDisplayModes().first.front().displayModePtr;
    }
    return mPolicy.mode;
}
+4 −2
Original line number Diff line number Diff line
@@ -269,8 +269,10 @@ private:
    template <typename S, typename T>
    GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock);

    // Returns the display mode that fulfills the policy, and the signals that were considered.
    std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock);
    // Returns the list of display modes in descending order of their priority that fulfills the
    // policy, and the signals that were considered.
    std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedDisplayModes()
            REQUIRES(mPolicyLock);

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

+1 −1
Original line number Diff line number Diff line
@@ -350,7 +350,7 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() {
    const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
    std::vector<LayerRequirement> layers = {{.weight = mFdp.ConsumeFloatingPoint<float>()}};

    refreshRateConfigs.getBestRefreshRate(layers, globalSignals);
    refreshRateConfigs.getRankedRefreshRates(layers, globalSignals);

    layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength);
    layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>();
Loading