Loading services/surfaceflinger/Scheduler/Scheduler.cpp +41 −14 Original line number Diff line number Diff line Loading @@ -109,7 +109,6 @@ void Scheduler::startTimers() { void Scheduler::setPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) { demotePacesetterDisplay(); std::scoped_lock lock(mDisplayLock); promotePacesetterDisplay(pacesetterIdOpt); } Loading @@ -123,16 +122,22 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId, std::shared_ptr<VsyncSchedule> vsyncSchedule) { 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)); promotePacesetterDisplay(); pacesetterVsyncSchedule = promotePacesetterDisplayLocked(); } applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule)); } void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) { demotePacesetterDisplay(); std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule; { std::scoped_lock lock(mDisplayLock); mRefreshRateSelectors.erase(displayId); mVsyncSchedules.erase(displayId); Loading @@ -142,7 +147,9 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) { // headless virtual display.) LOG_ALWAYS_FATAL_IF(mRefreshRateSelectors.empty(), "Cannot unregister all displays!"); promotePacesetterDisplay(); pacesetterVsyncSchedule = promotePacesetterDisplayLocked(); } applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule)); } void Scheduler::run() { Loading Loading @@ -678,6 +685,18 @@ bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps di } void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) { std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule; { std::scoped_lock lock(mDisplayLock); pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterIdOpt); } applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule)); } std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked( std::optional<PhysicalDisplayId> pacesetterIdOpt) { // TODO(b/241286431): Choose the pacesetter display. mPacesetterDisplayId = pacesetterIdOpt.value_or(mRefreshRateSelectors.begin()->first); ALOGI("Display %s is the pacesetter", to_string(*mPacesetterDisplayId).c_str()); Loading @@ -697,13 +716,21 @@ void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacese vsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(), true /* force */); } return vsyncSchedule; } void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule) { onNewVsyncSchedule(vsyncSchedule->getDispatch()); std::vector<android::EventThread*> threads; { std::lock_guard<std::mutex> lock(mConnectionsLock); threads.reserve(mConnections.size()); for (auto& [_, connection] : mConnections) { connection.thread->onNewVsyncSchedule(vsyncSchedule); threads.push_back(connection.thread.get()); } } for (auto* thread : threads) { thread->onNewVsyncSchedule(vsyncSchedule); } } Loading services/surfaceflinger/Scheduler/Scheduler.h +11 −0 Original line number Diff line number Diff line Loading @@ -321,7 +321,18 @@ private: // Chooses a pacesetter among the registered displays, unless `pacesetterIdOpt` is specified. // The new `mPacesetterDisplayId` is never `std::nullopt`. void promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); // Changes to the displays (e.g. registering and unregistering) must be made // while mDisplayLock is locked, and the new pacesetter then must be promoted while // mDisplayLock is still locked. However, a new pacesetter means that // MessageQueue and EventThread need to use the new pacesetter's // VsyncSchedule, and this must happen while mDisplayLock is *not* locked, // or else we may deadlock with EventThread. std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked( std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt) REQUIRES(kMainThreadContext, mDisplayLock); void applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule>) EXCLUDES(mDisplayLock); // Blocks until the pacesetter's idle timer thread exits. `mDisplayLock` must not be locked by // the caller on the main thread to avoid deadlock, since the timer thread locks it before exit. Loading Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +41 −14 Original line number Diff line number Diff line Loading @@ -109,7 +109,6 @@ void Scheduler::startTimers() { void Scheduler::setPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) { demotePacesetterDisplay(); std::scoped_lock lock(mDisplayLock); promotePacesetterDisplay(pacesetterIdOpt); } Loading @@ -123,16 +122,22 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId, std::shared_ptr<VsyncSchedule> vsyncSchedule) { 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)); promotePacesetterDisplay(); pacesetterVsyncSchedule = promotePacesetterDisplayLocked(); } applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule)); } void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) { demotePacesetterDisplay(); std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule; { std::scoped_lock lock(mDisplayLock); mRefreshRateSelectors.erase(displayId); mVsyncSchedules.erase(displayId); Loading @@ -142,7 +147,9 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) { // headless virtual display.) LOG_ALWAYS_FATAL_IF(mRefreshRateSelectors.empty(), "Cannot unregister all displays!"); promotePacesetterDisplay(); pacesetterVsyncSchedule = promotePacesetterDisplayLocked(); } applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule)); } void Scheduler::run() { Loading Loading @@ -678,6 +685,18 @@ bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps di } void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) { std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule; { std::scoped_lock lock(mDisplayLock); pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterIdOpt); } applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule)); } std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked( std::optional<PhysicalDisplayId> pacesetterIdOpt) { // TODO(b/241286431): Choose the pacesetter display. mPacesetterDisplayId = pacesetterIdOpt.value_or(mRefreshRateSelectors.begin()->first); ALOGI("Display %s is the pacesetter", to_string(*mPacesetterDisplayId).c_str()); Loading @@ -697,13 +716,21 @@ void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacese vsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(), true /* force */); } return vsyncSchedule; } void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule) { onNewVsyncSchedule(vsyncSchedule->getDispatch()); std::vector<android::EventThread*> threads; { std::lock_guard<std::mutex> lock(mConnectionsLock); threads.reserve(mConnections.size()); for (auto& [_, connection] : mConnections) { connection.thread->onNewVsyncSchedule(vsyncSchedule); threads.push_back(connection.thread.get()); } } for (auto* thread : threads) { thread->onNewVsyncSchedule(vsyncSchedule); } } Loading
services/surfaceflinger/Scheduler/Scheduler.h +11 −0 Original line number Diff line number Diff line Loading @@ -321,7 +321,18 @@ private: // Chooses a pacesetter among the registered displays, unless `pacesetterIdOpt` is specified. // The new `mPacesetterDisplayId` is never `std::nullopt`. void promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); // Changes to the displays (e.g. registering and unregistering) must be made // while mDisplayLock is locked, and the new pacesetter then must be promoted while // mDisplayLock is still locked. However, a new pacesetter means that // MessageQueue and EventThread need to use the new pacesetter's // VsyncSchedule, and this must happen while mDisplayLock is *not* locked, // or else we may deadlock with EventThread. std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked( std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt) REQUIRES(kMainThreadContext, mDisplayLock); void applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule>) EXCLUDES(mDisplayLock); // Blocks until the pacesetter's idle timer thread exits. `mDisplayLock` must not be locked by // the caller on the main thread to avoid deadlock, since the timer thread locks it before exit. Loading