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

Commit 39be47b9 authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

SF: Fix pacesetter promotion for folded mirroring

The pacesetter display is demoted/promoted in response to a hotplug. On
foldables, the promoted display was hard-coded to the inner display, so
a hotplug while folded would incorrectly use that powered-off display as
the pacesetter, causing system-wide jank until the next fold/unfold.

Bug: 347248313
Flag: EXEMPT bugfix
Test: Connect and disconnect external display while folded.
Test: Fold and unfold while external display is connected.
Test: Pacesetter is still correct on folded/unfolded boot.
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3ff44c7e852f5614514a15dcec78ba7857e5d010)
Merged-In: Id5cb29c3cbaa8ed455a15d8be3a32e79a470cce5

Change-Id: Id0a32686c1271163e88a8c586482ee37d42a5bdf
parent b00cdc55
Loading
Loading
Loading
Loading
+11 −6
Original line number Original line Diff line number Diff line
@@ -123,19 +123,22 @@ void Scheduler::setPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetter
    promotePacesetterDisplay(pacesetterIdOpt);
    promotePacesetterDisplay(pacesetterIdOpt);
}
}


void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
                                PhysicalDisplayId activeDisplayId) {
    auto schedulePtr =
    auto schedulePtr =
            std::make_shared<VsyncSchedule>(selectorPtr->getActiveMode().modePtr, mFeatures,
            std::make_shared<VsyncSchedule>(selectorPtr->getActiveMode().modePtr, mFeatures,
                                            [this](PhysicalDisplayId id, bool enable) {
                                            [this](PhysicalDisplayId id, bool enable) {
                                                onHardwareVsyncRequest(id, enable);
                                                onHardwareVsyncRequest(id, enable);
                                            });
                                            });


    registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr));
    registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr),
                            activeDisplayId);
}
}


void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
                                        RefreshRateSelectorPtr selectorPtr,
                                        RefreshRateSelectorPtr selectorPtr,
                                        VsyncSchedulePtr schedulePtr) {
                                        VsyncSchedulePtr schedulePtr,
                                        PhysicalDisplayId activeDisplayId) {
    demotePacesetterDisplay();
    demotePacesetterDisplay();


    auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) {
    auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) {
@@ -145,7 +148,7 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
                                                       std::move(schedulePtr), mFeatures)
                                                       std::move(schedulePtr), mFeatures)
                                   .second;
                                   .second;


        return std::make_pair(promotePacesetterDisplayLocked(), isNew);
        return std::make_pair(promotePacesetterDisplayLocked(activeDisplayId), isNew);
    }();
    }();


    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
@@ -158,7 +161,9 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
    dispatchHotplug(displayId, Hotplug::Connected);
    dispatchHotplug(displayId, Hotplug::Connected);
}
}


void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, PhysicalDisplayId activeDisplayId) {
    LOG_ALWAYS_FATAL_IF(displayId == activeDisplayId, "Cannot unregister the active display!");

    dispatchHotplug(displayId, Hotplug::Disconnected);
    dispatchHotplug(displayId, Hotplug::Disconnected);


    demotePacesetterDisplay();
    demotePacesetterDisplay();
@@ -173,7 +178,7 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
        // headless virtual display.)
        // headless virtual display.)
        LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");
        LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");


        pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
        pacesetterVsyncSchedule = promotePacesetterDisplayLocked(activeDisplayId);
    }
    }
    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}
}
+12 −4
Original line number Original line Diff line number Diff line
@@ -101,9 +101,16 @@ public:
    using ConstVsyncSchedulePtr = std::shared_ptr<const VsyncSchedule>;
    using ConstVsyncSchedulePtr = std::shared_ptr<const VsyncSchedule>;
    using VsyncSchedulePtr = std::shared_ptr<VsyncSchedule>;
    using VsyncSchedulePtr = std::shared_ptr<VsyncSchedule>;


    void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr) REQUIRES(kMainThreadContext)
    // After registration/unregistration, `activeDisplayId` is promoted to pacesetter. Note that the
    // active display is never unregistered, since hotplug disconnect never happens for activatable
    // displays, i.e. a foldable's internal displays or otherwise the (internal or external) primary
    // display.
    // TODO: b/255635821 - Remove active display parameters.
    void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr,
                         PhysicalDisplayId activeDisplayId) REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock);
            EXCLUDES(mDisplayLock);
    void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
    void unregisterDisplay(PhysicalDisplayId, PhysicalDisplayId activeDisplayId)
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);


    void run();
    void run();


