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

Commit 76742845 authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

SF: Fix display mode transitions for multi-display

SF does not yet support concurrent modeset on multiple displays, as the
scheduler/modeset/VSYNC state machines are tied to the internal display
that is powered on, a.k.a. the active display.

When SF detects a change in the DM policy for a display, it initiates a
transition to the new display mode, which includes syncing to its VSYNC.
However, the per-display calls to setDesiredDisplayModeSpecs that start
this process occur after the setPowerMode calls to turn off/on the old/
new active display, respectively. Before this CL, a change in policy on
the now inactive (powered-off) display triggered a partial display mode
transition (that would start resync but abort before HWC modeset), such
that SF wound up internally inconsistent and out of sync with HWC.

Fix this by deferring the applyRefreshRateConfigsPolicy of the inactive
display until it becomes active. Later, in onActiveDisplayChangedLocked,
the Scheduler::Policy is cleared by Scheduler::setRefreshRateConfigs, so
ensure that Scheduler::getPreferredDisplayMode subsequently initializes
Scheduler::Policy::mode to the chosen mode for the newly active display.
Otherwise, applyRefreshRateConfigsPolicy falls back to its default mode.

Bug: 260092798
Test: No intermittent jank on outer/inner displays after fold/unfold.
Test: DisplayModeSwitchingTest.multiDisplay
Change-Id: Iebe1a6bb4749630333ef954955ac33807c95dd9f
Merged-In: Iebe1a6bb4749630333ef954955ac33807c95dd9f
parent ba9d2022
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -511,7 +511,7 @@ void DisplayDevice::animateRefreshRateOverlay() {
    }
    }
}
}


bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) {
bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info, bool force) {
    ATRACE_CALL();
    ATRACE_CALL();


    LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided");
    LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided");
@@ -529,7 +529,7 @@ bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) {
    }
    }


    // Check if we are already at the desired mode
    // Check if we are already at the desired mode
    if (getActiveMode()->getId() == info.mode->getId()) {
    if (!force && getActiveMode()->getId() == info.mode->getId()) {
        return false;
        return false;
    }
    }


+1 −1
Original line number Original line Diff line number Diff line
@@ -204,7 +204,7 @@ public:
        }
        }
    };
    };


    bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
    bool setDesiredActiveMode(const ActiveModeInfo&, bool force = false) EXCLUDES(mActiveModeLock);
    std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
    std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
    void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
    void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
    ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) {
    ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) {
+1 −3
Original line number Original line Diff line number Diff line
@@ -727,9 +727,7 @@ auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals>
DisplayModePtr Scheduler::getPreferredDisplayMode() {
DisplayModePtr Scheduler::getPreferredDisplayMode() {
    std::lock_guard<std::mutex> lock(mPolicyLock);
    std::lock_guard<std::mutex> lock(mPolicyLock);
    // Make sure the stored mode is up to date.
    // Make sure the stored mode is up to date.
    if (mPolicy.mode) {
    mPolicy.mode = chooseDisplayMode().first;
    mPolicy.mode = chooseDisplayMode().first;
    }
    return mPolicy.mode;
    return mPolicy.mode;
}
}


+28 −6
Original line number Original line Diff line number Diff line
@@ -1070,7 +1070,7 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* st
    return NO_ERROR;
    return NO_ERROR;
}
}


void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) {
void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info, bool force) {
    ATRACE_CALL();
    ATRACE_CALL();


    if (!info.mode) {
    if (!info.mode) {
@@ -1083,7 +1083,7 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) {
        return;
        return;
    }
    }


    if (display->setDesiredActiveMode(info)) {
    if (display->setDesiredActiveMode(info, force)) {
        scheduleComposite(FrameHint::kNone);
        scheduleComposite(FrameHint::kNone);


        // Start receiving vsync samples now, so that we can detect a period
        // Start receiving vsync samples now, so that we can detect a period
@@ -3372,8 +3372,14 @@ void SurfaceFlinger::requestDisplayMode(DisplayModePtr mode, DisplayModeEvent ev
    }
    }
    ATRACE_CALL();
    ATRACE_CALL();


    if (display->isInternal() && !isDisplayActiveLocked(display)) {
        ALOGV("%s(%s): Inactive display", __func__, to_string(display->getId()).c_str());
        return;
    }

    if (!display->refreshRateConfigs().isModeAllowed(mode->getId())) {
    if (!display->refreshRateConfigs().isModeAllowed(mode->getId())) {
        ALOGV("Skipping disallowed mode %d", mode->getId().value());
        ALOGV("%s(%s): Disallowed mode %d", __func__, to_string(display->getId()).c_str(),
              mode->getId().value());
        return;
        return;
    }
    }


@@ -6942,10 +6948,17 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
        return NO_ERROR;
        return NO_ERROR;
    }
    }


    if (display->isInternal() && !isDisplayActiveLocked(display)) {
        // The policy will be be applied when the display becomes active.
        ALOGV("%s(%s): Inactive display", __func__, to_string(display->getId()).c_str());
        return NO_ERROR;
    }

    return applyRefreshRateConfigsPolicy(display);
    return applyRefreshRateConfigsPolicy(display);
}
}


