Loading services/surfaceflinger/Scheduler/Scheduler.cpp +66 −52 Original line number Diff line number Diff line Loading @@ -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 { \ Loading Loading @@ -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(); } Loading @@ -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(); } Loading Loading @@ -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; }; } Loading Loading @@ -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 */); } } Loading @@ -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, Loading @@ -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() { Loading Loading @@ -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) { Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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; } Loading @@ -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; } } Loading services/surfaceflinger/Scheduler/Scheduler.h +47 −26 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -51,7 +50,6 @@ #include "RefreshRateSelector.h" #include "Utils/Dumper.h" #include "VsyncModulator.h" #include "VsyncSchedule.h" namespace android::scheduler { Loading Loading @@ -94,6 +92,8 @@ namespace scheduler { using GlobalSignals = RefreshRateSelector::GlobalSignals; class VsyncSchedule; class Scheduler : android::impl::MessageQueue { using Impl = android::impl::MessageQueue; Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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)); } Loading services/surfaceflinger/tests/unittests/TestableScheduler.h +0 −4 Original line number Diff line number Diff line Loading @@ -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>(), Loading Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +66 −52 Original line number Diff line number Diff line Loading @@ -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 { \ Loading Loading @@ -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(); } Loading @@ -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(); } Loading Loading @@ -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; }; } Loading Loading @@ -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 */); } } Loading @@ -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, Loading @@ -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() { Loading Loading @@ -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) { Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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; } Loading @@ -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; } } Loading
services/surfaceflinger/Scheduler/Scheduler.h +47 −26 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -51,7 +50,6 @@ #include "RefreshRateSelector.h" #include "Utils/Dumper.h" #include "VsyncModulator.h" #include "VsyncSchedule.h" namespace android::scheduler { Loading Loading @@ -94,6 +92,8 @@ namespace scheduler { using GlobalSignals = RefreshRateSelector::GlobalSignals; class VsyncSchedule; class Scheduler : android::impl::MessageQueue { using Impl = android::impl::MessageQueue; Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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)); } Loading
services/surfaceflinger/tests/unittests/TestableScheduler.h +0 −4 Original line number Diff line number Diff line Loading @@ -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>(), Loading