@@ -388,8 +395,9 @@ private:
    // the caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
    // 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 demotePacesetterDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);


    void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr)
    void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr,
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
                                 PhysicalDisplayId activeDisplayId) REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock);


    struct Policy;
    struct Policy;


+5 −3
Original line number Original line Diff line number Diff line
@@ -3717,7 +3717,8 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
        ftl::FakeGuard guard(kMainThreadContext);
        ftl::FakeGuard guard(kMainThreadContext);


        // For hotplug reconnect, renew the registration since display modes have been reloaded.
        // For hotplug reconnect, renew the registration since display modes have been reloaded.
        mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
        mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector(),
                                    mActiveDisplayId);
    }
    }


    if (display->isVirtual()) {
    if (display->isVirtual()) {
@@ -3756,7 +3757,7 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
        if (display->isVirtual()) {
        if (display->isVirtual()) {
            releaseVirtualDisplay(display->getVirtualId());
            releaseVirtualDisplay(display->getVirtualId());
        } else {
        } else {
            mScheduler->unregisterDisplay(display->getPhysicalId());
            mScheduler->unregisterDisplay(display->getPhysicalId(), mActiveDisplayId);
        }
        }
    }
    }


@@ -4376,7 +4377,8 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
                                             getFactory(), activeRefreshRate, *mTimeStats);
                                             getFactory(), activeRefreshRate, *mTimeStats);


    // The pacesetter must be registered before EventThread creation below.
    // The pacesetter must be registered before EventThread creation below.
    mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
    mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector(),
                                mActiveDisplayId);
    if (FlagManager::getInstance().vrr_config()) {
    if (FlagManager::getInstance().vrr_config()) {
        mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps);
        mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps);
    }
    }
+16 −9
Original line number Original line Diff line number Diff line
@@ -337,12 +337,15 @@ TEST_F(SchedulerTest, chooseDisplayModesSingleDisplayHighHintTouchSignal) {
}
}


TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
    constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1;
    mScheduler->registerDisplay(kDisplayId1,
    mScheduler->registerDisplay(kDisplayId1,
                                std::make_shared<RefreshRateSelector>(kDisplay1Modes,
                                std::make_shared<RefreshRateSelector>(kDisplay1Modes,
                                                                      kDisplay1Mode60->getId()));
                                                                      kDisplay1Mode60->getId()),
                                kActiveDisplayId);
    mScheduler->registerDisplay(kDisplayId2,
    mScheduler->registerDisplay(kDisplayId2,
                                std::make_shared<RefreshRateSelector>(kDisplay2Modes,
                                std::make_shared<RefreshRateSelector>(kDisplay2Modes,
                                                                      kDisplay2Mode60->getId()));
                                                                      kDisplay2Mode60->getId()),
                                kActiveDisplayId);


    using DisplayModeChoice = TestableScheduler::DisplayModeChoice;
    using DisplayModeChoice = TestableScheduler::DisplayModeChoice;
    TestableScheduler::DisplayModeChoiceMap expectedChoices;
    TestableScheduler::DisplayModeChoiceMap expectedChoices;
@@ -402,10 +405,10 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
    {
    {
        // The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120
        // The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120
        // Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz.
        // Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz.
        mScheduler
        mScheduler->registerDisplay(kDisplayId3,
                ->registerDisplay(kDisplayId3,
                                    std::make_shared<RefreshRateSelector>(kDisplay3Modes,
                                    std::make_shared<RefreshRateSelector>(kDisplay3Modes,
                                                                        kDisplay3Mode60->getId()));
                                                                          kDisplay3Mode60->getId()),
                                    kActiveDisplayId);


        const GlobalSignals globalSignals = {.touch = true};
        const GlobalSignals globalSignals = {.touch = true};
        mScheduler->replaceTouchTimer(10);
        mScheduler->replaceTouchTimer(10);
@@ -447,12 +450,15 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
}
}


TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) {
TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) {
    constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1;
    mScheduler->registerDisplay(kDisplayId1,
    mScheduler->registerDisplay(kDisplayId1,
                                std::make_shared<RefreshRateSelector>(kDisplay1Modes,
                                std::make_shared<RefreshRateSelector>(kDisplay1Modes,
                                                                      kDisplay1Mode60->getId()));
                                                                      kDisplay1Mode60->getId()),
                                kActiveDisplayId);
    mScheduler->registerDisplay(kDisplayId2,
    mScheduler->registerDisplay(kDisplayId2,
                                std::make_shared<RefreshRateSelector>(kDisplay2Modes,
                                std::make_shared<RefreshRateSelector>(kDisplay2Modes,
                                                                      kDisplay2Mode60->getId()));
                                                                      kDisplay2Mode60->getId()),
                                kActiveDisplayId);


    using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;
    using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;


@@ -574,7 +580,8 @@ TEST_F(SchedulerTest, nextFrameIntervalTest) {
                                mFlinger.getTimeStats(),
                                mFlinger.getTimeStats(),
                                mSchedulerCallback};
                                mSchedulerCallback};


    scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker);
    scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, std::nullopt,
                              vrrTracker);
    vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
    vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
    scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate);
    scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate);
    vrrTracker->addVsyncTimestamp(0);
    vrrTracker->addVsyncTimestamp(0);
+7 −9
Original line number Original line Diff line number Diff line
@@ -53,7 +53,7 @@ public:
                      factory, selectorPtr->getActiveMode().fps, timeStats) {
                      factory, selectorPtr->getActiveMode().fps, timeStats) {
        const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
        const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
        registerDisplay(displayId, std::move(selectorPtr), std::move(controller),
        registerDisplay(displayId, std::move(selectorPtr), std::move(controller),
                        std::move(tracker));
                        std::move(tracker), displayId);


        ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
        ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
            // Execute task to prevent broken promise exception on destruction.
            // Execute task to prevent broken promise exception on destruction.
@@ -85,14 +85,16 @@ public:


    void registerDisplay(
    void registerDisplay(
            PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
            PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
            std::optional<PhysicalDisplayId> activeDisplayIdOpt = {},
            std::shared_ptr<VSyncTracker> vsyncTracker = std::make_shared<mock::VSyncTracker>()) {
            std::shared_ptr<VSyncTracker> vsyncTracker = std::make_shared<mock::VSyncTracker>()) {
        registerDisplay(displayId, std::move(selectorPtr),
        registerDisplay(displayId, std::move(selectorPtr),
                        std::make_unique<mock::VsyncController>(), vsyncTracker);
                        std::make_unique<mock::VsyncController>(), vsyncTracker,
                        activeDisplayIdOpt.value_or(displayId));
    }
    }


    void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
    void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
                         std::unique_ptr<VsyncController> controller,
                         std::unique_ptr<VsyncController> controller,
                         std::shared_ptr<VSyncTracker> tracker) {
                         std::shared_ptr<VSyncTracker> tracker, PhysicalDisplayId activeDisplayId) {
        ftl::FakeGuard guard(kMainThreadContext);
        ftl::FakeGuard guard(kMainThreadContext);
        Scheduler::registerDisplayInternal(displayId, std::move(selectorPtr),
        Scheduler::registerDisplayInternal(displayId, std::move(selectorPtr),
                                           std::shared_ptr<VsyncSchedule>(
                                           std::shared_ptr<VsyncSchedule>(
@@ -101,16 +103,12 @@ public:
                                                                             mock::VSyncDispatch>(),
                                                                             mock::VSyncDispatch>(),
                                                                     std::move(controller),
                                                                     std::move(controller),
                                                                     mockRequestHardwareVsync
                                                                     mockRequestHardwareVsync
                                                                             .AsStdFunction())));
                                                                             .AsStdFunction())),
                                           activeDisplayId);
    }
    }


    testing::MockFunction<void(PhysicalDisplayId, bool)> mockRequestHardwareVsync;
    testing::MockFunction<void(PhysicalDisplayId, bool)> mockRequestHardwareVsync;


    void unregisterDisplay(PhysicalDisplayId displayId) {
        ftl::FakeGuard guard(kMainThreadContext);
        Scheduler::unregisterDisplay(displayId);
    }

    std::optional<PhysicalDisplayId> pacesetterDisplayId() const NO_THREAD_SAFETY_ANALYSIS {
    std::optional<PhysicalDisplayId> pacesetterDisplayId() const NO_THREAD_SAFETY_ANALYSIS {
        return mPacesetterDisplayId;
        return mPacesetterDisplayId;
    }
    }
Loading