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

Commit afc9086a authored by Dominik Laskowski's avatar Dominik Laskowski Committed by Android (Google) Code Review
Browse files

Merge "SF: Clean up API for refresh rate selection"

parents 1dbec270 530d6bdd
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <cstdint>
#include <ostream>
#include <string>

#include <ftl/optional.h>
@@ -67,6 +68,11 @@ inline std::string to_string(DisplayId displayId) {
    return std::to_string(displayId.value);
}

// For tests.
inline std::ostream& operator<<(std::ostream& stream, DisplayId displayId) {
    return stream << "DisplayId{" << displayId.value << '}';
}

// DisplayId of a physical display, such as the internal display or externally connected display.
struct PhysicalDisplayId : DisplayId {
    static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) {
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <ftl/non_null.h>

#include "DisplayHardware/DisplayMode.h"

namespace android::display {

struct DisplayModeRequest {
    ftl::NonNull<DisplayModePtr> modePtr;

    // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE.
    bool emitEvent = false;
};

inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) {
    return lhs.modePtr == rhs.modePtr && lhs.emitEvent == rhs.emitEvent;
}

} // namespace android::display
+13 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>

#include "Display/DisplayModeRequest.h"
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/Hal.h"
#include "DisplayHardware/PowerAdvisor.h"
@@ -190,9 +191,20 @@ public:
    /* ------------------------------------------------------------------------
     * Display mode management.
     */

    // TODO(b/241285876): Replace ActiveModeInfo and DisplayModeEvent with DisplayModeRequest.
    struct ActiveModeInfo {
        using Event = scheduler::DisplayModeEvent;

        ActiveModeInfo() = default;
        ActiveModeInfo(DisplayModePtr mode, Event event) : mode(std::move(mode)), event(event) {}

        explicit ActiveModeInfo(display::DisplayModeRequest&& request)
              : ActiveModeInfo(std::move(request.modePtr).take(),
                               request.emitEvent ? Event::Changed : Event::None) {}

        DisplayModePtr mode;
        scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None;
        Event event = Event::None;

        bool operator!=(const ActiveModeInfo& other) const {
            return mode != other.mode || event != other.event;
+35 −45
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

#include <chrono>
#include <cmath>
#include <deque>

#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -143,8 +144,7 @@ struct RefreshRateConfigs::RefreshRateScoreComparator {

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

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

@@ -288,8 +288,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
}

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

    if (mGetRankedRefreshRatesCache &&
@@ -304,7 +303,7 @@ auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequiremen

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

@@ -375,8 +373,7 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ
    // selected a refresh rate to see if we should apply touch boost.
    if (signals.touch && !hasExplicitVoteLayers) {
        ALOGV("Touch Boost");
        return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
                                              /*preferredDisplayModeOpt*/ std::nullopt),
        return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending),
                GlobalSignals{.touch = true}};
    }

@@ -388,24 +385,19 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ

    if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
        ALOGV("Idle");
        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending,
                                              /*preferredDisplayModeOpt*/ std::nullopt),
        return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending),
                GlobalSignals{.idle = true}};
    }

    if (layers.empty() || noVoteLayers == layers.size()) {
        ALOGV("No layers with votes");
        return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
                                              /*preferredDisplayModeOpt*/ std::nullopt),
                kNoSignals};
        return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals};
    }

    // Only if all layers want Min we should return Min
    if (noVoteLayers + minVoteLayers == layers.size()) {
        ALOGV("All layers Min");
        return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending,
                                              /*preferredDisplayModeOpt*/ std::nullopt),
                kNoSignals};
        return {rankRefreshRates(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals};
    }

    // Find the best refresh rate based on score
@@ -557,12 +549,13 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ
            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),
    RefreshRateRanking ranking;
    ranking.reserve(scores.size());

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

    const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) {
@@ -574,11 +567,9 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ
        // range instead of picking a random score from the app range.
        if (noLayerScore) {
            ALOGV("Layers not scored");
            return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
                                                  /*preferredDisplayModeOpt*/ std::nullopt),
                    kNoSignals};
            return {rankRefreshRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals};
        } else {
            return {rankedRefreshRates, kNoSignals};
            return {ranking, kNoSignals};
        }
    }

@@ -596,14 +587,12 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ
        }
    }();

    const auto& touchRefreshRates =
            getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
                                          /*preferredDisplayModeOpt*/ std::nullopt);
    const auto touchRefreshRates = rankRefreshRates(anchorGroup, RefreshRateOrder::Descending);

    using fps_approx_ops::operator<;

    if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
        scores.front().modeIt->second->getFps() <
                touchRefreshRates.front().displayModePtr->getFps()) {
        scores.front().modeIt->second->getFps() < touchRefreshRates.front().modePtr->getFps()) {
        ALOGV("Touch Boost");
        return {touchRefreshRates, GlobalSignals{.touch = true}};
    }
