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

Commit 7fb29b99 authored by Steven Thomas's avatar Steven Thomas
Browse files

Add a flag for refresh rate switching

Some devices don't do refresh rate switching, so we should take that
into account when filtering display manager config settings and deciding
scheduling behavior.

This CL adds a sysprop that can be set to indicate if surface flinger
should do refresh rate switching, and modifies surface flinger to have
the correct behavior when we're not doing refresh rate switching.

Bug: 147233255
Bug: 136592946
Bug: 138261472

Test: Ran through various 60/90 switching scenarios on a device with
refresh rate switching.

Test: Set the refresh rate switching sysprop to false, and confirmed we
get a consistent 60Hz.

Test: Inspected dumpsys output and confirmed it looks correct. In
particular, refresh rate stats are output correctly.

Test: Ran automated tests: RefreshRateConfigsTest, RefreshRateStatsTest,
SchedulerTest.

Change-Id: I54cd5be9d2c1b9abc8475c3ce39846cbe9f9fe53
Merged-In: I54cd5be9d2c1b9abc8475c3ce39846cbe9f9fe53
parent ca342596
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -96,7 +96,6 @@ PhaseOffsets::PhaseOffsets() {
    highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
    highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
                           highFpsLateAppOffsetNs};
                           highFpsLateAppOffsetNs};


    mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
    mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
    mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
    mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
    mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});


+126 −58
Original line number Original line Diff line number Diff line
@@ -34,10 +34,9 @@ namespace scheduler {
 */
 */
class RefreshRateConfigs {
class RefreshRateConfigs {
public:
public:
    // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest
    // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance
    // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance
    // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
    // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
    enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
    enum class RefreshRateType { DEFAULT, PERFORMANCE };


    struct RefreshRate {
    struct RefreshRate {
        // This config ID corresponds to the position of the config in the vector that is stored
        // This config ID corresponds to the position of the config in the vector that is stored
@@ -47,26 +46,57 @@ public:
        std::string name;
        std::string name;
        // Refresh rate in frames per second, rounded to the nearest integer.
        // Refresh rate in frames per second, rounded to the nearest integer.
        uint32_t fps = 0;
        uint32_t fps = 0;
        // config Id (returned from HWC2::Display::Config::getId())
        // Vsync period in nanoseconds.
        hwc2_config_t id;
        nsecs_t vsyncPeriod;
        // Hwc config Id (returned from HWC2::Display::Config::getId())
        hwc2_config_t hwcId;
    };
    };


    // Returns true if this device is doing refresh rate switching. This won't change at runtime.
    bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; }

    // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access
    // from multiple threads. This can only be called if refreshRateSwitching() returns true.
    // TODO(b/122916473): Get this information from configs prepared by vendors, instead of
    // TODO(b/122916473): Get this information from configs prepared by vendors, instead of
    // baking them in.
    // baking them in.
    const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() const {
    const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const {
        return mRefreshRates;
        LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported);
        return mRefreshRateMap;
    }
    }
    std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) const {

        const auto& refreshRate = mRefreshRates.find(type);
    const RefreshRate& getRefreshRateFromType(RefreshRateType type) const {
        if (refreshRate != mRefreshRates.end()) {
        if (!mRefreshRateSwitchingSupported) {
            return getCurrentRefreshRate().second;
        } else {
            auto refreshRate = mRefreshRateMap.find(type);
            LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end());
            return refreshRate->second;
            return refreshRate->second;
        }
        }
        return nullptr;
    }
    }


    RefreshRateType getRefreshRateType(hwc2_config_t id) const {
    std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const {
        for (const auto& [type, refreshRate] : mRefreshRates) {
        int currentConfig = mCurrentConfig;
            if (refreshRate->id == id) {
        if (mRefreshRateSwitchingSupported) {
            for (const auto& [type, refresh] : mRefreshRateMap) {
                if (refresh.configId == currentConfig) {
                    return {type, refresh};
                }
            }
            LOG_ALWAYS_FATAL();
        }
        return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]};
    }

    const RefreshRate& getRefreshRateFromConfigId(int configId) const {
        LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size());
        return mRefreshRates[configId];
    }

    RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const {
        if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT;

        for (const auto& [type, refreshRate] : mRefreshRateMap) {
            if (refreshRate.hwcId == hwcId) {
                return type;
                return type;
            }
            }
        }
        }
