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

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

Merge "SF: Match followers' refresh rate to pacesetter's" into main

parents 8127c23d 9e88d62f
Loading
Loading
Loading
Loading
+27 −7
Original line number Diff line number Diff line
@@ -474,21 +474,23 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay
}

auto RefreshRateSelector::getRankedFrameRates(const std::vector<LayerRequirement>& layers,
                                              GlobalSignals signals) const -> RankedFrameRates {
                                              GlobalSignals signals, Fps pacesetterFps) const
        -> RankedFrameRates {
    GetRankedFrameRatesCache cache{layers, signals, pacesetterFps};

    std::lock_guard lock(mLock);

    if (mGetRankedFrameRatesCache &&
        mGetRankedFrameRatesCache->arguments == std::make_pair(layers, signals)) {
    if (mGetRankedFrameRatesCache && mGetRankedFrameRatesCache->matches(cache)) {
        return mGetRankedFrameRatesCache->result;
    }

    const auto result = getRankedFrameRatesLocked(layers, signals);
    mGetRankedFrameRatesCache = GetRankedFrameRatesCache{{layers, signals}, result};
    return result;
    cache.result = getRankedFrameRatesLocked(layers, signals, pacesetterFps);
    mGetRankedFrameRatesCache = std::move(cache);
    return mGetRankedFrameRatesCache->result;
}

auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers,
                                                    GlobalSignals signals) const
                                                    GlobalSignals signals, Fps pacesetterFps) const
        -> RankedFrameRates {
    using namespace fps_approx_ops;
    ATRACE_CALL();
@@ -496,6 +498,24 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi

    const auto& activeMode = *getActiveModeLocked().modePtr;

    if (pacesetterFps.isValid()) {
        ALOGV("Follower display");

        const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Descending,
                                            std::nullopt, [&](FrameRateMode mode) {
                                                return mode.modePtr->getPeakFps() == pacesetterFps;
                                            });

        if (!ranking.empty()) {
            ATRACE_FORMAT_INSTANT("%s (Follower display)",
                                  to_string(ranking.front().frameRateMode.fps).c_str());

            return {ranking, kNoSignals, pacesetterFps};
        }

        ALOGW("Follower display cannot follow the pacesetter");
    }

    // Keep the display at max frame rate for the duration of powering on the display.
    if (signals.powerOnImminent) {
        ALOGV("Power On Imminent");
+18 −5
Original line number Diff line number Diff line
@@ -233,14 +233,18 @@ public:
    struct RankedFrameRates {
        FrameRateRanking ranking; // Ordered by descending score.
        GlobalSignals consideredSignals;
        Fps pacesetterFps;

        bool operator==(const RankedFrameRates& other) const {
            return ranking == other.ranking && consideredSignals == other.consideredSignals;
            return ranking == other.ranking && consideredSignals == other.consideredSignals &&
                    isApproxEqual(pacesetterFps, other.pacesetterFps);
        }
    };

    RankedFrameRates getRankedFrameRates(const std::vector<LayerRequirement>&, GlobalSignals) const
            EXCLUDES(mLock);
    // If valid, `pacesetterFps` (used by follower displays) filters the ranking to modes matching
    // that refresh rate.
    RankedFrameRates getRankedFrameRates(const std::vector<LayerRequirement>&, GlobalSignals,
                                         Fps pacesetterFps = {}) const EXCLUDES(mLock);

    FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
        std::lock_guard lock(mLock);
@@ -415,7 +419,8 @@ private:
    const FrameRateMode& getActiveModeLocked() const REQUIRES(mLock);

    RankedFrameRates getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers,
                                               GlobalSignals signals) const REQUIRES(mLock);
                                               GlobalSignals signals, Fps pacesetterFps) const
            REQUIRES(mLock);

    // Returns number of display frames and remainder when dividing the layer refresh period by
    // display refresh period.
@@ -534,8 +539,16 @@ private:
    Config::FrameRateOverride mFrameRateOverrideConfig;

    struct GetRankedFrameRatesCache {
        std::pair<std::vector<LayerRequirement>, GlobalSignals> arguments;
        std::vector<LayerRequirement> layers;
        GlobalSignals signals;
        Fps pacesetterFps;

        RankedFrameRates result;

        bool matches(const GetRankedFrameRatesCache& other) const {
            return layers == other.layers && signals == other.signals &&
                    isApproxEqual(pacesetterFps, other.pacesetterFps);
        }
    };
    mutable std::optional<GetRankedFrameRatesCache> mGetRankedFrameRatesCache GUARDED_BY(mLock);

