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

Commit d916d941 authored by Daniel Solomon's avatar Daniel Solomon
Browse files

SurfaceFlinger: Query Scheduler when updating allowed display configs

Currently two entities in SurfaceFlinger can set a new display refresh
rate: (1) SurfaceFlinger core, and (2) Scheduler. It's possible for
these two entities to get out of sync in the following way:
1) Scheduler updates the refresh rate to some rate
2) Upper layers call into SurfaceFlinger to update allowed display
configs
3) SurfaceFlinger always sets display rate to max

If the refresh rate from #1 and #3 don't match, it can leave the system
in an inconsistent state, potentially causing visual and power issues.

This change fixes this problem by changing step #3: Instead of always
choosing the max refresh rate, SurfaceFlinger queries the optimal
refresh rate from Scheduler. If that rate isn't available, only then
does SurfaceFlinger default to the maximum rate.

Bug: 139557239
Test: atest libsurfaceflinger_unittest
Test: Manual:
    1) Start with SurfaceFlinger idling (Scheduler selected
    RefreshRateType::DEFAULT)
    2) Trigger a change in allowed display configs from
    DisplayModeDirector
    3) Make sure the RefreshRateType SurfaceFlinger sets is DEFAULT
    instead of PERFORMANCE
Change-Id: Ia85a60fde55afaed5106462942e0bb77652ec737
Merged-In: Ia85a60fde55afaed5106462942e0bb77652ec737
parent c14f2309
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -567,6 +567,7 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
    }
    }


    // Content detection is on, find the appropriate refresh rate with minimal error
    // Content detection is on, find the appropriate refresh rate with minimal error
    // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs)
    auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
    auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
                            mRefreshRateConfigs.getRefreshRates().cend(),
                            mRefreshRateConfigs.getRefreshRates().cend(),
                            [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
                            [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
@@ -596,6 +597,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
    return currRefreshRateType;
    return currRefreshRateType;
}
}


Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() {
    std::lock_guard<std::mutex> lock(mFeatureStateLock);
    return mRefreshRateType;
}

void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mChangeRefreshRateCallback) {
    if (mChangeRefreshRateCallback) {
+3 −0
Original line number Original line Diff line number Diff line
@@ -189,6 +189,9 @@ public:
    // calls DispSync::dump() on primary disp sync
    // calls DispSync::dump() on primary disp sync
    void dumpPrimaryDispSync(std::string& result) const;
    void dumpPrimaryDispSync(std::string& result) const;


    // Get the appropriate refresh type for current conditions.
    RefreshRateType getPreferredRefreshRateType();

protected:
protected:
    virtual std::unique_ptr<EventThread> makeEventThread(
    virtual std::unique_ptr<EventThread> makeEventThread(
            const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
            const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+20 −10
Original line number Original line Diff line number Diff line
@@ -6169,6 +6169,25 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& disp
    }
    }
}
}


void SurfaceFlinger::setPreferredDisplayConfig() {
    const auto& type = mScheduler->getPreferredRefreshRateType();
    const auto& config = mRefreshRateConfigs.getRefreshRate(type);
    if (config && isDisplayConfigAllowed(config->configId)) {
        ALOGV("switching to Scheduler preferred config %d", config->configId);
        setDesiredActiveConfig({type, config->configId, Scheduler::ConfigEvent::Changed});
    } else {
        // Set the highest allowed config by iterating backwards on available refresh rates
        const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
        for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
            if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
                ALOGV("switching to allowed config %d", iter->second->configId);
                setDesiredActiveConfig({iter->first, iter->second->configId,
                        Scheduler::ConfigEvent::Changed});
            }
        }
    }
}

void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
                                                      const std::vector<int32_t>& allowedConfigs) {
                                                      const std::vector<int32_t>& allowedConfigs) {
    if (!display->isPrimary()) {
    if (!display->isPrimary()) {
@@ -6190,16 +6209,7 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& d
    mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
    mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
                                display->getActiveConfig());
                                display->getActiveConfig());


    // Set the highest allowed config by iterating backwards on available refresh rates
    setPreferredDisplayConfig();
    const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
    for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
        if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
            ALOGV("switching to config %d", iter->second->configId);
            setDesiredActiveConfig(
                    {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed});
            break;
        }
    }
}
}


status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+3 −0
Original line number Original line Diff line number Diff line
@@ -534,6 +534,9 @@ private:
    // called on the main thread in response to setPowerMode()
    // called on the main thread in response to setPowerMode()
    void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
    void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);


    // Query the Scheduler or allowed display configs list for a matching config, and set it
    void setPreferredDisplayConfig() REQUIRES(mStateLock);

    // called on the main thread in response to setAllowedDisplayConfigs()
    // called on the main thread in response to setAllowedDisplayConfigs()
    void setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
    void setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
                                          const std::vector<int32_t>& allowedConfigs)
                                          const std::vector<int32_t>& allowedConfigs)