status_t SurfaceFlinger::applyRefreshRateConfigsPolicy(const sp<DisplayDevice>& display) {
status_t SurfaceFlinger::applyRefreshRateConfigsPolicy(const sp<DisplayDevice>& display,
                                                       bool force) {
    const scheduler::RefreshRateConfigs::Policy currentPolicy =
    const scheduler::RefreshRateConfigs::Policy currentPolicy =
            display->refreshRateConfigs().getCurrentPolicy();
            display->refreshRateConfigs().getCurrentPolicy();
    ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
    ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
@@ -6975,7 +6988,7 @@ status_t SurfaceFlinger::applyRefreshRateConfigsPolicy(const sp<DisplayDevice>&
    if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) {
    if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) {
        ALOGV("switching to Scheduler preferred display mode %d",
        ALOGV("switching to Scheduler preferred display mode %d",
              preferredDisplayMode->getId().value());
              preferredDisplayMode->getId().value());
        setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed});
        setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed}, force);
    } else {
    } else {
        LOG_ALWAYS_FATAL("Desired display mode not allowed: %d",
        LOG_ALWAYS_FATAL("Desired display mode not allowed: %d",
                         preferredDisplayMode->getId().value());
                         preferredDisplayMode->getId().value());
@@ -7304,14 +7317,23 @@ void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeD
void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) {
void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) {
    ATRACE_CALL();
    ATRACE_CALL();


    // During boot, SF powers on the primary display, which is the first display to be active. In
    // that case, there is no need to force setDesiredActiveMode, because DM is about to send its
    // policy via setDesiredDisplayModeSpecs.
    bool forceApplyPolicy = false;

    if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
    if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
        display->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
        display->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
        forceApplyPolicy = true;
    }
    }


    if (!activeDisplay) {
    if (!activeDisplay) {
        ALOGE("%s: activeDisplay is null", __func__);
        ALOGE("%s: activeDisplay is null", __func__);
        return;
        return;
    }
    }

    ALOGI("Active display is %s", to_string(activeDisplay->getPhysicalId()).c_str());

    mActiveDisplayToken = activeDisplay->getDisplayToken();
    mActiveDisplayToken = activeDisplay->getDisplayToken();
    activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
    activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
    updateInternalDisplayVsyncLocked(activeDisplay);
    updateInternalDisplayVsyncLocked(activeDisplay);
@@ -7324,7 +7346,7 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activ
    // case, its preferred mode has not been propagated to HWC (via setDesiredActiveMode). In either
    // case, its preferred mode has not been propagated to HWC (via setDesiredActiveMode). In either
    // case, the Scheduler's cachedModeChangedParams must be initialized to the newly active mode,
    // case, the Scheduler's cachedModeChangedParams must be initialized to the newly active mode,
    // and the kernel idle timer of the newly active display must be toggled.
    // and the kernel idle timer of the newly active display must be toggled.
    applyRefreshRateConfigsPolicy(activeDisplay);
    applyRefreshRateConfigsPolicy(activeDisplay, forceApplyPolicy);
}
}


status_t SurfaceFlinger::addWindowInfosListener(
status_t SurfaceFlinger::addWindowInfosListener(
+3 −2
Original line number Original line Diff line number Diff line
@@ -712,7 +712,7 @@ private:
    // Called on the main thread in response to initializeDisplays()
    // Called on the main thread in response to initializeDisplays()
    void onInitializeDisplays() REQUIRES(mStateLock);
    void onInitializeDisplays() REQUIRES(mStateLock);
    // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
    // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
    void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock);
    void setDesiredActiveMode(const ActiveModeInfo& info, bool force = false) REQUIRES(mStateLock);
    status_t setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int id);
    status_t setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int id);
    // Sets the active mode and a new refresh rate in SF.
    // Sets the active mode and a new refresh rate in SF.
    void updateInternalStateWithChangedMode() REQUIRES(mStateLock);
    void updateInternalStateWithChangedMode() REQUIRES(mStateLock);
@@ -735,7 +735,8 @@ private:
            const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
            const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
            EXCLUDES(mStateLock);
            EXCLUDES(mStateLock);


    status_t applyRefreshRateConfigsPolicy(const sp<DisplayDevice>&) REQUIRES(mStateLock);
    status_t applyRefreshRateConfigsPolicy(const sp<DisplayDevice>&, bool force = false)
            REQUIRES(mStateLock);


    void commitTransactions() EXCLUDES(mStateLock);
    void commitTransactions() EXCLUDES(mStateLock);
    void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
    void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
Loading