@@ -74,64 +104,102 @@ public:
        return RefreshRateType::DEFAULT;
        return RefreshRateType::DEFAULT;
    }
    }


    void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
    void setCurrentConfig(int config) {
        mRefreshRates.clear();
        LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size());
        mCurrentConfig = config;
    }

    struct InputConfig {
        hwc2_config_t hwcId = 0;
        nsecs_t vsyncPeriod = 0;
    };


        // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
    RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
        mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
                       int currentConfig) {
                              std::make_shared<RefreshRate>(
        init(refreshRateSwitching, configs, currentConfig);
                                      RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0,
    }
                                                  HWC2_SCREEN_OFF_CONFIG_ID}));


        if (configs.size() < 1) {
    RefreshRateConfigs(bool refreshRateSwitching,
            ALOGE("Device does not have valid configs. Config size is 0.");
                       const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
            return;
                       int currentConfig) {
        std::vector<InputConfig> inputConfigs;
        for (const auto& config : configs) {
            inputConfigs.push_back({config->getId(), config->getVsyncPeriod()});
        }
        init(refreshRateSwitching, inputConfigs, currentConfig);
    }
    }


        // Create a map between config index and vsync period. This is all the info we need
private:
        // from the configs.
    void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
        std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod;
              int currentConfig) {
        mRefreshRateSwitchingSupported = refreshRateSwitching;
        LOG_ALWAYS_FATAL_IF(configs.empty());
        LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size());
        mCurrentConfig = currentConfig;

        auto buildRefreshRate = [&](int configId) -> RefreshRate {
            const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod;
            const float fps = 1e9 / vsyncPeriod;
            return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps),
                    vsyncPeriod, configs[configId].hwcId};
        };

        for (int i = 0; i < configs.size(); ++i) {
        for (int i = 0; i < configs.size(); ++i) {
            configIdToVsyncPeriod.emplace_back(i, configs.at(i)->getVsyncPeriod());
            mRefreshRates.push_back(buildRefreshRate(i));
        }

        if (!mRefreshRateSwitchingSupported) return;

        auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> {
            if (configs.size() < 2) {
                return {};
            }
            }


        std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(),
            std::vector<const RefreshRate*> sortedRefreshRates;
                  [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) {
            for (const auto& refreshRate : mRefreshRates) {
                      return a.second > b.second;
                sortedRefreshRates.push_back(&refreshRate);
            }
            std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(),
                      [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) {
                          return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
                      });
                      });


        // When the configs are ordered by the resync rate. We assume that the first one is DEFAULT.
            // When the configs are ordered by the resync rate, we assume that
        nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
            // the first one is DEFAULT and the second one is PERFORMANCE,
        if (vsyncPeriod != 0) {
            // i.e. the higher rate.
            const float fps = 1e9 / vsyncPeriod;
            if (sortedRefreshRates[0]->vsyncPeriod == 0 ||
            const int configId = configIdToVsyncPeriod[0].first;
                sortedRefreshRates[1]->vsyncPeriod == 0) {
            mRefreshRates.emplace(RefreshRateType::DEFAULT,
                return {};
                                  std::make_shared<RefreshRate>(
                                          RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
                                                      static_cast<uint32_t>(fps),
                                                      configs.at(configId)->getId()}));
            }
            }


        if (configs.size() < 2) {
            return std::pair<int, int>(sortedRefreshRates[0]->configId,
                                       sortedRefreshRates[1]->configId);
        };

        auto defaultAndPerfConfigs = findDefaultAndPerfConfigs();
        if (!defaultAndPerfConfigs) {
            mRefreshRateSwitchingSupported = false;
            return;
            return;
        }
        }


        // When the configs are ordered by the resync rate. We assume that the second one is
        mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first];
        // PERFORMANCE, eg. the higher rate.
        mRefreshRateMap[RefreshRateType::PERFORMANCE] =
        vsyncPeriod = configIdToVsyncPeriod[1].second;
                mRefreshRates[defaultAndPerfConfigs->second];
        if (vsyncPeriod != 0) {
            const float fps = 1e9 / vsyncPeriod;
            const int configId = configIdToVsyncPeriod[1].first;
            mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
                                  std::make_shared<RefreshRate>(
                                          RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
                                                      static_cast<uint32_t>(fps),
                                                      configs.at(configId)->getId()}));
        }
    }
    }