+19 −26
Original line number Diff line number Diff line
@@ -1149,38 +1149,31 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals
auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap {
    ATRACE_CALL();

    using RankedRefreshRates = RefreshRateSelector::RankedFrameRates;
    ui::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking;
    DisplayModeChoiceMap modeChoices;
    const auto globalSignals = makeGlobalSignals();
    Fps pacesetterFps;

    for (const auto& [id, display] : mDisplays) {
    const Fps pacesetterFps = [&]() REQUIRES(mPolicyLock, mDisplayLock, kMainThreadContext) {
        auto rankedFrameRates =
                display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements,
                pacesetterSelectorPtrLocked()->getRankedFrameRates(mPolicy.contentRequirements,
                                                                   globalSignals);
        if (id == *mPacesetterDisplayId) {
            pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps;
        }
        perDisplayRanking.push_back(std::move(rankedFrameRates));
    }

    DisplayModeChoiceMap modeChoices;
    using fps_approx_ops::operator==;
        const Fps pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps;

    for (auto& [rankings, signals] : perDisplayRanking) {
        const auto chosenFrameRateMode =
                ftl::find_if(rankings,
                             [&](const auto& ranking) {
                                 return ranking.frameRateMode.fps == pacesetterFps;
                             })
                        .transform([](const auto& scoredFrameRate) {
                            return scoredFrameRate.get().frameRateMode;
                        })
                        .value_or(rankings.front().frameRateMode);
        modeChoices.try_emplace(*mPacesetterDisplayId,
                                DisplayModeChoice::from(std::move(rankedFrameRates)));
        return pacesetterFps;
    }();

    for (const auto& [id, display] : mDisplays) {
        if (id == *mPacesetterDisplayId) continue;

        modeChoices.try_emplace(chosenFrameRateMode.modePtr->getPhysicalDisplayId(),
                                DisplayModeChoice{chosenFrameRateMode, signals});
        auto rankedFrameRates =
                display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals,
                                                         pacesetterFps);

        modeChoices.try_emplace(id, DisplayModeChoice::from(std::move(rankedFrameRates)));
    }

    return modeChoices;
}

+5 −0
Original line number Diff line number Diff line
@@ -402,6 +402,11 @@ private:
        DisplayModeChoice(FrameRateMode mode, GlobalSignals consideredSignals)
              : mode(std::move(mode)), consideredSignals(consideredSignals) {}

        static DisplayModeChoice from(RefreshRateSelector::RankedFrameRates rankedFrameRates) {
            return {rankedFrameRates.ranking.front().frameRateMode,
                    rankedFrameRates.consideredSignals};
        }

        FrameRateMode mode;
        GlobalSignals consideredSignals;

