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

Commit b1b9d41c authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: define a known frame rates list

Keep a list of known frame rates that would be used when we calculated
heuristically the frame rate of a layer. This keeps the signal to the
algorithm that chooses the refresh rate steady and avoid strange
frame rates like 57.2 due to inconsistent presentation timestamps.

Bug: 157540021
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest
Change-Id: I97a24b74605256646e9b8444bd9f3818fe0a4a2a
parent 607a0c6d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ private:

class LayerHistoryV2 : public android::scheduler::LayerHistory {
public:
    LayerHistoryV2();
    LayerHistoryV2(const scheduler::RefreshRateConfigs&);
    virtual ~LayerHistoryV2();

    // Layers are unregistered when the weak reference expires.
+5 −2
Original line number Diff line number Diff line
@@ -87,8 +87,11 @@ void trace(const wp<Layer>& weak, LayerHistory::LayerVoteType type, int fps) {
}
} // namespace

LayerHistoryV2::LayerHistoryV2()
      : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {}
LayerHistoryV2::LayerHistoryV2(const scheduler::RefreshRateConfigs& refreshRateConfigs)
      : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {
    LayerInfoV2::setRefreshRateConfigs(refreshRateConfigs);
}

LayerHistoryV2::~LayerHistoryV2() = default;

void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
+11 −6
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@

namespace android::scheduler {

const RefreshRateConfigs* LayerInfoV2::sRefreshRateConfigs = nullptr;

LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
                         LayerHistory::LayerVoteType defaultVote)
      : mName(name),
@@ -168,7 +170,6 @@ bool LayerInfoV2::isRefreshRateStable(nsecs_t averageFrameTime, bool missingPres

std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
    static constexpr float MARGIN = 1.0f; // 1Hz

    if (!hasEnoughDataForHeuristic()) {
        ALOGV("Not enough data");
        return std::nullopt;
@@ -177,7 +178,7 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
    const auto [averageFrameTime, missingPresentTime] = calculateAverageFrameTime();

    // If there are no presentation timestamps provided we can't calculate the refresh rate
    if (missingPresentTime && mLastReportedRefreshRate == 0) {
    if (missingPresentTime && mLastRefreshRate.reported == 0) {
        return std::nullopt;
    }

@@ -186,12 +187,16 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
    }

    const auto refreshRate = 1e9f / averageFrameTime;
    if (std::abs(refreshRate - mLastReportedRefreshRate) > MARGIN) {
        mLastReportedRefreshRate = refreshRate;
    const auto knownRefreshRate = sRefreshRateConfigs->findClosestKnownFrameRate(refreshRate);
    if (std::abs(mLastRefreshRate.calculated - refreshRate) > MARGIN &&
        mLastRefreshRate.reported != knownRefreshRate) {
        mLastRefreshRate.calculated = refreshRate;
        mLastRefreshRate.reported = knownRefreshRate;
    }

    ALOGV("Refresh rate: %.2f", mLastReportedRefreshRate);
    return mLastReportedRefreshRate;
    ALOGV("%s %.2fHz rounded to nearest known frame rate %.2fHz", mName.c_str(), refreshRate,
          mLastRefreshRate.reported);
    return mLastRefreshRate.reported;
}

std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
+15 −2
Original line number Diff line number Diff line
@@ -56,6 +56,10 @@ class LayerInfoV2 {
    friend class LayerHistoryTestV2;

public:
    static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) {
        sRefreshRateConfigs = &refreshRateConfigs;
    }

    LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
                LayerHistory::LayerVoteType defaultVote);

@@ -93,7 +97,7 @@ public:
        // posting infrequent updates.
        const auto timePoint = std::chrono::nanoseconds(now);
        mFrameTimeValidSince = std::chrono::time_point<std::chrono::steady_clock>(timePoint);
        mLastReportedRefreshRate = 0.0f;
        mLastRefreshRate = {};
    }

    void clearHistory(nsecs_t now) {
@@ -127,7 +131,13 @@ private:

    nsecs_t mLastAnimationTime = 0;

    float mLastReportedRefreshRate = 0.0f;
    // Holds information about the calculated and reported refresh rate
    struct RefreshRateHeuristicData {
        float calculated = 0.0f; // Rate calculated on the layer
        float reported = 0.0f;   // Last reported rate for LayerInfoV2::getRefreshRate()
    };

    RefreshRateHeuristicData mLastRefreshRate;

    // Holds information about the layer vote
    struct {
@@ -140,6 +150,9 @@ private:
            std::chrono::steady_clock::now();
    static constexpr size_t HISTORY_SIZE = 90;
    static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;

    // Shared for all LayerInfo instances
    static const RefreshRateConfigs* sRefreshRateConfigs;
};

} // namespace scheduler
+39 −2
Original line number Diff line number Diff line
@@ -242,7 +242,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(

            if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
                layer.vote == LayerVoteType::Heuristic) {
                const auto layerScore = [&]() {
                const auto layerScore = [&] {
                    // Calculate how many display vsyncs we need to present a single frame for this
                    // layer
                    const auto [displayFramesQuot, displayFramesRem] =
@@ -384,7 +384,8 @@ void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {

RefreshRateConfigs::RefreshRateConfigs(
        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
        HwcConfigIndexType currentConfigId) {
        HwcConfigIndexType currentConfigId)
      : mKnownFrameRates(constructKnownFrameRates(configs)) {
    LOG_ALWAYS_FATAL_IF(configs.empty());
    LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());

@@ -544,4 +545,40 @@ void RefreshRateConfigs::constructAvailableRefreshRates() {
                       &mAppRequestRefreshRates);
}

std::vector<float> RefreshRateConfigs::constructKnownFrameRates(
        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
    std::vector<float> knownFrameRates = {24.0f, 30.0f, 45.0f, 60.0f, 72.0f};
    knownFrameRates.reserve(knownFrameRates.size() + configs.size());

    // Add all supported refresh rates to the set
    for (const auto& config : configs) {
        const auto refreshRate = 1e9f / config->getVsyncPeriod();
        knownFrameRates.emplace_back(refreshRate);
    }

    // Sort and remove duplicates
    const auto frameRatesEqual = [](float a, float b) { return std::abs(a - b) <= 0.01f; };
    std::sort(knownFrameRates.begin(), knownFrameRates.end());
    knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
                                      frameRatesEqual),
                          knownFrameRates.end());
    return knownFrameRates;
}

float RefreshRateConfigs::findClosestKnownFrameRate(float frameRate) const {
    if (frameRate <= *mKnownFrameRates.begin()) {
        return *mKnownFrameRates.begin();
    }

    if (frameRate >= *std::prev(mKnownFrameRates.end())) {
        return *std::prev(mKnownFrameRates.end());
    }

    auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate);

    const auto distance1 = std::abs(frameRate - *lowerBound);
    const auto distance2 = std::abs(frameRate - *std::prev(lowerBound));
    return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
}

} // namespace android::scheduler
Loading