diff options
-rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateSelector.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 62 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.h | 15 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 22 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/SchedulerTest.cpp | 55 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TestableScheduler.h | 15 |
7 files changed, 89 insertions, 84 deletions
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 998b1b81b1..a398c01a8f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -210,6 +210,8 @@ public: // within the timeout of DisplayPowerTimer. bool powerOnImminent = false; + bool shouldEmitEvent() const { return !idle; } + bool operator==(GlobalSignals other) const { return touch == other.touch && idle == other.idle && powerOnImminent == other.powerOnImminent; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 84584a4245..6b3113512e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -424,50 +424,49 @@ void Scheduler::onHdcpLevelsChanged(Cycle cycle, PhysicalDisplayId displayId, eventThreadFor(cycle).onHdcpLevelsChanged(displayId, connectedLevel, maxLevel); } -void Scheduler::onPrimaryDisplayModeChanged(Cycle cycle, const FrameRateMode& mode) { - { +bool Scheduler::onDisplayModeChanged(PhysicalDisplayId displayId, const FrameRateMode& mode) { + const bool isPacesetter = + FTL_FAKE_GUARD(kMainThreadContext, + (std::scoped_lock(mDisplayLock), displayId == mPacesetterDisplayId)); + + if (isPacesetter) { std::lock_guard<std::mutex> lock(mPolicyLock); - // Cache the last reported modes for primary display. - mPolicy.cachedModeChangedParams = {cycle, mode}; + mPolicy.emittedModeOpt = mode; // Invalidate content based refresh rate selection so it could be calculated // again for the new refresh rate. mPolicy.contentRequirements.clear(); } - onNonPrimaryDisplayModeChanged(cycle, mode); -} -void Scheduler::dispatchCachedReportedMode() { - // Check optional fields first. - if (!mPolicy.modeOpt) { - ALOGW("No mode ID found, not dispatching cached mode."); - return; + if (hasEventThreads()) { + eventThreadFor(Cycle::Render).onModeChanged(mode); } - if (!mPolicy.cachedModeChangedParams) { - ALOGW("No mode changed params found, not dispatching cached mode."); + + return isPacesetter; +} + +void Scheduler::emitModeChangeIfNeeded() { + if (!mPolicy.modeOpt || !mPolicy.emittedModeOpt) { + ALOGW("No mode change to emit"); return; } - // If the mode is not the current mode, this means that a - // mode change is in progress. In that case we shouldn't dispatch an event - // as it will be dispatched when the current mode changes. - if (pacesetterSelectorPtr()->getActiveMode() != mPolicy.modeOpt) { + const auto& mode = *mPolicy.modeOpt; + + if (mode != pacesetterSelectorPtr()->getActiveMode()) { + // A mode change is pending. The event will be emitted when the mode becomes active. return; } - // If there is no change from cached mode, there is no need to dispatch an event - if (*mPolicy.modeOpt == mPolicy.cachedModeChangedParams->mode) { + if (mode == *mPolicy.emittedModeOpt) { + // The event was already emitted. return; } - mPolicy.cachedModeChangedParams->mode = *mPolicy.modeOpt; - onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->cycle, - mPolicy.cachedModeChangedParams->mode); -} + mPolicy.emittedModeOpt = mode; -void Scheduler::onNonPrimaryDisplayModeChanged(Cycle cycle, const FrameRateMode& mode) { if (hasEventThreads()) { - eventThreadFor(cycle).onModeChanged(mode); + eventThreadFor(Cycle::Render).onModeChanged(mode); } } @@ -1139,7 +1138,8 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals for (auto& [id, choice] : modeChoices) { modeRequests.emplace_back( display::DisplayModeRequest{.mode = std::move(choice.mode), - .emitEvent = !choice.consideredSignals.idle}); + .emitEvent = choice.consideredSignals + .shouldEmitEvent()}); } if (!FlagManager::getInstance().vrr_bugfix_dropped_frame()) { @@ -1149,12 +1149,10 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals if (mPolicy.modeOpt != modeOpt) { mPolicy.modeOpt = modeOpt; refreshRateChanged = true; - } else { - // We don't need to change the display mode, but we might need to send an event - // about a mode change, since it was suppressed if previously considered idle. - if (!consideredSignals.idle) { - dispatchCachedReportedMode(); - } + } else if (consideredSignals.shouldEmitEvent()) { + // The mode did not change, but we may need to emit if DisplayModeRequest::emitEvent was + // previously false. + emitModeChangeIfNeeded(); } } if (refreshRateChanged) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index e1f4d2096f..4003d9f840 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -154,8 +154,8 @@ public: void dispatchHotplugError(int32_t errorCode); - void onPrimaryDisplayModeChanged(Cycle, const FrameRateMode&) EXCLUDES(mPolicyLock); - void onNonPrimaryDisplayModeChanged(Cycle, const FrameRateMode&); + // Returns true if the PhysicalDisplayId is the pacesetter. + bool onDisplayModeChanged(PhysicalDisplayId, const FrameRateMode&) EXCLUDES(mPolicyLock); void enableSyntheticVsync(bool = true) REQUIRES(kMainThreadContext); @@ -458,7 +458,7 @@ private: void updateAttachedChoreographersFrameRate(const surfaceflinger::frontend::RequestedLayerState&, Fps fps) EXCLUDES(mChoreographerLock); - void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mDisplayLock); + void emitModeChangeIfNeeded() REQUIRES(mPolicyLock) EXCLUDES(mDisplayLock); // IEventThreadCallback overrides bool throttleVsync(TimePoint, uid_t) override; @@ -584,13 +584,8 @@ private: // Chosen display mode. ftl::Optional<FrameRateMode> modeOpt; - struct ModeChangedParams { - Cycle cycle; - FrameRateMode mode; - }; - - // Parameters for latest dispatch of mode change event. - std::optional<ModeChangedParams> cachedModeChangedParams; + // Display mode of latest emitted event. + std::optional<FrameRateMode> emittedModeOpt; } mPolicy GUARDED_BY(mPolicyLock); std::mutex mChoreographerLock; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e7d802a524..9633cc5c9d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1358,7 +1358,7 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { } if (emitEvent) { - dispatchDisplayModeChangeEvent(displayId, mode); + mScheduler->onDisplayModeChanged(displayId, mode); } break; case DesiredModeAction::None: @@ -1455,7 +1455,7 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { } if (pendingModeOpt->emitEvent) { - dispatchDisplayModeChangeEvent(displayId, activeMode); + mScheduler->onDisplayModeChanged(displayId, activeMode); } } @@ -3589,16 +3589,6 @@ void SurfaceFlinger::processHotplugDisconnect(PhysicalDisplayId displayId, mPhysicalDisplays.erase(displayId); } -void SurfaceFlinger::dispatchDisplayModeChangeEvent(PhysicalDisplayId displayId, - const scheduler::FrameRateMode& mode) { - // TODO(b/255635821): Merge code paths and move to Scheduler. - const auto onDisplayModeChanged = displayId == mActiveDisplayId - ? &scheduler::Scheduler::onPrimaryDisplayModeChanged - : &scheduler::Scheduler::onNonPrimaryDisplayModeChanged; - - ((*mScheduler).*onDisplayModeChanged)(scheduler::Cycle::Render, mode); -} - sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const wp<IBinder>& displayToken, std::shared_ptr<compositionengine::Display> compositionDisplay, @@ -7959,13 +7949,9 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( const scheduler::RefreshRateSelector::Policy currentPolicy = selector.getCurrentPolicy(); ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str()); - // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might - // be depending in this callback. - if (const auto activeMode = selector.getActiveMode(); displayId == mActiveDisplayId) { - mScheduler->onPrimaryDisplayModeChanged(scheduler::Cycle::Render, activeMode); + if (const bool isPacesetter = + mScheduler->onDisplayModeChanged(displayId, selector.getActiveMode())) { toggleKernelIdleTimer(); - } else { - mScheduler->onNonPrimaryDisplayModeChanged(scheduler::Cycle::Render, activeMode); } auto preferredModeOpt = getPreferredDisplayMode(displayId, currentPolicy.defaultMode); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9b2dea2dae..8b71f3be55 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1067,8 +1067,6 @@ private: const DisplayDeviceState& drawingState) REQUIRES(mStateLock, kMainThreadContext); - void dispatchDisplayModeChangeEvent(PhysicalDisplayId, const scheduler::FrameRateMode&); - /* * VSYNC */ diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 3df724a09e..dddda05544 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -78,6 +78,8 @@ protected: SchedulerTest(); + static constexpr RefreshRateSelector::LayerRequirement kLayer = {.weight = 1.f}; + static constexpr PhysicalDisplayId kDisplayId1 = PhysicalDisplayId::fromPort(255u); static inline const ftl::NonNull<DisplayModePtr> kDisplay1Mode60 = ftl::as_non_null(createDisplayMode(kDisplayId1, DisplayModeId(0), 60_Hz)); @@ -85,6 +87,9 @@ protected: ftl::as_non_null(createDisplayMode(kDisplayId1, DisplayModeId(1), 120_Hz)); static inline const DisplayModes kDisplay1Modes = makeModes(kDisplay1Mode60, kDisplay1Mode120); + static inline FrameRateMode kDisplay1Mode60_60{60_Hz, kDisplay1Mode60}; + static inline FrameRateMode kDisplay1Mode120_120{120_Hz, kDisplay1Mode120}; + static constexpr PhysicalDisplayId kDisplayId2 = PhysicalDisplayId::fromPort(254u); static inline const ftl::NonNull<DisplayModePtr> kDisplay2Mode60 = ftl::as_non_null(createDisplayMode(kDisplayId2, DisplayModeId(0), 60_Hz)); @@ -123,6 +128,7 @@ SchedulerTest::SchedulerTest() { .WillRepeatedly(Return(mEventThreadConnection)); mScheduler->setEventThread(Cycle::Render, std::move(eventThread)); + mScheduler->setEventThread(Cycle::LastComposite, std::make_unique<MockEventThread>()); mFlinger.resetScheduler(mScheduler); } @@ -193,11 +199,39 @@ TEST_F(SchedulerTest, updateDisplayModes) { ASSERT_EQ(1u, mScheduler->getNumActiveLayers()); } -TEST_F(SchedulerTest, dispatchCachedReportedMode) { - mScheduler->clearCachedReportedMode(); +TEST_F(SchedulerTest, emitModeChangeEvent) { + const auto selectorPtr = + std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode120->getId()); + mScheduler->registerDisplay(kDisplayId1, selectorPtr); + mScheduler->onDisplayModeChanged(kDisplayId1, kDisplay1Mode120_120); + + mScheduler->setContentRequirements({kLayer}); + // No event is emitted in response to idle. EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); - EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); + + using TimerState = TestableScheduler::TimerState; + + mScheduler->idleTimerCallback(TimerState::Expired); + selectorPtr->setActiveMode(kDisplay1Mode60->getId(), 60_Hz); + + auto layer = kLayer; + layer.vote = RefreshRateSelector::LayerVoteType::ExplicitExact; + layer.desiredRefreshRate = 60_Hz; + mScheduler->setContentRequirements({layer}); + + // An event is emitted implicitly despite choosing the same mode as when idle. + EXPECT_CALL(*mEventThread, onModeChanged(kDisplay1Mode60_60)).Times(1); + + mScheduler->idleTimerCallback(TimerState::Reset); + + mScheduler->setContentRequirements({kLayer}); + + // An event is emitted explicitly for the mode change. + EXPECT_CALL(*mEventThread, onModeChanged(kDisplay1Mode120_120)).Times(1); + + mScheduler->touchTimerCallback(TimerState::Reset); + mScheduler->onDisplayModeChanged(kDisplayId1, kDisplay1Mode120_120); } TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { @@ -246,14 +280,12 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { /*updateAttachedChoreographer*/ false); } -TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) { +TEST_F(SchedulerTest, chooseDisplayModes) { mScheduler->registerDisplay(kDisplayId1, std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode60->getId())); - std::vector<RefreshRateSelector::LayerRequirement> layers = - std::vector<RefreshRateSelector::LayerRequirement>({{.weight = 1.f}, {.weight = 1.f}}); - mScheduler->setContentRequirements(layers); + mScheduler->setContentRequirements({kLayer, kLayer}); GlobalSignals globalSignals = {.idle = true}; mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); @@ -288,15 +320,14 @@ TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) { EXPECT_EQ(choice->get(), DisplayModeChoice({120_Hz, kDisplay1Mode120}, globalSignals)); } -TEST_F(SchedulerTest, chooseDisplayModesSingleDisplayHighHintTouchSignal) { +TEST_F(SchedulerTest, chooseDisplayModesHighHintTouchSignal) { mScheduler->registerDisplay(kDisplayId1, std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode60->getId())); using DisplayModeChoice = TestableScheduler::DisplayModeChoice; - std::vector<RefreshRateSelector::LayerRequirement> layers = - std::vector<RefreshRateSelector::LayerRequirement>({{.weight = 1.f}, {.weight = 1.f}}); + std::vector<RefreshRateSelector::LayerRequirement> layers = {kLayer, kLayer}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; @@ -371,9 +402,7 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { kDisplay2Mode60}, GlobalSignals{}); - std::vector<RefreshRateSelector::LayerRequirement> layers = {{.weight = 1.f}, - {.weight = 1.f}}; - mScheduler->setContentRequirements(layers); + mScheduler->setContentRequirements({kLayer, kLayer}); mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals); const auto actualChoices = mScheduler->chooseDisplayModes(); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 0814e3d6fe..df16b2e058 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -176,6 +176,11 @@ public: mPolicy.idleTimer = globalSignals.idle ? TimerState::Expired : TimerState::Reset; } + using Scheduler::TimerState; + + using Scheduler::idleTimerCallback; + using Scheduler::touchTimerCallback; + void setContentRequirements(std::vector<RefreshRateSelector::LayerRequirement> layers) { std::lock_guard<std::mutex> lock(mPolicyLock); mPolicy.contentRequirements = std::move(layers); @@ -188,15 +193,7 @@ public: return Scheduler::chooseDisplayModes(); } - void dispatchCachedReportedMode() { - std::lock_guard<std::mutex> lock(mPolicyLock); - Scheduler::dispatchCachedReportedMode(); - } - - void clearCachedReportedMode() { - std::lock_guard<std::mutex> lock(mPolicyLock); - mPolicy.cachedModeChangedParams.reset(); - } + using Scheduler::onDisplayModeChanged; void setInitialHwVsyncEnabled(PhysicalDisplayId id, bool enabled) { auto schedule = getVsyncSchedule(id); |