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

Commit c125bc4c authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "SF: Merge per-display maps in Scheduler" into udc-dev am: 60cd58c1

parents ed500931 60cd58c1
Loading
Loading
Loading
Loading
+66 −52
Original line number Diff line number Diff line
@@ -50,8 +50,9 @@
#include "FrontEnd/LayerHandle.h"
#include "OneShotTimer.h"
#include "SurfaceFlingerProperties.h"
#include "VSyncPredictor.h"
#include "VSyncReactor.h"
#include "VSyncTracker.h"
#include "VsyncController.h"
#include "VsyncSchedule.h"

#define RETURN_IF_INVALID_HANDLE(handle, ...)                        \
    do {                                                             \
@@ -119,14 +120,13 @@ void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelector

void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
                                        RefreshRateSelectorPtr selectorPtr,
                                        std::shared_ptr<VsyncSchedule> vsyncSchedule) {
                                        VsyncSchedulePtr schedulePtr) {
    demotePacesetterDisplay();

    std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
    {
        std::scoped_lock lock(mDisplayLock);
        mRefreshRateSelectors.emplace_or_replace(displayId, std::move(selectorPtr));
        mVsyncSchedules.emplace_or_replace(displayId, std::move(vsyncSchedule));
        mDisplays.emplace_or_replace(displayId, std::move(selectorPtr), std::move(schedulePtr));

        pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
    }
@@ -139,13 +139,12 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
    std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
    {
        std::scoped_lock lock(mDisplayLock);
        mRefreshRateSelectors.erase(displayId);
        mVsyncSchedules.erase(displayId);
        mDisplays.erase(displayId);

        // Do not allow removing the final display. Code in the scheduler expects
        // there to be at least one display. (This may be relaxed in the future with
        // headless virtual display.)
        LOG_ALWAYS_FATAL_IF(mRefreshRateSelectors.empty(), "Cannot unregister all displays!");
        LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");

        pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
    }
@@ -199,20 +198,27 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback()

impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
    return [this](uid_t uid) {
        const Fps refreshRate = pacesetterSelectorPtr()->getActiveMode().fps;
        const nsecs_t currentPeriod =
                getVsyncSchedule()->period().ns() ?: refreshRate.getPeriodNsecs();
        const auto [refreshRate, period] = [this] {
            std::scoped_lock lock(mDisplayLock);
            const auto pacesetterOpt = pacesetterDisplayLocked();
            LOG_ALWAYS_FATAL_IF(!pacesetterOpt);
            const Display& pacesetter = *pacesetterOpt;
            return std::make_pair(pacesetter.selectorPtr->getActiveMode().fps,
                                  pacesetter.schedulePtr->period());
        }();

        const Period currentPeriod = period != Period::zero() ? period : refreshRate.getPeriod();

        const auto frameRate = getFrameRateOverride(uid);
        if (!frameRate.has_value()) {
            return currentPeriod;
            return currentPeriod.ns();
        }

        const auto divisor = RefreshRateSelector::getFrameRateDivisor(refreshRate, *frameRate);
        if (divisor <= 1) {
            return currentPeriod;
            return currentPeriod.ns();
        }
        return currentPeriod * divisor;
        return currentPeriod.ns() * divisor;
    };
}

@@ -413,22 +419,23 @@ void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
    std::scoped_lock lock(mDisplayLock);
    ftl::FakeGuard guard(kMainThreadContext);

    for (const auto& [id, _] : mRefreshRateSelectors) {
    for (const auto& [id, _] : mDisplays) {
        resyncToHardwareVsyncLocked(id, allowToEnable);
    }
}