private:
    // Whether this device is doing refresh rate switching or not. This must not change after this
    std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
    // object is initialized.
    bool mRefreshRateSwitchingSupported;
    // The list of refresh rates, indexed by display config ID. This must not change after this
    // object is initialized.
    std::vector<RefreshRate> mRefreshRates;
    // The mapping of refresh rate type to RefreshRate. This must not change after this object is
    // initialized.
    std::map<RefreshRateType, RefreshRate> mRefreshRateMap;
    // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on
    // the main thread, and read by the Scheduler (and other objects) on other threads, so it's
    // atomic.
    std::atomic<int> mCurrentConfig;
};
};


} // namespace scheduler
} // namespace scheduler
+31 −40
Original line number Original line Diff line number Diff line
@@ -41,21 +41,18 @@ class RefreshRateStats {
    static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
    static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;


public:
public:
    RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats)
    RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats,
          : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {}
                     int currentConfigMode, int currentPowerMode)

          : mRefreshRateConfigs(refreshRateConfigs),
    // Sets power mode. We only collect the information when the power mode is not
            mTimeStats(timeStats),
    // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
            mCurrentConfigMode(currentConfigMode),
    // on config mode.
            mCurrentPowerMode(currentPowerMode) {}

    // Sets power mode.
    void setPowerMode(int mode) {
    void setPowerMode(int mode) {
        if (mCurrentPowerMode == mode) {
        if (mCurrentPowerMode == mode) {
            return;
            return;
        }
        }
        // If power mode is normal, the time is going to be recorded under config modes.
        if (mode == HWC_POWER_MODE_NORMAL) {
            mCurrentPowerMode = mode;
            return;
        }
        flushTime();
        flushTime();
        mCurrentPowerMode = mode;
        mCurrentPowerMode = mode;
    }
    }
@@ -79,16 +76,15 @@ public:
        flushTime();
        flushTime();


        std::unordered_map<std::string, int64_t> totalTime;
        std::unordered_map<std::string, int64_t> totalTime;
        for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
        // Multiple configs may map to the same name, e.g. "60fps". Add the
            int64_t totalTimeForConfig = 0;
        // times for such configs together.
            if (!config) {
        for (const auto& [config, time] : mConfigModesTotalTime) {
                continue;
            totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0;
            }
            if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) {
                totalTimeForConfig = mConfigModesTotalTime.at(config->configId);
        }
        }
            totalTime[config->name] = totalTimeForConfig;
        for (const auto& [config, time] : mConfigModesTotalTime) {
            totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time;
        }
        }
        totalTime["ScreenOff"] = mScreenOffTime;
        return totalTime;
        return totalTime;
    }
    }


@@ -104,32 +100,26 @@ public:
    }
    }


private:
private:
    void flushTime() {
        // Normal power mode is counted under different config modes.
        if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
            flushTimeForMode(mCurrentConfigMode);
        } else {
            flushTimeForMode(SCREEN_OFF_CONFIG_ID);
        }
    }

    // Calculates the time that passed in ms between the last time we recorded time and the time
    // Calculates the time that passed in ms between the last time we recorded time and the time
    // this method was called.
    // this method was called.
    void flushTimeForMode(int mode) {
    void flushTime() {
        nsecs_t currentTime = systemTime();
        nsecs_t currentTime = systemTime();
        nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
        nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
        int64_t timeElapsedMs = ns2ms(timeElapsed);
        int64_t timeElapsedMs = ns2ms(timeElapsed);
        mPreviousRecordedTime = currentTime;
        mPreviousRecordedTime = currentTime;


        mConfigModesTotalTime[mode] += timeElapsedMs;
        uint32_t fps = 0;
        for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
        if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
            if (!config) {
            // Normal power mode is counted under different config modes.
                continue;
            if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) {
            }
                mConfigModesTotalTime[mCurrentConfigMode] = 0;
            if (config->configId == mode) {
                mTimeStats.recordRefreshRate(config->fps, timeElapsed);
            }
            }
            mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs;
            fps = mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps;
        } else {
            mScreenOffTime += timeElapsedMs;
        }
        }
        mTimeStats.recordRefreshRate(fps, timeElapsed);
    }
    }


    // Formats the time in milliseconds into easy to read format.
    // Formats the time in milliseconds into easy to read format.
