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

Commit b7c5f08c authored by Steven Thomas's avatar Steven Thomas Committed by Android (Google) Code Review
Browse files

Merge changes from topic "rr-switch-flag" into qt-surfaceflinger-dev

* changes:
  DO NOT MERGE: Turn refresh rate switching on by default
  Add a flag for refresh rate switching
parents 9790e2cc e6255611
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -96,7 +96,6 @@ PhaseOffsets::PhaseOffsets() {
    highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
                           highFpsLateAppOffsetNs};

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

+126 −58
Original line number Diff line number Diff line
@@ -34,10 +34,9 @@ namespace scheduler {
 */
class RefreshRateConfigs {
public:
    // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest
    // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance
    // Enum to indicate which vsync rate to run at. 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.
    enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
    enum class RefreshRateType { DEFAULT, PERFORMANCE };

    struct RefreshRate {
        // This config ID corresponds to the position of the config in the vector that is stored
@@ -47,26 +46,57 @@ public:
        std::string name;
        // Refresh rate in frames per second, rounded to the nearest integer.
        uint32_t fps = 0;
        // config Id (returned from HWC2::Display::Config::getId())
        hwc2_config_t id;
        // Vsync period in nanoseconds.
        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
    // baking them in.
    const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() const {
        return mRefreshRates;
    const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const {
        LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported);
        return mRefreshRateMap;
    }
    std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) const {
        const auto& refreshRate = mRefreshRates.find(type);
        if (refreshRate != mRefreshRates.end()) {

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

    RefreshRateType getRefreshRateType(hwc2_config_t id) const {
        for (const auto& [type, refreshRate] : mRefreshRates) {
            if (refreshRate->id == id) {
    std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const {
        int currentConfig = mCurrentConfig;
        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;
            }
        }
@@ -74,64 +104,102 @@ public:
        return RefreshRateType::DEFAULT;
    }

    void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
        mRefreshRates.clear();
    void setCurrentConfig(int config) {
        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.
        mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
                              std::make_shared<RefreshRate>(
                                      RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0,
                                                  HWC2_SCREEN_OFF_CONFIG_ID}));
    RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
                       int currentConfig) {
        init(refreshRateSwitching, configs, currentConfig);
    }

        if (configs.size() < 1) {
            ALOGE("Device does not have valid configs. Config size is 0.");
            return;
    RefreshRateConfigs(bool refreshRateSwitching,
                       const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
                       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
        // from the configs.
        std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod;
private:
    void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
              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) {
            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(),
                  [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) {
                      return a.second > b.second;
            std::vector<const RefreshRate*> sortedRefreshRates;
            for (const auto& refreshRate : mRefreshRates) {
                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.
        nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
        if (vsyncPeriod != 0) {
            const float fps = 1e9 / vsyncPeriod;
            const int configId = configIdToVsyncPeriod[0].first;
            mRefreshRates.emplace(RefreshRateType::DEFAULT,
                                  std::make_shared<RefreshRate>(
                                          RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
                                                      static_cast<uint32_t>(fps),
                                                      configs.at(configId)->getId()}));
            // When the configs are ordered by the resync rate, we assume that
            // the first one is DEFAULT and the second one is PERFORMANCE,
            // i.e. the higher rate.
            if (sortedRefreshRates[0]->vsyncPeriod == 0 ||
                sortedRefreshRates[1]->vsyncPeriod == 0) {
                return {};
            }

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

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

        // When the configs are ordered by the resync rate. We assume that the second one is
        // PERFORMANCE, eg. the higher rate.
        vsyncPeriod = configIdToVsyncPeriod[1].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()}));
        }
        mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first];
        mRefreshRateMap[RefreshRateType::PERFORMANCE] =
                mRefreshRates[defaultAndPerfConfigs->second];
    }

private:
    std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
    // Whether this device is doing refresh rate switching or not. This must not change after this
    // 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
+31 −40
Original line number Diff line number Diff line
@@ -41,21 +41,18 @@ class RefreshRateStats {
    static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;

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

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

    // Sets power mode.
    void setPowerMode(int mode) {
        if (mCurrentPowerMode == mode) {
            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();
        mCurrentPowerMode = mode;
    }
@@ -79,16 +76,15 @@ public:
        flushTime();

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

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

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
    // this method was called.
    void flushTimeForMode(int mode) {
    void flushTime() {
        nsecs_t currentTime = systemTime();
        nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
        int64_t timeElapsedMs = ns2ms(timeElapsed);
        mPreviousRecordedTime = currentTime;

        mConfigModesTotalTime[mode] += timeElapsedMs;
        for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
            if (!config) {
                continue;
            }
            if (config->configId == mode) {
                mTimeStats.recordRefreshRate(config->fps, timeElapsed);
        uint32_t fps = 0;
        if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
            // Normal power mode is counted under different config modes.
            if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) {
                mConfigModesTotalTime[mCurrentConfigMode] = 0;
            }
            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.
@@ -149,10 +139,11 @@ private:
    // Aggregate refresh rate statistics for telemetry.
    TimeStats& mTimeStats;

    int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID;
    int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
    int mCurrentConfigMode;
    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();
};
+45 −63
Original line number Diff line number Diff line
@@ -133,7 +133,6 @@ Scheduler::~Scheduler() {

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

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

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

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

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

ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
    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) {
void Scheduler::resync() {
    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);

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

    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::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::PERFORMANCE;

    const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
    const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;

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

@@ -398,17 +390,6 @@ void Scheduler::setChangeRefreshRateCallback(
    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) {
    ATRACE_INT("FrameSkipCount", skipCount);
    if (mSkipCount != skipCount) {
@@ -460,14 +441,12 @@ void Scheduler::resetTimerCallback() {

void Scheduler::resetKernelTimerCallback() {
    ATRACE_INT("ExpiredKernelIdleTimer", 0);
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
    const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
    // 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
    // same.
        if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
            resyncToHardwareVsync(true, mGetVsyncPeriod());
        }
    if (refreshRate.first == Scheduler::RefreshRateType::PERFORMANCE) {
        resyncToHardwareVsync(true, refreshRate.second.vsyncPeriod);
    }
}

@@ -499,15 +478,14 @@ void Scheduler::expiredDisplayPowerTimerCallback() {
void Scheduler::expiredKernelTimerCallback() {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    ATRACE_INT("ExpiredKernelIdleTimer", 1);
    if (mGetCurrentRefreshRateTypeCallback) {
        if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
    if (mRefreshRateConfigs.getCurrentRefreshRate().first !=
        Scheduler::RefreshRateType::PERFORMANCE) {
        // 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
        // mode then we'll need to re-update the DispSync model anyways.
        disableHardwareVsync(false);
    }
}
}

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

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

    // HDR content is not supported on PERFORMANCE mode
    if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
        return RefreshRateType::DEFAULT;
@@ -567,11 +549,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
    }

    // Content detection is on, find the appropriate refresh rate with minimal error
    auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
                            mRefreshRateConfigs.getRefreshRates().cend(),
    auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(),
                            mRefreshRateConfigs.getRefreshRateMap().cend(),
                            [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
                                return std::abs(l.second->fps - static_cast<float>(rate)) <
                                        std::abs(r.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));
                            });
    RefreshRateType currRefreshRateType = iter->first;

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

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

File changed.

Preview size limit exceeded, changes collapsed.

Loading