void Scheduler::resyncToHardwareVsyncLocked(PhysicalDisplayId id, bool allowToEnable,
                                            std::optional<Fps> refreshRate) {
    auto schedule = getVsyncScheduleLocked(id);
    if (schedule->isHardwareVsyncAllowed(allowToEnable)) {
    const auto displayOpt = mDisplays.get(id);
    LOG_ALWAYS_FATAL_IF(!displayOpt);
    const Display& display = *displayOpt;

    if (display.schedulePtr->isHardwareVsyncAllowed(allowToEnable)) {
        if (!refreshRate) {
            auto selectorPtr = mRefreshRateSelectors.get(id);
            LOG_ALWAYS_FATAL_IF(!selectorPtr);
            refreshRate = selectorPtr->get()->getActiveMode().modePtr->getFps();
            refreshRate = display.selectorPtr->getActiveMode().modePtr->getFps();
        }
        if (refreshRate->isValid()) {
            schedule->startPeriodTransition(mSchedulerCallback, refreshRate->getPeriod(),
            display.schedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate->getPeriod(),
                                                       false /* force */);
        }
    }
@@ -438,9 +445,10 @@ void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate) {
    std::scoped_lock lock(mDisplayLock);
    ftl::FakeGuard guard(kMainThreadContext);

    auto selectorPtr = mRefreshRateSelectors.get(id);
    LOG_ALWAYS_FATAL_IF(!selectorPtr);
    const auto mode = selectorPtr->get()->getActiveMode();
    const auto displayOpt = mDisplays.get(id);
    LOG_ALWAYS_FATAL_IF(!displayOpt);
    const Display& display = *displayOpt;
    const auto mode = display.selectorPtr->getActiveMode();

    using fps_approx_ops::operator!=;
    LOG_ALWAYS_FATAL_IF(renderFrameRate != mode.fps,
@@ -451,7 +459,7 @@ void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate) {
    ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(),
          to_string(mode.modePtr->getFps()).c_str());

    getVsyncScheduleLocked(id)->getTracker().setRenderRate(renderFrameRate);
    display.schedulePtr->getTracker().setRenderRate(renderFrameRate);
}

void Scheduler::resync() {
@@ -558,22 +566,24 @@ void Scheduler::setDisplayPowerMode(PhysicalDisplayId id, hal::PowerMode powerMo
    mLayerHistory.clear();
}

std::shared_ptr<const VsyncSchedule> Scheduler::getVsyncSchedule(
        std::optional<PhysicalDisplayId> idOpt) const {
auto Scheduler::getVsyncSchedule(std::optional<PhysicalDisplayId> idOpt) const
        -> ConstVsyncSchedulePtr {
    std::scoped_lock lock(mDisplayLock);
    return getVsyncScheduleLocked(idOpt);
}

std::shared_ptr<const VsyncSchedule> Scheduler::getVsyncScheduleLocked(
        std::optional<PhysicalDisplayId> idOpt) const {
auto Scheduler::getVsyncScheduleLocked(std::optional<PhysicalDisplayId> idOpt) const
        -> ConstVsyncSchedulePtr {
    ftl::FakeGuard guard(kMainThreadContext);

    if (!idOpt) {
        LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId, "Missing a pacesetter!");
        idOpt = mPacesetterDisplayId;
    }
    auto scheduleOpt = mVsyncSchedules.get(*idOpt);
    LOG_ALWAYS_FATAL_IF(!scheduleOpt);
    return std::const_pointer_cast<const VsyncSchedule>(scheduleOpt->get());

    const auto displayOpt = mDisplays.get(*idOpt);
    LOG_ALWAYS_FATAL_IF(!displayOpt);
    return displayOpt->get().schedulePtr;
}

void Scheduler::kernelIdleTimerCallback(TimerState state) {
@@ -597,9 +607,9 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) {
        // need to update the VsyncController model anyway.
        std::scoped_lock lock(mDisplayLock);
        ftl::FakeGuard guard(kMainThreadContext);
        constexpr bool disallow = false;
        for (auto& [_, schedule] : mVsyncSchedules) {
            schedule->disableHardwareVsync(mSchedulerCallback, disallow);
        for (const auto& [_, display] : mDisplays) {
            constexpr bool kDisallow = false;
            display.schedulePtr->disableHardwareVsync(mSchedulerCallback, kDisallow);
        }
    }

@@ -664,12 +674,12 @@ void Scheduler::dumpVsync(std::string& out) const {
                            to_string(*mPacesetterDisplayId).c_str());
        getVsyncScheduleLocked()->dump(out);
    }
    for (auto& [id, vsyncSchedule] : mVsyncSchedules) {
    for (auto& [id, display] : mDisplays) {
        if (id == mPacesetterDisplayId) {
            continue;
        }
        base::StringAppendF(&out, "VsyncSchedule for follower %s:\n", to_string(id).c_str());
        vsyncSchedule->dump(out);
        display.schedulePtr->dump(out);
    }
}

@@ -699,25 +709,29 @@ void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacese
std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
        std::optional<PhysicalDisplayId> pacesetterIdOpt) {
    // TODO(b/241286431): Choose the pacesetter display.
    mPacesetterDisplayId = pacesetterIdOpt.value_or(mRefreshRateSelectors.begin()->first);
    mPacesetterDisplayId = pacesetterIdOpt.value_or(mDisplays.begin()->first);
    ALOGI("Display %s is the pacesetter", to_string(*mPacesetterDisplayId).c_str());

    auto vsyncSchedule = getVsyncScheduleLocked(*mPacesetterDisplayId);
    if (const auto pacesetterPtr = pacesetterSelectorPtrLocked()) {
        pacesetterPtr->setIdleTimerCallbacks(
    std::shared_ptr<VsyncSchedule> newVsyncSchedulePtr;
    if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
        const Display& pacesetter = *pacesetterOpt;

        pacesetter.selectorPtr->setIdleTimerCallbacks(
                {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
                              .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
                 .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
                            .onExpired =
                                    [this] { kernelIdleTimerCallback(TimerState::Expired); }}});

        pacesetterPtr->startIdleTimer();
        pacesetter.selectorPtr->startIdleTimer();

        newVsyncSchedulePtr = pacesetter.schedulePtr;

        const Fps refreshRate = pacesetterPtr->getActiveMode().modePtr->getFps();
        vsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(),
        const Fps refreshRate = pacesetter.selectorPtr->getActiveMode().modePtr->getFps();
        newVsyncSchedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(),
                                                   true /* force */);
    }
    return vsyncSchedule;
    return newVsyncSchedulePtr;
}

void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule) {
@@ -831,9 +845,10 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap {

    const auto globalSignals = makeGlobalSignals();

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

        for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) {
            const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score);
@@ -852,7 +867,7 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap {

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

@@ -861,8 +876,7 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap {
        for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) {
            const auto [fps, tally] = *it;

            if (tally.displayCount == mRefreshRateSelectors.size() &&
                tally.score > maxScoreIt->second.score) {
            if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) {
                maxScoreIt = it;
            }
        }
+47 −26
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"

#include <ftl/algorithm.h>
#include <ftl/fake_guard.h>
#include <ftl/optional.h>
#include <scheduler/Features.h>
@@ -51,7 +50,6 @@
#include "RefreshRateSelector.h"
#include "Utils/Dumper.h"
#include "VsyncModulator.h"
#include "VsyncSchedule.h"

namespace android::scheduler {

@@ -94,6 +92,8 @@ namespace scheduler {

using GlobalSignals = RefreshRateSelector::GlobalSignals;

class VsyncSchedule;

class Scheduler : android::impl::MessageQueue {
    using Impl = android::impl::MessageQueue;

@@ -109,6 +109,9 @@ public:

    using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>;

    using ConstVsyncSchedulePtr = std::shared_ptr<const VsyncSchedule>;
    using VsyncSchedulePtr = std::shared_ptr<VsyncSchedule>;

    void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr) REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock);
    void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
@@ -237,12 +240,12 @@ public:
    void setDisplayPowerMode(PhysicalDisplayId, hal::PowerMode powerMode)
            REQUIRES(kMainThreadContext);

    std::shared_ptr<const VsyncSchedule> getVsyncSchedule(
            std::optional<PhysicalDisplayId> idOpt = std::nullopt) const EXCLUDES(mDisplayLock);
    std::shared_ptr<VsyncSchedule> getVsyncSchedule(
            std::optional<PhysicalDisplayId> idOpt = std::nullopt) EXCLUDES(mDisplayLock) {
        return std::const_pointer_cast<VsyncSchedule>(
                static_cast<const Scheduler*>(this)->getVsyncSchedule(idOpt));
    ConstVsyncSchedulePtr getVsyncSchedule(std::optional<PhysicalDisplayId> = std::nullopt) const
            EXCLUDES(mDisplayLock);

    VsyncSchedulePtr getVsyncSchedule(std::optional<PhysicalDisplayId> idOpt = std::nullopt)
            EXCLUDES(mDisplayLock) {
        return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt));
    }

    // Returns true if a given vsync timestamp is considered valid vsync
@@ -339,9 +342,8 @@ private:
    // the caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
    void demotePacesetterDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);

    void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr,
                                 std::shared_ptr<VsyncSchedule>) REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock);
    void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr)
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);

    struct Policy;