+46 −19
Original line number Diff line number Diff line
@@ -103,8 +103,9 @@ struct TestableRefreshRateSelector : RefreshRateSelector {
    auto& mutableGetRankedRefreshRatesCache() { return mGetRankedFrameRatesCache; }

    auto getRankedFrameRates(const std::vector<LayerRequirement>& layers,
                             GlobalSignals signals = {}) const {
        const auto result = RefreshRateSelector::getRankedFrameRates(layers, signals);
                             GlobalSignals signals = {}, Fps pacesetterFps = {}) const {
        const auto result =
                RefreshRateSelector::getRankedFrameRates(layers, signals, pacesetterFps);

        EXPECT_TRUE(std::is_sorted(result.ranking.begin(), result.ranking.end(),
                                   ScoredFrameRate::DescendingScore{}));
@@ -114,8 +115,8 @@ struct TestableRefreshRateSelector : RefreshRateSelector {

    auto getRankedRefreshRatesAsPair(const std::vector<LayerRequirement>& layers,
                                     GlobalSignals signals) const {
        const auto [ranking, consideredSignals] = getRankedFrameRates(layers, signals);
        return std::make_pair(ranking, consideredSignals);
        const auto result = getRankedFrameRates(layers, signals);
        return std::make_pair(result.ranking, result.consideredSignals);
    }

    FrameRateMode getBestFrameRateMode(const std::vector<LayerRequirement>& layers = {},
@@ -1387,7 +1388,7 @@ TEST_P(RefreshRateSelectorTest, getMaxRefreshRatesByPolicyOutsideTheGroup) {
TEST_P(RefreshRateSelectorTest, powerOnImminentConsidered) {
    auto selector = createSelector(kModes_60_90, kModeId60);

    auto [refreshRates, signals] = selector.getRankedFrameRates({}, {});
    auto [refreshRates, signals, _] = selector.getRankedFrameRates({}, {});
    EXPECT_FALSE(signals.powerOnImminent);

    auto expectedRefreshRates = []() -> std::vector<FrameRateMode> {
@@ -1471,10 +1472,32 @@ TEST_P(RefreshRateSelectorTest, powerOnImminentConsidered) {
    }
}

TEST_P(RefreshRateSelectorTest, pacesetterConsidered) {
    auto selector = createSelector(kModes_60_90, kModeId60);
    constexpr RefreshRateSelector::GlobalSignals kNoSignals;

    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
    layers[0].vote = LayerVoteType::Min;

    // The pacesetterFps takes precedence over the LayerRequirement.
    {
        const auto result = selector.getRankedFrameRates(layers, {}, 90_Hz);
        EXPECT_EQ(kMode90, result.ranking.front().frameRateMode.modePtr);
        EXPECT_EQ(kNoSignals, result.consideredSignals);
    }

    // The pacesetterFps takes precedence over GlobalSignals.
    {
        const auto result = selector.getRankedFrameRates(layers, {.touch = true}, 60_Hz);
        EXPECT_EQ(kMode60, result.ranking.front().frameRateMode.modePtr);
        EXPECT_EQ(kNoSignals, result.consideredSignals);
    }
}

TEST_P(RefreshRateSelectorTest, touchConsidered) {
    auto selector = createSelector(kModes_60_90, kModeId60);

    auto [_, signals] = selector.getRankedFrameRates({}, {});
    auto signals = selector.getRankedFrameRates({}, {}).consideredSignals;
    EXPECT_FALSE(signals.touch);

    std::tie(std::ignore, signals) = selector.getRankedRefreshRatesAsPair({}, {.touch = true});
@@ -2363,7 +2386,7 @@ TEST_P(RefreshRateSelectorTest,
    lr.name = "60Hz ExplicitDefault";
    lr.focused = true;

    const auto [rankedFrameRate, signals] =
    const auto [rankedFrameRate, signals, _] =
            selector.getRankedFrameRates(layers, {.touch = true, .idle = true});

    EXPECT_EQ(rankedFrameRate.begin()->frameRateMode.modePtr, kMode60);
@@ -2587,7 +2610,7 @@ TEST_P(RefreshRateSelectorTest,
    EXPECT_EQ(SetPolicyResult::Changed,
              selector.setDisplayManagerPolicy({kModeId90, {k90, k90}, {k60_90, k60_90}}));

    const auto [ranking, signals] = selector.getRankedFrameRates({}, {});
    const auto [ranking, signals, _] = selector.getRankedFrameRates({}, {});
    EXPECT_EQ(ranking.front().frameRateMode.modePtr, kMode90);
    EXPECT_FALSE(signals.touch);

@@ -2971,7 +2994,7 @@ TEST_P(RefreshRateSelectorTest, idle) {
        layers[0].vote = voteType;
        layers[0].desiredRefreshRate = 90_Hz;

        const auto [ranking, signals] =
        const auto [ranking, signals, _] =
                selector.getRankedFrameRates(layers, {.touch = touchActive, .idle = true});

        // Refresh rate will be chosen by either touch state or idle state.
@@ -3121,16 +3144,17 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ReadsCache) {
    auto selector = createSelector(kModes_30_60_72_90_120, kModeId60);

    using GlobalSignals = RefreshRateSelector::GlobalSignals;
    const auto args = std::make_pair(std::vector<LayerRequirement>{},
                                     GlobalSignals{.touch = true, .idle = true});

    const RefreshRateSelector::RankedFrameRates result = {{RefreshRateSelector::ScoredFrameRate{
                                                                  {90_Hz, kMode90}}},
                                                          GlobalSignals{.touch = true}};

    selector.mutableGetRankedRefreshRatesCache() = {args, result};
    selector.mutableGetRankedRefreshRatesCache() = {.layers = std::vector<LayerRequirement>{},
                                                    .signals = GlobalSignals{.touch = true,
                                                                             .idle = true},
                                                    .result = result};

    EXPECT_EQ(result, selector.getRankedFrameRates(args.first, args.second));
    const auto& cache = *selector.mutableGetRankedRefreshRatesCache();
    EXPECT_EQ(result, selector.getRankedFrameRates(cache.layers, cache.signals));
}

TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_WritesCache) {
@@ -3138,15 +3162,18 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_WritesCache) {

    EXPECT_FALSE(selector.mutableGetRankedRefreshRatesCache());

    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
    RefreshRateSelector::GlobalSignals globalSignals{.touch = true, .idle = true};
    const std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
    const RefreshRateSelector::GlobalSignals globalSignals{.touch = true, .idle = true};
    const Fps pacesetterFps = 60_Hz;

    const auto result = selector.getRankedFrameRates(layers, globalSignals);
    const auto result = selector.getRankedFrameRates(layers, globalSignals, pacesetterFps);

    const auto& cache = selector.mutableGetRankedRefreshRatesCache();
    ASSERT_TRUE(cache);

    EXPECT_EQ(cache->arguments, std::make_pair(layers, globalSignals));
    EXPECT_EQ(cache->layers, layers);
    EXPECT_EQ(cache->signals, globalSignals);
    EXPECT_EQ(cache->pacesetterFps, pacesetterFps);
    EXPECT_EQ(cache->result, result);
}

@@ -4073,7 +4100,7 @@ TEST_P(RefreshRateSelectorTest, idleWhenLowestRefreshRateIsNotDivisor) {
        layers[0].vote = voteType;
        layers[0].desiredRefreshRate = 90_Hz;

        const auto [ranking, signals] =
        const auto [ranking, signals, _] =
                selector.getRankedFrameRates(layers, {.touch = touchActive, .idle = true});

        // Refresh rate will be chosen by either touch state or idle state.
Loading