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

Commit 53852a5c authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: set refresh rate type when after an attempt to switch

When a refresh rate change is starting we change the offsets to the
new refresh rate to have a better alignment between buffers and the actual
vsync. This change guarantees that we set the correct offset by updating
PhaseOffset after desired config changed.

Test: Let device go to 60Hz due to idle; Open an app; Get systrace; repeat
Bug: 133241520
Change-Id: Id25f5e7d3d280813a106fd311906767d79e4e6ee
parent 2eeb9c63
Loading
Loading
Loading
Loading
+17 −24
Original line number Diff line number Diff line
@@ -935,12 +935,9 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
        // Start receiving vsync samples now, so that we can detect a period
        // switch.
        mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
        // We should only move to early offsets when we know that the refresh
        // rate will change. Otherwise, we may be stuck in early offsets
        // forever, as onRefreshRateChangeDetected will not be called.
        if (mDesiredActiveConfig.event == Scheduler::ConfigEvent::Changed) {
        // As we called to set period, we will call to onRefreshRateChangeCompleted once
        // DispSync model is locked.
        mVsyncModulator.onRefreshRateChangeInitiated();
        }
        mPhaseOffsets->setRefreshRateType(info.type);
        const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
        mVsyncModulator.setPhaseOffsets(early, gl, late);
@@ -975,7 +972,6 @@ void SurfaceFlinger::setActiveConfigInternal() {

    display->setActiveConfig(mUpcomingActiveConfig.configId);

    mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
    mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
    const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
    mVsyncModulator.setPhaseOffsets(early, gl, late);
@@ -987,6 +983,18 @@ void SurfaceFlinger::setActiveConfigInternal() {
    }
}

void SurfaceFlinger::desiredActiveConfigChangeDone() {
    std::lock_guard<std::mutex> lock(mActiveConfigLock);
    mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
    mDesiredActiveConfigChanged = false;
    ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);

    mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
    mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
    const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
    mVsyncModulator.setPhaseOffsets(early, gl, late);
}

bool SurfaceFlinger::performSetActiveConfig() {
    ATRACE_CALL();
    if (mCheckPendingFence) {
@@ -1016,14 +1024,7 @@ bool SurfaceFlinger::performSetActiveConfig() {
    if (!display || display->getActiveConfig() == desiredActiveConfig.configId) {
        // display is not valid or we are already in the requested mode
        // on both cases there is nothing left to do
        std::lock_guard<std::mutex> lock(mActiveConfigLock);
        mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
        mDesiredActiveConfigChanged = false;
        // Update scheduler with the correct vsync period as a no-op.
        // Otherwise, there exists a race condition where we get stuck in the
        // incorrect vsync period.
        mScheduler->resyncToHardwareVsync(false, getVsyncPeriod());
        ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
        desiredActiveConfigChangeDone();
        return false;
    }

@@ -1031,15 +1032,7 @@ bool SurfaceFlinger::performSetActiveConfig() {
    // allowed configs might have change by the time we process the refresh.
    // Make sure the desired config is still allowed
    if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) {
        std::lock_guard<std::mutex> lock(mActiveConfigLock);
        mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
        mDesiredActiveConfig.configId = display->getActiveConfig();
        mDesiredActiveConfigChanged = false;
        // Update scheduler with the current vsync period as a no-op.
        // Otherwise, there exists a race condition where we get stuck in the
        // incorrect vsync period.
        mScheduler->resyncToHardwareVsync(false, getVsyncPeriod());
        ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
        desiredActiveConfigChangeDone();
        return false;
    }
    mUpcomingActiveConfig = desiredActiveConfig;
+3 −1
Original line number Diff line number Diff line
@@ -508,13 +508,15 @@ private:
    // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
    void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
    // Once HWC has returned the present fence, this sets the active config and a new refresh
    // rate in SF. It also triggers HWC vsync.
    // rate in SF.
    void setActiveConfigInternal() REQUIRES(mStateLock);
    // Active config is updated on INVALIDATE call in a state machine-like manner. When the
    // desired config was set, HWC needs to update the panel on the next refresh, and when
    // we receive the fence back, we know that the process was complete. It returns whether
    // we need to wait for the next invalidate
    bool performSetActiveConfig() REQUIRES(mStateLock);
    // Called when active config is no longer is progress
    void desiredActiveConfigChangeDone() REQUIRES(mStateLock);
    // called on the main thread in response to setPowerMode()
    void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);