@@ -420,16 +422,37 @@ private:
    // must lock for writes but not reads. See also mPolicyLock for locking order.
    mutable std::mutex mDisplayLock;

    display::PhysicalDisplayMap<PhysicalDisplayId, RefreshRateSelectorPtr> mRefreshRateSelectors
            GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext);
    struct Display {
        Display(RefreshRateSelectorPtr selectorPtr, VsyncSchedulePtr schedulePtr)
              : selectorPtr(std::move(selectorPtr)), schedulePtr(std::move(schedulePtr)) {}

        // Effectively const except in move constructor.
        RefreshRateSelectorPtr selectorPtr;
        VsyncSchedulePtr schedulePtr;
    };

    using DisplayRef = std::reference_wrapper<Display>;
    using ConstDisplayRef = std::reference_wrapper<const Display>;

    // TODO (b/266715559): Store in the same map as mRefreshRateSelectors.
    display::PhysicalDisplayMap<PhysicalDisplayId, std::shared_ptr<VsyncSchedule>> mVsyncSchedules
            GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext);
    display::PhysicalDisplayMap<PhysicalDisplayId, Display> mDisplays GUARDED_BY(mDisplayLock)
            GUARDED_BY(kMainThreadContext);

    ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock)
            GUARDED_BY(kMainThreadContext);

    ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) {
        return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform(
                [](const Display& display) { return std::ref(const_cast<Display&>(display)); });
    }

    ftl::Optional<ConstDisplayRef> pacesetterDisplayLocked() const REQUIRES(mDisplayLock) {
        ftl::FakeGuard guard(kMainThreadContext);
        return mPacesetterDisplayId.and_then([this](PhysicalDisplayId pacesetterId)
                                                     REQUIRES(mDisplayLock, kMainThreadContext) {
                                                         return mDisplays.get(pacesetterId);
                                                     });
    }

    RefreshRateSelectorPtr pacesetterSelectorPtr() const EXCLUDES(mDisplayLock) {
        std::scoped_lock lock(mDisplayLock);
        return pacesetterSelectorPtrLocked();
@@ -437,19 +460,17 @@ private:

    RefreshRateSelectorPtr pacesetterSelectorPtrLocked() const REQUIRES(mDisplayLock) {
        ftl::FakeGuard guard(kMainThreadContext);
        return mPacesetterDisplayId
                .and_then([this](PhysicalDisplayId pacesetterId)
                                  REQUIRES(mDisplayLock, kMainThreadContext) {
                                      return mRefreshRateSelectors.get(pacesetterId);
                                  })
                .or_else(ftl::static_ref<RefreshRateSelectorPtr>([] { return nullptr; }))
        return pacesetterDisplayLocked()
                .transform([](const Display& display) { return display.selectorPtr; })
                .or_else([] { return std::optional<RefreshRateSelectorPtr>(nullptr); })
                .value();
    }

    std::shared_ptr<const VsyncSchedule> getVsyncScheduleLocked(
            std::optional<PhysicalDisplayId> idOpt = std::nullopt) const REQUIRES(mDisplayLock);
    std::shared_ptr<VsyncSchedule> getVsyncScheduleLocked(
            std::optional<PhysicalDisplayId> idOpt = std::nullopt) REQUIRES(mDisplayLock) {
    ConstVsyncSchedulePtr getVsyncScheduleLocked(
            std::optional<PhysicalDisplayId> = std::nullopt) const REQUIRES(mDisplayLock);

    VsyncSchedulePtr getVsyncScheduleLocked(std::optional<PhysicalDisplayId> idOpt = std::nullopt)
            REQUIRES(mDisplayLock) {
        return std::const_pointer_cast<VsyncSchedule>(
                static_cast<const Scheduler*>(this)->getVsyncScheduleLocked(idOpt));
    }
+0 −4
Original line number Diff line number Diff line
@@ -65,10 +65,6 @@ public:

    auto refreshRateSelector() { return pacesetterSelectorPtr(); }

    const auto& refreshRateSelectors() const NO_THREAD_SAFETY_ANALYSIS {
        return mRefreshRateSelectors;
    }

    void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
        registerDisplay(displayId, std::move(selectorPtr),
                        std::make_unique<mock::VsyncController>(),