@@ -149,10 +139,11 @@ private:
    // Aggregate refresh rate statistics for telemetry.
    // Aggregate refresh rate statistics for telemetry.
    TimeStats& mTimeStats;
    TimeStats& mTimeStats;


    int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID;
    int mCurrentConfigMode;
    int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
    int32_t mCurrentPowerMode;


    std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
    std::unordered_map<int /* config */, int64_t /* duration in ms */> mConfigModesTotalTime;
    int64_t mScreenOffTime = 0;


    nsecs_t mPreviousRecordedTime = systemTime();
    nsecs_t mPreviousRecordedTime = systemTime();
};
};
+42 −65
Original line number Original line Diff line number Diff line
@@ -133,7 +133,6 @@ Scheduler::~Scheduler() {


sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
        const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
        const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
        ResyncCallback resyncCallback,
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
    const int64_t id = sNextId++;
    const int64_t id = sNextId++;
    ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
    ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
@@ -143,8 +142,7 @@ sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
                            offsetThresholdForNextVsync, std::move(interceptCallback));
                            offsetThresholdForNextVsync, std::move(interceptCallback));


    auto eventThreadConnection =
    auto eventThreadConnection =
            createConnectionInternal(eventThread.get(), std::move(resyncCallback),
            createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
                                     ISurfaceComposer::eConfigChangedSuppress);
    mConnections.emplace(id,
    mConnections.emplace(id,
                         std::make_unique<Connection>(new ConnectionHandle(id),
                         std::make_unique<Connection>(new ConnectionHandle(id),
                                                      eventThreadConnection,
                                                      eventThreadConnection,
@@ -164,17 +162,15 @@ std::unique_ptr<EventThread> Scheduler::makeEventThread(
}
}


sp<EventThreadConnection> Scheduler::createConnectionInternal(
sp<EventThreadConnection> Scheduler::createConnectionInternal(
        EventThread* eventThread, ResyncCallback&& resyncCallback,
        EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
        ISurfaceComposer::ConfigChanged configChanged) {
    return eventThread->createEventConnection([&] { resync(); }, configChanged);
    return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
}
}


sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
        const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
        const sp<Scheduler::ConnectionHandle>& handle,
        ISurfaceComposer::ConfigChanged configChanged) {
        ISurfaceComposer::ConfigChanged configChanged) {
    RETURN_VALUE_IF_INVALID(nullptr);
    RETURN_VALUE_IF_INVALID(nullptr);
    return createConnectionInternal(mConnections[handle->id]->thread.get(),
    return createConnectionInternal(mConnections[handle->id]->thread.get(), configChanged);
                                    std::move(resyncCallback), configChanged);
}
}


EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -264,23 +260,15 @@ void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
    setVsyncPeriod(period);
    setVsyncPeriod(period);
}
}


ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
void Scheduler::resync() {
    std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
    return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
        if (const auto vsync = ptr.lock()) {
            vsync->resync(getVsyncPeriod);
        }
    };
}

void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
    static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
    static constexpr nsecs_t kIgnoreDelay = ms2ns(750);


    const nsecs_t now = systemTime();
    const nsecs_t now = systemTime();
    const nsecs_t last = lastResyncTime.exchange(now);
    const nsecs_t last = mLastResyncTime.exchange(now);


    if (now - last > kIgnoreDelay) {
    if (now - last > kIgnoreDelay) {
        scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
        resyncToHardwareVsync(false,
                              mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod);
    }
    }
}
}


@@ -338,15 +326,19 @@ void Scheduler::dumpPrimaryDispSync(std::string& result) const {


std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
        std::string const& name, int windowType) {
        std::string const& name, int windowType) {
    RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
    uint32_t defaultFps, performanceFps;
    if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
        defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
        performanceFps =
                mRefreshRateConfigs
                        .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
                                                        ? RefreshRateType::DEFAULT
                                                        ? RefreshRateType::DEFAULT
            : RefreshRateType::PERFORMANCE;
                                                        : RefreshRateType::PERFORMANCE)

                        .fps;
    const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
    } else {
    const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
        defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;

        performanceFps = defaultFps;
    const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
    }
    const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
    return mLayerHistory.createLayer(name, defaultFps, performanceFps);
    return mLayerHistory.createLayer(name, defaultFps, performanceFps);
}
}


@@ -398,17 +390,6 @@ void Scheduler::setChangeRefreshRateCallback(
    mChangeRefreshRateCallback = changeRefreshRateCallback;
    mChangeRefreshRateCallback = changeRefreshRateCallback;
}
}


void Scheduler::setGetCurrentRefreshRateTypeCallback(
        const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
}

void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mGetVsyncPeriod = getVsyncPeriod;
}