@@ -612,12 +601,11 @@ auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequ
    // current config
    if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) {
        const auto preferredDisplayMode = activeMode.getId();
        return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Ascending,
                                              preferredDisplayMode),
        return {rankRefreshRates(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode),
                kNoSignals};
    }

    return {rankedRefreshRates, kNoSignals};
    return {ranking, kNoSignals};
}

std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
@@ -783,11 +771,12 @@ const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int an
    return mPrimaryRefreshRates.back()->second;
}

std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked(
auto RefreshRateConfigs::rankRefreshRates(
        std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder,
        std::optional<DisplayModeId> preferredDisplayModeOpt) const {
    std::deque<RefreshRateRanking> rankings;
    const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) {
        std::optional<DisplayModeId> preferredDisplayModeOpt) const -> RefreshRateRanking {
    std::deque<ScoredRefreshRate> ranking;

    const auto rankRefreshRate = [&](DisplayModeIterator it) REQUIRES(mLock) {
        const auto& mode = it->second;
        if (anchorGroupOpt && mode->getGroup() != anchorGroupOpt) {
            return;
@@ -800,31 +789,32 @@ std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocke
        }
        if (preferredDisplayModeOpt) {
            if (*preferredDisplayModeOpt == mode->getId()) {
                rankings.push_front(RefreshRateRanking{mode, /*score*/ 1.0f});
                constexpr float kScore = std::numeric_limits<float>::max();
                ranking.push_front(ScoredRefreshRate{mode, kScore});
                return;
            }
            constexpr float kNonPreferredModePenalty = 0.95f;
            score *= kNonPreferredModePenalty;
        }
        rankings.push_back(RefreshRateRanking{mode, score});
        ranking.push_back(ScoredRefreshRate{mode, score});
    };

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

    if (!rankings.empty() || !anchorGroupOpt) {
        return {rankings.begin(), rankings.end()};
    if (!ranking.empty() || !anchorGroupOpt) {
        return {ranking.begin(), ranking.end()};
    }

    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,
                                         preferredDisplayModeOpt);
    constexpr std::optional<int> kNoAnchorGroup = std::nullopt;
    return rankRefreshRates(kNoAnchorGroup, refreshRateOrder, preferredDisplayModeOpt);
}

DisplayModePtr RefreshRateConfigs::getActiveModePtr() const {
+45 −20
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <utility>
#include <variant>

#include <ftl/concat.h>
#include <gui/DisplayEventReceiver.h>

#include <scheduler/Fps.h>
@@ -46,15 +47,6 @@ 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;

/**
@@ -208,12 +200,46 @@ public:
            return touch == other.touch && idle == other.idle &&
                    powerOnImminent == other.powerOnImminent;
        }

        auto toString() const {
            return ftl::Concat("{touch=", touch, ", idle=", idle,
                               ", powerOnImminent=", powerOnImminent, '}');
        }
    };

    struct ScoredRefreshRate {
        DisplayModePtr modePtr;
        float score = 0.0f;

        bool operator==(const ScoredRefreshRate& other) const {
            return modePtr == other.modePtr && score == other.score;
        }

        static bool scoresEqual(float lhs, float rhs) {
            constexpr float kEpsilon = 0.0001f;
            return std::abs(lhs - rhs) <= kEpsilon;
        }

        struct DescendingScore {
            bool operator()(const ScoredRefreshRate& lhs, const ScoredRefreshRate& rhs) const {
                return lhs.score > rhs.score && !scoresEqual(lhs.score, rhs.score);
            }
        };
    };

    using RefreshRateRanking = std::vector<ScoredRefreshRate>;

    struct RankedRefreshRates {
        RefreshRateRanking ranking; // Ordered by descending score.
        GlobalSignals consideredSignals;

        bool operator==(const RankedRefreshRates& other) const {
            return ranking == other.ranking && consideredSignals == other.consideredSignals;
        }
    };

    // 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);
    RankedRefreshRates getRankedRefreshRates(const std::vector<LayerRequirement>&,
                                             GlobalSignals) const EXCLUDES(mLock);

    FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
        std::lock_guard lock(mLock);
@@ -354,8 +380,8 @@ private:
    // See mActiveModeIt for thread safety.
    DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock);

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

    // Returns number of display frames and remainder when dividing the layer refresh period by
    // display refresh period.
@@ -373,11 +399,10 @@ private:

    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,
            std::optional<DisplayModeId> preferredDisplayModeOpt) const REQUIRES(mLock);
    RefreshRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt, RefreshRateOrder,
                                        std::optional<DisplayModeId> preferredDisplayModeOpt =
                                                std::nullopt) const REQUIRES(mLock);

    const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
    bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
@@ -436,7 +461,7 @@ private:

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

Loading