Loading services/surfaceflinger/DisplayDevice.cpp +24 −8 Original line number Diff line number Diff line Loading @@ -222,7 +222,6 @@ bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline& outTimeline) { mPendingModeOpt = std::move(desiredMode); mIsModeSetPending = true; const auto& mode = *mPendingModeOpt->mode.modePtr; Loading @@ -235,9 +234,22 @@ bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode return true; } void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) { setActiveMode(modeId, vsyncRate, renderFps); mIsModeSetPending = false; auto DisplayDevice::finalizeModeChange() -> ModeChange { if (!mPendingModeOpt) return NoModeChange{"No pending mode"}; auto pendingMode = *std::exchange(mPendingModeOpt, std::nullopt); auto& pendingModePtr = pendingMode.mode.modePtr; if (!mRefreshRateSelector->displayModes().contains(pendingModePtr->getId())) { return NoModeChange{"Unknown pending mode"}; } if (getActiveMode().modePtr->getResolution() != pendingModePtr->getResolution()) { return ResolutionChange{std::move(pendingMode)}; } setActiveMode(pendingModePtr->getId(), pendingModePtr->getVsyncRate(), pendingMode.mode.fps); return RefreshRateChange{std::move(pendingMode)}; } nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { Loading Loading @@ -571,11 +583,15 @@ auto DisplayDevice::getDesiredMode() const -> DisplayModeRequestOpt { return mDesiredModeOpt; } void DisplayDevice::clearDesiredMode() { auto DisplayDevice::takeDesiredMode() -> DisplayModeRequestOpt { DisplayModeRequestOpt desiredModeOpt; { std::scoped_lock lock(mDesiredModeLock); mDesiredModeOpt.reset(); std::swap(mDesiredModeOpt, desiredModeOpt); mHasDesiredModeTrace = false; } return desiredModeOpt; } void DisplayDevice::adjustRefreshRate(Fps pacesetterDisplayRefreshRate) { using fps_approx_ops::operator<=; Loading services/surfaceflinger/DisplayDevice.h +29 −7 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <memory> #include <string> #include <unordered_map> #include <variant> #include <android-base/thread_annotations.h> #include <android/native_window.h> Loading Loading @@ -194,12 +195,11 @@ public: using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>; DisplayModeRequestOpt getDesiredMode() const EXCLUDES(mDesiredModeLock); void clearDesiredMode() EXCLUDES(mDesiredModeLock); DisplayModeRequestOpt takeDesiredMode() EXCLUDES(mDesiredModeLock); DisplayModeRequestOpt getPendingMode() const REQUIRES(kMainThreadContext) { return mPendingModeOpt; bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mPendingModeOpt.has_value(); } bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mIsModeSetPending; } scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) { return mRefreshRateSelector->getActiveMode(); Loading @@ -211,8 +211,25 @@ public: hal::VsyncPeriodChangeTimeline& outTimeline) REQUIRES(kMainThreadContext); void finalizeModeChange(DisplayModeId, Fps vsyncRate, Fps renderFps) REQUIRES(kMainThreadContext); struct NoModeChange { const char* reason; }; struct ResolutionChange { display::DisplayModeRequest activeMode; }; struct RefreshRateChange { display::DisplayModeRequest activeMode; }; using ModeChange = std::variant<NoModeChange, ResolutionChange, RefreshRateChange>; // Clears the pending DisplayModeRequest, and returns the ModeChange that occurred. If it was a // RefreshRateChange, the pending mode becomes the active mode. If it was a ResolutionChange, // the caller is responsible for resizing the framebuffer to match the active resolution by // recreating the DisplayDevice. ModeChange finalizeModeChange() REQUIRES(kMainThreadContext); scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; } Loading Loading @@ -249,6 +266,8 @@ public: void dump(utils::Dumper&) const; private: friend class TestableSurfaceFlinger; template <size_t N> inline std::string concatId(const char (&str)[N]) const { return std::string(ftl::Concat(str, ' ', getId().value).str()); Loading Loading @@ -299,12 +318,15 @@ private: // This parameter is only used for hdr/sdr ratio overlay float mHdrSdrRatio = 1.0f; // A DisplayModeRequest flows through three states: desired, pending, and active. Requests // within a frame are merged into a single desired request. Unless cleared, the request is // relayed to HWC on the next frame, and becomes pending. The mode becomes active once HWC // signals the present fence to confirm the mode set. mutable std::mutex mDesiredModeLock; DisplayModeRequestOpt mDesiredModeOpt GUARDED_BY(mDesiredModeLock); TracedOrdinal<bool> mHasDesiredModeTrace GUARDED_BY(mDesiredModeLock); DisplayModeRequestOpt mPendingModeOpt GUARDED_BY(kMainThreadContext); bool mIsModeSetPending GUARDED_BY(kMainThreadContext) = false; }; struct DisplayDeviceState { Loading services/surfaceflinger/SurfaceFlinger.cpp +60 −69 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ #include <ftl/concat.h> #include <ftl/fake_guard.h> #include <ftl/future.h> #include <ftl/match.h> #include <ftl/unit.h> #include <gui/AidlStatusUtil.h> #include <gui/BufferQueue.h> Loading Loading @@ -1229,20 +1230,21 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken, return NO_ERROR; } void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) { const auto displayId = request.mode.modePtr->getPhysicalDisplayId(); void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode, bool force) { const auto mode = desiredMode.mode; const auto displayId = mode.modePtr->getPhysicalDisplayId(); ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); const auto display = getDisplayDeviceLocked(displayId); if (!display) { ALOGW("%s: display is no longer valid", __func__); ALOGW("%s: Unknown display %s", __func__, to_string(displayId).c_str()); return; } const auto mode = request.mode; const bool emitEvent = request.emitEvent; const bool emitEvent = desiredMode.emitEvent; switch (display->setDesiredMode(std::move(request), force)) { switch (display->setDesiredMode(std::move(desiredMode), force)) { case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch: // DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler. mScheduler->setRenderRate(displayId, Loading Loading @@ -1338,61 +1340,55 @@ void SurfaceFlinger::finalizeDisplayModeChange(DisplayDevice& display) { const auto displayId = display.getPhysicalId(); ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); const auto pendingModeOpt = display.getPendingMode(); if (!pendingModeOpt) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. return; } ftl::match( display.finalizeModeChange(), [this, displayId](DisplayDevice::RefreshRateChange change) { ftl::FakeGuard guard(mStateLock); const auto& activeMode = pendingModeOpt->mode; if (change.activeMode.emitEvent) { dispatchDisplayModeChangeEvent(displayId, change.activeMode.mode); } if (display.getActiveMode().modePtr->getResolution() != activeMode.modePtr->getResolution()) { applyActiveMode(std::move(change.activeMode)); }, [&](DisplayDevice::ResolutionChange change) { auto& state = mCurrentState.displays.editValueFor(display.getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). // Assign a new sequence ID to recreate the display and so its framebuffer. state.sequenceId = DisplayDeviceState{}.sequenceId; state.physical->activeMode = activeMode.modePtr.get(); processDisplayChangesLocked(); // processDisplayChangesLocked will update all necessary components so we're done here. return; } display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(), activeMode.fps); state.physical->activeMode = change.activeMode.mode.modePtr.get(); if (displayId == mActiveDisplayId) { mRefreshRateStats->setRefreshRate(activeMode.fps); updatePhaseConfiguration(activeMode.fps); } ftl::FakeGuard guard1(kMainThreadContext); ftl::FakeGuard guard2(mStateLock); processDisplayChangesLocked(); if (pendingModeOpt->emitEvent) { dispatchDisplayModeChangeEvent(displayId, activeMode); } applyActiveMode(std::move(change.activeMode)); }, [](DisplayDevice::NoModeChange noChange) { // TODO(b/255635821): Remove this case, as it should no longer happen. ALOGE("A mode change was initiated but not finalized: %s", noChange.reason); }); } void SurfaceFlinger::dropModeRequest(const sp<DisplayDevice>& display) { display->clearDesiredMode(); if (display->getPhysicalId() == mActiveDisplayId) { void SurfaceFlinger::dropModeRequest(display::DisplayModeRequest&& request) { if (request.mode.modePtr->getPhysicalDisplayId() == mActiveDisplayId) { // TODO(b/255635711): Check for pending mode changes on other displays. mScheduler->setModeChangePending(false); } } void SurfaceFlinger::applyActiveMode(const sp<DisplayDevice>& display) { const auto activeModeOpt = display->getDesiredMode(); auto activeModePtr = activeModeOpt->mode.modePtr; void SurfaceFlinger::applyActiveMode(display::DisplayModeRequest&& activeMode) { auto activeModePtr = activeMode.mode.modePtr; const auto displayId = activeModePtr->getPhysicalDisplayId(); const auto renderFps = activeModeOpt->mode.fps; const auto renderFps = activeMode.mode.fps; dropModeRequest(display); dropModeRequest(std::move(activeMode)); constexpr bool kAllowToEnable = true; mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, std::move(activeModePtr).take()); mScheduler->setRenderRate(displayId, renderFps); if (displayId == mActiveDisplayId) { mRefreshRateStats->setRefreshRate(renderFps); updatePhaseConfiguration(renderFps); } } Loading @@ -1406,50 +1402,50 @@ void SurfaceFlinger::initiateDisplayModeChanges() { const auto display = getDisplayDeviceLocked(id); if (!display) continue; auto desiredModeOpt = display->getDesiredMode(); auto desiredModeOpt = display->takeDesiredMode(); if (!desiredModeOpt) { continue; } auto desiredMode = std::move(*desiredModeOpt); if (!shouldApplyRefreshRateSelectorPolicy(*display)) { dropModeRequest(display); dropModeRequest(std::move(desiredMode)); continue; } const auto desiredModeId = desiredModeOpt->mode.modePtr->getId(); const auto desiredModeId = desiredMode.mode.modePtr->getId(); const auto displayModePtrOpt = physical.snapshot().displayModes().get(desiredModeId); if (!displayModePtrOpt) { ALOGW("Desired display mode is no longer supported. Mode ID = %d", desiredModeId.value()); dropModeRequest(display); ALOGW("%s: Unknown mode %d for display %s", __func__, desiredModeId.value(), to_string(id).c_str()); dropModeRequest(std::move(desiredMode)); continue; } ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(), to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(), to_string(display->getId()).c_str()); if (display->getActiveMode() == desiredModeOpt->mode) { applyActiveMode(display); if (display->getActiveMode() == desiredMode.mode) { dropModeRequest(std::move(desiredMode)); continue; } // Desired active mode was set, it is different than the mode currently in use, however // allowed modes might have changed by the time we process the refresh. // Make sure the desired mode is still allowed if (!display->refreshRateSelector().isModeAllowed(desiredModeOpt->mode)) { dropModeRequest(display); // The desired mode is different from the active mode. However, the allowed modes might have // changed since setDesiredMode scheduled a mode transition. if (!display->refreshRateSelector().isModeAllowed(desiredMode.mode)) { dropModeRequest(std::move(desiredMode)); continue; } // TODO(b/142753666) use constrains ALOGV("Mode setting display %s to %d (%s)", to_string(id).c_str(), desiredModeId.value(), to_string(displayModePtrOpt.value().get()->getVsyncRate()).c_str()); // TODO(b/142753666): Use constraints. hal::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; if (!display->initiateModeChange(std::move(*desiredModeOpt), constraints, outTimeline)) { if (!display->initiateModeChange(std::move(desiredMode), constraints, outTimeline)) { continue; } Loading @@ -1469,11 +1465,6 @@ void SurfaceFlinger::initiateDisplayModeChanges() { if (displayToUpdateImmediately) { const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately); finalizeDisplayModeChange(*display); const auto desiredModeOpt = display->getDesiredMode(); if (desiredModeOpt && display->getActiveMode() == desiredModeOpt->mode) { applyActiveMode(display); } } } Loading Loading @@ -7391,7 +7382,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { if (!updateOverlay) return; // Update the overlay on the main thread to avoid race conditions with // RefreshRateSelector::getActiveMode // RefreshRateSelector::getActiveMode. static_cast<void>(mScheduler->schedule([=, this] { const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (!display) { Loading services/surfaceflinger/SurfaceFlinger.h +3 −3 Original line number Diff line number Diff line Loading @@ -725,9 +725,9 @@ private: void initiateDisplayModeChanges() REQUIRES(mStateLock, kMainThreadContext); void finalizeDisplayModeChange(DisplayDevice&) REQUIRES(mStateLock, kMainThreadContext); // TODO(b/241285191): Replace DisplayDevice with DisplayModeRequest, and move to Scheduler. void dropModeRequest(const sp<DisplayDevice>&) REQUIRES(mStateLock); void applyActiveMode(const sp<DisplayDevice>&) REQUIRES(mStateLock); // TODO(b/241285191): Move to Scheduler. void dropModeRequest(display::DisplayModeRequest&&) REQUIRES(mStateLock); void applyActiveMode(display::DisplayModeRequest&&) REQUIRES(mStateLock); // Called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) Loading services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +54 −23 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #define EXPECT_DISPLAY_MODE_REQUEST(expected, requestOpt) \ #define EXPECT_DISPLAY_MODE_REQUEST(expected, request) \ EXPECT_FRAME_RATE_MODE(expected.mode.modePtr, expected.mode.fps, request.mode); \ EXPECT_EQ(expected.emitEvent, request.emitEvent) #define EXPECT_DISPLAY_MODE_REQUEST_OPT(expected, requestOpt) \ ASSERT_TRUE(requestOpt); \ EXPECT_FRAME_RATE_MODE(expected.mode.modePtr, expected.mode.fps, requestOpt->mode); \ EXPECT_EQ(expected.emitEvent, requestOpt->emitEvent) EXPECT_DISPLAY_MODE_REQUEST(expected, (*requestOpt)) namespace android { namespace { Loading @@ -37,6 +40,7 @@ using DisplayModeRequest = display::DisplayModeRequest; class InitiateModeChangeTest : public DisplayTransactionTest { public: using Action = DisplayDevice::DesiredModeAction; void SetUp() override { injectFakeBufferQueueFactory(); injectFakeNativeWindowSurfaceFactory(); Loading Loading @@ -84,36 +88,43 @@ TEST_F(InitiateModeChangeTest, setDesiredModeToActiveMode) { TEST_F(InitiateModeChangeTest, setDesiredMode) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_EQ(Action::None, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode120))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode120, mDisplay->getDesiredMode()); } TEST_F(InitiateModeChangeTest, clearDesiredMode) { TEST_F(InitiateModeChangeTest, takeDesiredMode) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_TRUE(mDisplay->getDesiredMode()); EXPECT_EQ(kDesiredMode90, mDisplay->getDesiredMode()); mDisplay->clearDesiredMode(); EXPECT_EQ(kDesiredMode90, mDisplay->takeDesiredMode()); EXPECT_FALSE(mDisplay->getDesiredMode()); } TEST_F(InitiateModeChangeTest, initiateModeChange) REQUIRES(kMainThreadContext) { TEST_F(InitiateModeChangeTest, initiateModeChange) FTL_FAKE_GUARD(kMainThreadContext) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode90, mDisplay->getDesiredMode()); const hal::VsyncPeriodChangeConstraints constraints{ .desiredTimeNanos = systemTime(), .seamlessRequired = false, }; hal::VsyncPeriodChangeTimeline timeline; EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getPendingMode()); mDisplay->clearDesiredMode(); auto desiredModeOpt = mDisplay->takeDesiredMode(); ASSERT_TRUE(desiredModeOpt); EXPECT_FALSE(mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(std::move(*desiredModeOpt), constraints, timeline)); auto modeChange = mDisplay->finalizeModeChange(); auto* changePtr = std::get_if<DisplayDevice::RefreshRateChange>(&modeChange); ASSERT_TRUE(changePtr); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, changePtr->activeMode); } TEST_F(InitiateModeChangeTest, initiateRenderRateSwitch) { Loading @@ -125,27 +136,47 @@ TEST_F(InitiateModeChangeTest, initiateRenderRateSwitch) { TEST_F(InitiateModeChangeTest, initiateDisplayModeSwitch) FTL_FAKE_GUARD(kMainThreadContext) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode90, mDisplay->getDesiredMode()); const hal::VsyncPeriodChangeConstraints constraints{ .desiredTimeNanos = systemTime(), .seamlessRequired = false, }; hal::VsyncPeriodChangeTimeline timeline; EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getPendingMode()); auto desiredModeOpt = mDisplay->takeDesiredMode(); ASSERT_TRUE(desiredModeOpt); EXPECT_FALSE(mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(std::move(*desiredModeOpt), constraints, timeline)); auto modeChange = mDisplay->finalizeModeChange(); auto* changePtr = std::get_if<DisplayDevice::RefreshRateChange>(&modeChange); ASSERT_TRUE(changePtr); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, changePtr->activeMode); // The latest request should override the desired mode. EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode60))); EXPECT_EQ(Action::None, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode120))); ASSERT_TRUE(mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getPendingMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode120, mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDisplay->getPendingMode()); // No pending mode change. EXPECT_TRUE( std::holds_alternative<DisplayDevice::NoModeChange>(mDisplay->finalizeModeChange())); mDisplay->clearDesiredMode(); desiredModeOpt = mDisplay->takeDesiredMode(); ASSERT_TRUE(desiredModeOpt); EXPECT_FALSE(mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(std::move(*desiredModeOpt), constraints, timeline)); modeChange = mDisplay->finalizeModeChange(); changePtr = std::get_if<DisplayDevice::RefreshRateChange>(&modeChange); ASSERT_TRUE(changePtr); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, changePtr->activeMode); } } // namespace Loading Loading
services/surfaceflinger/DisplayDevice.cpp +24 −8 Original line number Diff line number Diff line Loading @@ -222,7 +222,6 @@ bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline& outTimeline) { mPendingModeOpt = std::move(desiredMode); mIsModeSetPending = true; const auto& mode = *mPendingModeOpt->mode.modePtr; Loading @@ -235,9 +234,22 @@ bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode return true; } void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) { setActiveMode(modeId, vsyncRate, renderFps); mIsModeSetPending = false; auto DisplayDevice::finalizeModeChange() -> ModeChange { if (!mPendingModeOpt) return NoModeChange{"No pending mode"}; auto pendingMode = *std::exchange(mPendingModeOpt, std::nullopt); auto& pendingModePtr = pendingMode.mode.modePtr; if (!mRefreshRateSelector->displayModes().contains(pendingModePtr->getId())) { return NoModeChange{"Unknown pending mode"}; } if (getActiveMode().modePtr->getResolution() != pendingModePtr->getResolution()) { return ResolutionChange{std::move(pendingMode)}; } setActiveMode(pendingModePtr->getId(), pendingModePtr->getVsyncRate(), pendingMode.mode.fps); return RefreshRateChange{std::move(pendingMode)}; } nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { Loading Loading @@ -571,11 +583,15 @@ auto DisplayDevice::getDesiredMode() const -> DisplayModeRequestOpt { return mDesiredModeOpt; } void DisplayDevice::clearDesiredMode() { auto DisplayDevice::takeDesiredMode() -> DisplayModeRequestOpt { DisplayModeRequestOpt desiredModeOpt; { std::scoped_lock lock(mDesiredModeLock); mDesiredModeOpt.reset(); std::swap(mDesiredModeOpt, desiredModeOpt); mHasDesiredModeTrace = false; } return desiredModeOpt; } void DisplayDevice::adjustRefreshRate(Fps pacesetterDisplayRefreshRate) { using fps_approx_ops::operator<=; Loading
services/surfaceflinger/DisplayDevice.h +29 −7 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <memory> #include <string> #include <unordered_map> #include <variant> #include <android-base/thread_annotations.h> #include <android/native_window.h> Loading Loading @@ -194,12 +195,11 @@ public: using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>; DisplayModeRequestOpt getDesiredMode() const EXCLUDES(mDesiredModeLock); void clearDesiredMode() EXCLUDES(mDesiredModeLock); DisplayModeRequestOpt takeDesiredMode() EXCLUDES(mDesiredModeLock); DisplayModeRequestOpt getPendingMode() const REQUIRES(kMainThreadContext) { return mPendingModeOpt; bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mPendingModeOpt.has_value(); } bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mIsModeSetPending; } scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) { return mRefreshRateSelector->getActiveMode(); Loading @@ -211,8 +211,25 @@ public: hal::VsyncPeriodChangeTimeline& outTimeline) REQUIRES(kMainThreadContext); void finalizeModeChange(DisplayModeId, Fps vsyncRate, Fps renderFps) REQUIRES(kMainThreadContext); struct NoModeChange { const char* reason; }; struct ResolutionChange { display::DisplayModeRequest activeMode; }; struct RefreshRateChange { display::DisplayModeRequest activeMode; }; using ModeChange = std::variant<NoModeChange, ResolutionChange, RefreshRateChange>; // Clears the pending DisplayModeRequest, and returns the ModeChange that occurred. If it was a // RefreshRateChange, the pending mode becomes the active mode. If it was a ResolutionChange, // the caller is responsible for resizing the framebuffer to match the active resolution by // recreating the DisplayDevice. ModeChange finalizeModeChange() REQUIRES(kMainThreadContext); scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; } Loading Loading @@ -249,6 +266,8 @@ public: void dump(utils::Dumper&) const; private: friend class TestableSurfaceFlinger; template <size_t N> inline std::string concatId(const char (&str)[N]) const { return std::string(ftl::Concat(str, ' ', getId().value).str()); Loading Loading @@ -299,12 +318,15 @@ private: // This parameter is only used for hdr/sdr ratio overlay float mHdrSdrRatio = 1.0f; // A DisplayModeRequest flows through three states: desired, pending, and active. Requests // within a frame are merged into a single desired request. Unless cleared, the request is // relayed to HWC on the next frame, and becomes pending. The mode becomes active once HWC // signals the present fence to confirm the mode set. mutable std::mutex mDesiredModeLock; DisplayModeRequestOpt mDesiredModeOpt GUARDED_BY(mDesiredModeLock); TracedOrdinal<bool> mHasDesiredModeTrace GUARDED_BY(mDesiredModeLock); DisplayModeRequestOpt mPendingModeOpt GUARDED_BY(kMainThreadContext); bool mIsModeSetPending GUARDED_BY(kMainThreadContext) = false; }; struct DisplayDeviceState { Loading
services/surfaceflinger/SurfaceFlinger.cpp +60 −69 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ #include <ftl/concat.h> #include <ftl/fake_guard.h> #include <ftl/future.h> #include <ftl/match.h> #include <ftl/unit.h> #include <gui/AidlStatusUtil.h> #include <gui/BufferQueue.h> Loading Loading @@ -1229,20 +1230,21 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken, return NO_ERROR; } void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) { const auto displayId = request.mode.modePtr->getPhysicalDisplayId(); void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode, bool force) { const auto mode = desiredMode.mode; const auto displayId = mode.modePtr->getPhysicalDisplayId(); ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); const auto display = getDisplayDeviceLocked(displayId); if (!display) { ALOGW("%s: display is no longer valid", __func__); ALOGW("%s: Unknown display %s", __func__, to_string(displayId).c_str()); return; } const auto mode = request.mode; const bool emitEvent = request.emitEvent; const bool emitEvent = desiredMode.emitEvent; switch (display->setDesiredMode(std::move(request), force)) { switch (display->setDesiredMode(std::move(desiredMode), force)) { case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch: // DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler. mScheduler->setRenderRate(displayId, Loading Loading @@ -1338,61 +1340,55 @@ void SurfaceFlinger::finalizeDisplayModeChange(DisplayDevice& display) { const auto displayId = display.getPhysicalId(); ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); const auto pendingModeOpt = display.getPendingMode(); if (!pendingModeOpt) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. return; } ftl::match( display.finalizeModeChange(), [this, displayId](DisplayDevice::RefreshRateChange change) { ftl::FakeGuard guard(mStateLock); const auto& activeMode = pendingModeOpt->mode; if (change.activeMode.emitEvent) { dispatchDisplayModeChangeEvent(displayId, change.activeMode.mode); } if (display.getActiveMode().modePtr->getResolution() != activeMode.modePtr->getResolution()) { applyActiveMode(std::move(change.activeMode)); }, [&](DisplayDevice::ResolutionChange change) { auto& state = mCurrentState.displays.editValueFor(display.getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). // Assign a new sequence ID to recreate the display and so its framebuffer. state.sequenceId = DisplayDeviceState{}.sequenceId; state.physical->activeMode = activeMode.modePtr.get(); processDisplayChangesLocked(); // processDisplayChangesLocked will update all necessary components so we're done here. return; } display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(), activeMode.fps); state.physical->activeMode = change.activeMode.mode.modePtr.get(); if (displayId == mActiveDisplayId) { mRefreshRateStats->setRefreshRate(activeMode.fps); updatePhaseConfiguration(activeMode.fps); } ftl::FakeGuard guard1(kMainThreadContext); ftl::FakeGuard guard2(mStateLock); processDisplayChangesLocked(); if (pendingModeOpt->emitEvent) { dispatchDisplayModeChangeEvent(displayId, activeMode); } applyActiveMode(std::move(change.activeMode)); }, [](DisplayDevice::NoModeChange noChange) { // TODO(b/255635821): Remove this case, as it should no longer happen. ALOGE("A mode change was initiated but not finalized: %s", noChange.reason); }); } void SurfaceFlinger::dropModeRequest(const sp<DisplayDevice>& display) { display->clearDesiredMode(); if (display->getPhysicalId() == mActiveDisplayId) { void SurfaceFlinger::dropModeRequest(display::DisplayModeRequest&& request) { if (request.mode.modePtr->getPhysicalDisplayId() == mActiveDisplayId) { // TODO(b/255635711): Check for pending mode changes on other displays. mScheduler->setModeChangePending(false); } } void SurfaceFlinger::applyActiveMode(const sp<DisplayDevice>& display) { const auto activeModeOpt = display->getDesiredMode(); auto activeModePtr = activeModeOpt->mode.modePtr; void SurfaceFlinger::applyActiveMode(display::DisplayModeRequest&& activeMode) { auto activeModePtr = activeMode.mode.modePtr; const auto displayId = activeModePtr->getPhysicalDisplayId(); const auto renderFps = activeModeOpt->mode.fps; const auto renderFps = activeMode.mode.fps; dropModeRequest(display); dropModeRequest(std::move(activeMode)); constexpr bool kAllowToEnable = true; mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, std::move(activeModePtr).take()); mScheduler->setRenderRate(displayId, renderFps); if (displayId == mActiveDisplayId) { mRefreshRateStats->setRefreshRate(renderFps); updatePhaseConfiguration(renderFps); } } Loading @@ -1406,50 +1402,50 @@ void SurfaceFlinger::initiateDisplayModeChanges() { const auto display = getDisplayDeviceLocked(id); if (!display) continue; auto desiredModeOpt = display->getDesiredMode(); auto desiredModeOpt = display->takeDesiredMode(); if (!desiredModeOpt) { continue; } auto desiredMode = std::move(*desiredModeOpt); if (!shouldApplyRefreshRateSelectorPolicy(*display)) { dropModeRequest(display); dropModeRequest(std::move(desiredMode)); continue; } const auto desiredModeId = desiredModeOpt->mode.modePtr->getId(); const auto desiredModeId = desiredMode.mode.modePtr->getId(); const auto displayModePtrOpt = physical.snapshot().displayModes().get(desiredModeId); if (!displayModePtrOpt) { ALOGW("Desired display mode is no longer supported. Mode ID = %d", desiredModeId.value()); dropModeRequest(display); ALOGW("%s: Unknown mode %d for display %s", __func__, desiredModeId.value(), to_string(id).c_str()); dropModeRequest(std::move(desiredMode)); continue; } ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(), to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(), to_string(display->getId()).c_str()); if (display->getActiveMode() == desiredModeOpt->mode) { applyActiveMode(display); if (display->getActiveMode() == desiredMode.mode) { dropModeRequest(std::move(desiredMode)); continue; } // Desired active mode was set, it is different than the mode currently in use, however // allowed modes might have changed by the time we process the refresh. // Make sure the desired mode is still allowed if (!display->refreshRateSelector().isModeAllowed(desiredModeOpt->mode)) { dropModeRequest(display); // The desired mode is different from the active mode. However, the allowed modes might have // changed since setDesiredMode scheduled a mode transition. if (!display->refreshRateSelector().isModeAllowed(desiredMode.mode)) { dropModeRequest(std::move(desiredMode)); continue; } // TODO(b/142753666) use constrains ALOGV("Mode setting display %s to %d (%s)", to_string(id).c_str(), desiredModeId.value(), to_string(displayModePtrOpt.value().get()->getVsyncRate()).c_str()); // TODO(b/142753666): Use constraints. hal::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; if (!display->initiateModeChange(std::move(*desiredModeOpt), constraints, outTimeline)) { if (!display->initiateModeChange(std::move(desiredMode), constraints, outTimeline)) { continue; } Loading @@ -1469,11 +1465,6 @@ void SurfaceFlinger::initiateDisplayModeChanges() { if (displayToUpdateImmediately) { const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately); finalizeDisplayModeChange(*display); const auto desiredModeOpt = display->getDesiredMode(); if (desiredModeOpt && display->getActiveMode() == desiredModeOpt->mode) { applyActiveMode(display); } } } Loading Loading @@ -7391,7 +7382,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { if (!updateOverlay) return; // Update the overlay on the main thread to avoid race conditions with // RefreshRateSelector::getActiveMode // RefreshRateSelector::getActiveMode. static_cast<void>(mScheduler->schedule([=, this] { const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (!display) { Loading
services/surfaceflinger/SurfaceFlinger.h +3 −3 Original line number Diff line number Diff line Loading @@ -725,9 +725,9 @@ private: void initiateDisplayModeChanges() REQUIRES(mStateLock, kMainThreadContext); void finalizeDisplayModeChange(DisplayDevice&) REQUIRES(mStateLock, kMainThreadContext); // TODO(b/241285191): Replace DisplayDevice with DisplayModeRequest, and move to Scheduler. void dropModeRequest(const sp<DisplayDevice>&) REQUIRES(mStateLock); void applyActiveMode(const sp<DisplayDevice>&) REQUIRES(mStateLock); // TODO(b/241285191): Move to Scheduler. void dropModeRequest(display::DisplayModeRequest&&) REQUIRES(mStateLock); void applyActiveMode(display::DisplayModeRequest&&) REQUIRES(mStateLock); // Called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) Loading
services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +54 −23 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #define EXPECT_DISPLAY_MODE_REQUEST(expected, requestOpt) \ #define EXPECT_DISPLAY_MODE_REQUEST(expected, request) \ EXPECT_FRAME_RATE_MODE(expected.mode.modePtr, expected.mode.fps, request.mode); \ EXPECT_EQ(expected.emitEvent, request.emitEvent) #define EXPECT_DISPLAY_MODE_REQUEST_OPT(expected, requestOpt) \ ASSERT_TRUE(requestOpt); \ EXPECT_FRAME_RATE_MODE(expected.mode.modePtr, expected.mode.fps, requestOpt->mode); \ EXPECT_EQ(expected.emitEvent, requestOpt->emitEvent) EXPECT_DISPLAY_MODE_REQUEST(expected, (*requestOpt)) namespace android { namespace { Loading @@ -37,6 +40,7 @@ using DisplayModeRequest = display::DisplayModeRequest; class InitiateModeChangeTest : public DisplayTransactionTest { public: using Action = DisplayDevice::DesiredModeAction; void SetUp() override { injectFakeBufferQueueFactory(); injectFakeNativeWindowSurfaceFactory(); Loading Loading @@ -84,36 +88,43 @@ TEST_F(InitiateModeChangeTest, setDesiredModeToActiveMode) { TEST_F(InitiateModeChangeTest, setDesiredMode) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_EQ(Action::None, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode120))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode120, mDisplay->getDesiredMode()); } TEST_F(InitiateModeChangeTest, clearDesiredMode) { TEST_F(InitiateModeChangeTest, takeDesiredMode) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_TRUE(mDisplay->getDesiredMode()); EXPECT_EQ(kDesiredMode90, mDisplay->getDesiredMode()); mDisplay->clearDesiredMode(); EXPECT_EQ(kDesiredMode90, mDisplay->takeDesiredMode()); EXPECT_FALSE(mDisplay->getDesiredMode()); } TEST_F(InitiateModeChangeTest, initiateModeChange) REQUIRES(kMainThreadContext) { TEST_F(InitiateModeChangeTest, initiateModeChange) FTL_FAKE_GUARD(kMainThreadContext) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode90, mDisplay->getDesiredMode()); const hal::VsyncPeriodChangeConstraints constraints{ .desiredTimeNanos = systemTime(), .seamlessRequired = false, }; hal::VsyncPeriodChangeTimeline timeline; EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getPendingMode()); mDisplay->clearDesiredMode(); auto desiredModeOpt = mDisplay->takeDesiredMode(); ASSERT_TRUE(desiredModeOpt); EXPECT_FALSE(mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(std::move(*desiredModeOpt), constraints, timeline)); auto modeChange = mDisplay->finalizeModeChange(); auto* changePtr = std::get_if<DisplayDevice::RefreshRateChange>(&modeChange); ASSERT_TRUE(changePtr); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, changePtr->activeMode); } TEST_F(InitiateModeChangeTest, initiateRenderRateSwitch) { Loading @@ -125,27 +136,47 @@ TEST_F(InitiateModeChangeTest, initiateRenderRateSwitch) { TEST_F(InitiateModeChangeTest, initiateDisplayModeSwitch) FTL_FAKE_GUARD(kMainThreadContext) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode90))); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode90, mDisplay->getDesiredMode()); const hal::VsyncPeriodChangeConstraints constraints{ .desiredTimeNanos = systemTime(), .seamlessRequired = false, }; hal::VsyncPeriodChangeTimeline timeline; EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getPendingMode()); auto desiredModeOpt = mDisplay->takeDesiredMode(); ASSERT_TRUE(desiredModeOpt); EXPECT_FALSE(mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(std::move(*desiredModeOpt), constraints, timeline)); auto modeChange = mDisplay->finalizeModeChange(); auto* changePtr = std::get_if<DisplayDevice::RefreshRateChange>(&modeChange); ASSERT_TRUE(changePtr); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, changePtr->activeMode); // The latest request should override the desired mode. EXPECT_EQ(Action::InitiateDisplayModeSwitch, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode60))); EXPECT_EQ(Action::None, mDisplay->setDesiredMode(DisplayModeRequest(kDesiredMode120))); ASSERT_TRUE(mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDisplay->getDesiredMode()); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDisplay->getPendingMode()); EXPECT_DISPLAY_MODE_REQUEST_OPT(kDesiredMode120, mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDisplay->getPendingMode()); // No pending mode change. EXPECT_TRUE( std::holds_alternative<DisplayDevice::NoModeChange>(mDisplay->finalizeModeChange())); mDisplay->clearDesiredMode(); desiredModeOpt = mDisplay->takeDesiredMode(); ASSERT_TRUE(desiredModeOpt); EXPECT_FALSE(mDisplay->getDesiredMode()); EXPECT_TRUE(mDisplay->initiateModeChange(std::move(*desiredModeOpt), constraints, timeline)); modeChange = mDisplay->finalizeModeChange(); changePtr = std::get_if<DisplayDevice::RefreshRateChange>(&modeChange); ASSERT_TRUE(changePtr); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, changePtr->activeMode); } } // namespace Loading