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

Commit af744398 authored by Ram Indani's avatar Ram Indani Committed by Android (Google) Code Review
Browse files

Merge "[SF] Refresh rate selection based on the pacesetter display" into udc-dev

parents 8aedbf30 22f2ead8
Loading
Loading
Loading
Loading
+16 −62
Original line number Original line Diff line number Diff line
@@ -830,81 +830,35 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap {


    using RankedRefreshRates = RefreshRateSelector::RankedFrameRates;
    using RankedRefreshRates = RefreshRateSelector::RankedFrameRates;
    display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking;
    display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking;

    // Tallies the score of a refresh rate across `displayCount` displays.
    struct RefreshRateTally {
        explicit RefreshRateTally(float score) : score(score) {}

        float score;
        size_t displayCount = 1;
    };

    // Chosen to exceed a typical number of refresh rates across displays.
    constexpr size_t kStaticCapacity = 8;
    ftl::SmallMap<Fps, RefreshRateTally, kStaticCapacity, FpsApproxEqual> refreshRateTallies;

    const auto globalSignals = makeGlobalSignals();
    const auto globalSignals = makeGlobalSignals();
    Fps pacesetterFps;


    for (const auto& [id, display] : mDisplays) {
    for (const auto& [id, display] : mDisplays) {
        auto rankedFrameRates =
        auto rankedFrameRates =
                display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements,
                display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements,
                                                         globalSignals);
                                                         globalSignals);

        if (id == *mPacesetterDisplayId) {
        for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) {
            pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps;
            const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score);

            if (!inserted) {
                auto& tally = it->second;
                tally.score += score;
                tally.displayCount++;
        }
        }
        }

        perDisplayRanking.push_back(std::move(rankedFrameRates));
        perDisplayRanking.push_back(std::move(rankedFrameRates));
    }
    }


    auto maxScoreIt = refreshRateTallies.cbegin();

    // Find the first refresh rate common to all displays.
    while (maxScoreIt != refreshRateTallies.cend() &&
           maxScoreIt->second.displayCount != mDisplays.size()) {
        ++maxScoreIt;
    }

    if (maxScoreIt != refreshRateTallies.cend()) {
        // Choose the highest refresh rate common to all displays, if any.
        for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) {
            const auto [fps, tally] = *it;

            if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) {
                maxScoreIt = it;
            }
        }
    }

    const std::optional<Fps> chosenFps = maxScoreIt != refreshRateTallies.cend()
            ? std::make_optional(maxScoreIt->first)
            : std::nullopt;

    DisplayModeChoiceMap modeChoices;
    DisplayModeChoiceMap modeChoices;

    using fps_approx_ops::operator==;
    using fps_approx_ops::operator==;


    for (auto& [ranking, signals] : perDisplayRanking) {
    for (auto& [rankings, signals] : perDisplayRanking) {
        if (!chosenFps) {
        const auto chosenFrameRateMode =
            const auto& [frameRateMode, _] = ranking.front();
                ftl::find_if(rankings,
            modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
                             [&](const auto& ranking) {
                                    DisplayModeChoice{frameRateMode, signals});
                                 return ranking.frameRateMode.fps == pacesetterFps;
            continue;
                             })
        }
                        .transform([](const auto& scoredFrameRate) {
                            return scoredFrameRate.get().frameRateMode;
                        })
                        .value_or(rankings.front().frameRateMode);


        for (auto& [frameRateMode, _] : ranking) {
        modeChoices.try_emplace(chosenFrameRateMode.modePtr->getPhysicalDisplayId(),
            if (frameRateMode.fps == *chosenFps) {
                                DisplayModeChoice{chosenFrameRateMode, signals});
                modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
                                        DisplayModeChoice{frameRateMode, signals});
                break;
            }
        }
    }
    }
    return modeChoices;
    return modeChoices;
}
}
+22 −1
Original line number Original line Diff line number Diff line
@@ -359,7 +359,8 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
        EXPECT_EQ(expectedChoices, actualChoices);
        EXPECT_EQ(expectedChoices, actualChoices);
    }
    }
    {
    {
        // This display does not support 120 Hz, so we should choose 60 Hz despite the touch signal.
        // The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120
        // Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz.
        mScheduler
        mScheduler
                ->registerDisplay(kDisplayId3,
                ->registerDisplay(kDisplayId3,
                                  std::make_shared<RefreshRateSelector>(kDisplay3Modes,
                                  std::make_shared<RefreshRateSelector>(kDisplay3Modes,
@@ -369,6 +370,26 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
        mScheduler->replaceTouchTimer(10);
        mScheduler->replaceTouchTimer(10);
        mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
        mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);


        expectedChoices = ftl::init::map<
                const PhysicalDisplayId&,
                DisplayModeChoice>(kDisplayId1, FrameRateMode{120_Hz, kDisplay1Mode120},
                                   globalSignals)(kDisplayId2,
                                                  FrameRateMode{120_Hz, kDisplay2Mode120},
                                                  globalSignals)(kDisplayId3,
                                                                 FrameRateMode{60_Hz,
                                                                               kDisplay3Mode60},
                                                                 globalSignals);

        const auto actualChoices = mScheduler->chooseDisplayModes();
        EXPECT_EQ(expectedChoices, actualChoices);
    }
    {
        // We should choose 60Hz despite the touch signal as pacesetter only supports 60Hz
        mScheduler->setPacesetterDisplay(kDisplayId3);
        const GlobalSignals globalSignals = {.touch = true};
        mScheduler->replaceTouchTimer(10);
        mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);

        expectedChoices = ftl::init::map<
        expectedChoices = ftl::init::map<
                const PhysicalDisplayId&,
                const PhysicalDisplayId&,
                DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60},
                DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60},