void Scheduler::updateFrameSkipping(const int64_t skipCount) {
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
    ATRACE_INT("FrameSkipCount", skipCount);
    ATRACE_INT("FrameSkipCount", skipCount);
    if (mSkipCount != skipCount) {
    if (mSkipCount != skipCount) {
@@ -460,14 +441,12 @@ void Scheduler::resetTimerCallback() {


void Scheduler::resetKernelTimerCallback() {
void Scheduler::resetKernelTimerCallback() {
    ATRACE_INT("ExpiredKernelIdleTimer", 0);
    ATRACE_INT("ExpiredKernelIdleTimer", 0);
    std::lock_guard<std::mutex> lock(mCallbackLock);
    const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
    if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
    if (refreshRate.first == RefreshRateType::PERFORMANCE) {
        // If we're not in performance mode then the kernel timer shouldn't do
        // If we're not in performance mode then the kernel timer shouldn't do
        // anything, as the refresh rate during DPU power collapse will be the
        // anything, as the refresh rate during DPU power collapse will be the
        // same.
        // same.
        if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
        resyncToHardwareVsync(true, refreshRate.second.vsyncPeriod);
            resyncToHardwareVsync(true, mGetVsyncPeriod());
        }
    }
    }
}
}


@@ -497,17 +476,15 @@ void Scheduler::expiredDisplayPowerTimerCallback() {
}
}


void Scheduler::expiredKernelTimerCallback() {
void Scheduler::expiredKernelTimerCallback() {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    ATRACE_INT("ExpiredKernelIdleTimer", 1);
    ATRACE_INT("ExpiredKernelIdleTimer", 1);
    if (mGetCurrentRefreshRateTypeCallback) {
    const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
        if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
    if (refreshRate.first != RefreshRateType::PERFORMANCE) {
        // Disable HW Vsync if the timer expired, as we don't need it
        // Disable HW Vsync if the timer expired, as we don't need it
        // enabled if we're not pushing frames, and if we're in PERFORMANCE
        // enabled if we're not pushing frames, and if we're in PERFORMANCE
        // mode then we'll need to re-update the DispSync model anyways.
        // mode then we'll need to re-update the DispSync model anyways.
        disableHardwareVsync(false);
        disableHardwareVsync(false);
    }
    }
}
}
}


std::string Scheduler::doDump() {
std::string Scheduler::doDump() {
    std::ostringstream stream;
    std::ostringstream stream;
@@ -540,6 +517,10 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO
}
}


Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
    if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
        return RefreshRateType::DEFAULT;
    }

    // HDR content is not supported on PERFORMANCE mode
    // HDR content is not supported on PERFORMANCE mode
    if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
    if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
        return RefreshRateType::DEFAULT;
        return RefreshRateType::DEFAULT;
@@ -567,16 +548,12 @@ 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
    auto begin = mRefreshRateConfigs.getRefreshRates().cbegin();
    auto begin = mRefreshRateConfigs.getRefreshRateMap().cbegin();


    // Skip POWER_SAVING config as it is not a real config
    auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRateMap().cend(),
    if (begin->first == RefreshRateType::POWER_SAVING) {
        ++begin;
    }
    auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(),
                            [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
                            [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
                                return std::abs(l.second->fps - static_cast<float>(rate)) <
                                return std::abs(l.second.fps - static_cast<float>(rate)) <
                                        std::abs(r.second->fps - static_cast<float>(rate));
                                        std::abs(r.second.fps - static_cast<float>(rate));
                            });
                            });
    RefreshRateType currRefreshRateType = iter->first;
    RefreshRateType currRefreshRateType = iter->first;


@@ -584,11 +561,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
    // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
    // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
    // align well with both
    // align well with both
    constexpr float MARGIN = 0.05f;
    constexpr float MARGIN = 0.05f;
    float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
    float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps /
            float(mContentRefreshRate);
            float(mContentRefreshRate);
    if (std::abs(std::round(ratio) - ratio) > MARGIN) {
    if (std::abs(std::round(ratio) - ratio) > MARGIN) {
        while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
        while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) {
            ratio = iter->second->fps / float(mContentRefreshRate);
            ratio = iter->second.fps / float(mContentRefreshRate);


            if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
            if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
                currRefreshRateType = iter->first;
                currRefreshRateType = iter->first;
+6 −24

File changed.

Preview size limit exceeded, changes collapsed.

Loading