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

Commit b74fe1dc authored by Ady Abraham's avatar Ady Abraham Committed by Android (Google) Code Review
Browse files

Merge changes from topic "sf_157096772" into rvc-dev

* changes:
  SurfaceFlinger: clear LayerHistory on first touch
  Revert "SurfaceFlinger: more aggressive infrequent layer detection"
  Revert "SurfaceFlinger: tune MAX_FREQUENT_LAYER_PERIOD_NS for inactive layers"
  Revert "SurfaceFlinger: tune infrequent detection logic more"
parents 0b257105 a6b676e3
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
@@ -62,13 +62,17 @@ void trace(const wp<Layer>& weak, LayerHistory::LayerVoteType type, int fps) {
    const auto layer = weak.promote();
    if (!layer) return;

    const auto& name = layer->getName();
    const auto noVoteTag = "LFPS NoVote " + name;
    const auto heuristicVoteTag = "LFPS Heuristic " + name;
    const auto explicitDefaultVoteTag = "LFPS ExplicitDefault" + name;
    const auto explicitExactOrMultipleVoteTag = "LFPS ExplicitExactOrMultiple" + name;
    const auto minVoteTag = "LFPS Min " + name;
    const auto maxVoteTag = "LFPS Max " + name;
    const auto makeTag = [layer](LayerHistory::LayerVoteType vote) {
        return "LFPS " + RefreshRateConfigs::layerVoteTypeString(vote) + " " + layer->getName();
    };

    const auto noVoteTag = makeTag(LayerHistory::LayerVoteType::NoVote);
    const auto heuristicVoteTag = makeTag(LayerHistory::LayerVoteType::Heuristic);
    const auto explicitDefaultVoteTag = makeTag(LayerHistory::LayerVoteType::ExplicitDefault);
    const auto explicitExactOrMultipleVoteTag =
            makeTag(LayerHistory::LayerVoteType::ExplicitExactOrMultiple);
    const auto minVoteTag = makeTag(LayerHistory::LayerVoteType::Min);
    const auto maxVoteTag = makeTag(LayerHistory::LayerVoteType::Max);

    ATRACE_INT(noVoteTag.c_str(), type == LayerHistory::LayerVoteType::NoVote ? 1 : 0);
    ATRACE_INT(heuristicVoteTag.c_str(), type == LayerHistory::LayerVoteType::Heuristic ? fps : 0);
@@ -79,7 +83,7 @@ void trace(const wp<Layer>& weak, LayerHistory::LayerVoteType type, int fps) {
    ATRACE_INT(minVoteTag.c_str(), type == LayerHistory::LayerVoteType::Min ? 1 : 0);
    ATRACE_INT(maxVoteTag.c_str(), type == LayerHistory::LayerVoteType::Max ? 1 : 0);

    ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
    ALOGD("%s: %s @ %d Hz", __FUNCTION__, layer->getName().c_str(), fps);
}
} // namespace

+38 −20
Original line number Diff line number Diff line
@@ -50,28 +50,42 @@ void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now,
    }
}

bool LayerInfoV2::isFrequent(nsecs_t now) {
    mLastReportedIsFrequent = [&] {
        for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) {
            if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) {
                ALOGV("%s infrequent (last frame is %.2fms ago)", mName.c_str(),
                      (now - mFrameTimes.back().queueTime) / 1e6f);
                return false;
bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const {
    return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>(
                                          mFrameTimeValidSince.time_since_epoch())
                                          .count();
}

bool LayerInfoV2::isFrequent(nsecs_t now) const {
    // Find the first valid frame time
    auto it = mFrameTimes.begin();
    for (; it != mFrameTimes.end(); ++it) {
        if (isFrameTimeValid(*it)) {
            break;
        }
    }

            const auto numFrames = std::distance(mFrameTimes.crbegin(), it + 1);
            if (numFrames >= FREQUENT_LAYER_WINDOW_SIZE) {
                ALOGV("%s frequent (burst of %zu frames)", mName.c_str(), numFrames);
    // If we know nothing about this layer we consider it as frequent as it might be the start
    // of an animation.
    if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) {
        return true;
    }

    // Find the first active frame
    for (; it != mFrameTimes.end(); ++it) {
        if (it->queueTime >= getActiveLayerThreshold(now)) {
            break;
        }
    }

        ALOGV("%s %sfrequent (not enough frames %zu)", mName.c_str(),
              mLastReportedIsFrequent ? "" : "in", mFrameTimes.size());
        return mLastReportedIsFrequent;
    }();
    const auto numFrames = std::distance(it, mFrameTimes.end());
    if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) {
        return false;
    }

    return mLastReportedIsFrequent;
    // Layer is considered frequent if the average frame rate is higher than the threshold
    const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
    return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
}

bool LayerInfoV2::hasEnoughDataForHeuristic() const {
@@ -80,6 +94,10 @@ bool LayerInfoV2::hasEnoughDataForHeuristic() const {
        return false;
    }

    if (!isFrameTimeValid(mFrameTimes.front())) {
        return false;
    }

    if (mFrameTimes.size() < HISTORY_SIZE &&
        mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
        return false;
@@ -190,7 +208,7 @@ std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_
        return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
    }

    ALOGV("%s Max (can't resolve refresh rate", mName.c_str());
    ALOGV("%s Max (can't resolve refresh rate)", mName.c_str());
    return {LayerHistory::LayerVoteType::Max, 0};
}

+12 −10
Original line number Diff line number Diff line
@@ -47,7 +47,9 @@ class LayerInfoV2 {
    // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
    // favor of a low refresh rate.
    static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
    static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 150ms;
    static constexpr float MIN_FPS_FOR_FREQUENT_LAYER = 10.0f;
    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS =
            std::chrono::nanoseconds(static_cast<nsecs_t>(1e9f / MIN_FPS_FOR_FREQUENT_LAYER)) + 1ms;

    friend class LayerHistoryTestV2;

@@ -82,7 +84,11 @@ public:
    nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }

    void clearHistory() {
        mFrameTimes.clear();
        // Mark mFrameTimeValidSince to now to ignore all previous frame times.
        // We are not deleting the old frame to keep track of whether we should treat the first
        // buffer as Max as we don't know anything about this layer or Min as this layer is
        // posting infrequent updates.
        mFrameTimeValidSince = std::chrono::steady_clock::now();
        mLastReportedRefreshRate = 0.0f;
    }

@@ -94,11 +100,12 @@ private:
        bool pendingConfigChange;
    };

    bool isFrequent(nsecs_t now);
    bool isFrequent(nsecs_t now) const;
    bool hasEnoughDataForHeuristic() const;
    std::optional<float> calculateRefreshRateIfPossible();
    std::pair<nsecs_t, bool> calculateAverageFrameTime() const;
    bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const;
    bool isFrameTimeValid(const FrameTimeData&) const;

    const std::string mName;

@@ -110,13 +117,6 @@ private:

    float mLastReportedRefreshRate = 0.0f;

    // Used to determine whether a layer should be considered frequent or
    // not when we don't have enough frames. This member will not be cleared
    // as part of clearHistory() to remember whether this layer was frequent
    // or not before we processed touch boost (or anything else that would
    // clear layer history).
    bool mLastReportedIsFrequent = true;

    // Holds information about the layer vote
    struct {
        LayerHistory::LayerVoteType type;
@@ -124,6 +124,8 @@ private:
    } mLayerVote;

    std::deque<FrameTimeData> mFrameTimes;
    std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince =
            std::chrono::steady_clock::now();
    static constexpr size_t HISTORY_SIZE = 90;
    static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
};
+24 −5
Original line number Diff line number Diff line
@@ -31,6 +31,23 @@ namespace android::scheduler {
using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
using RefreshRate = RefreshRateConfigs::RefreshRate;

std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
    switch (vote) {
        case LayerVoteType::NoVote:
            return "NoVote";
        case LayerVoteType::Min:
            return "Min";
        case LayerVoteType::Max:
            return "Max";
        case LayerVoteType::Heuristic:
            return "Heuristic";
        case LayerVoteType::ExplicitDefault:
            return "ExplicitDefault";
        case LayerVoteType::ExplicitExactOrMultiple:
            return "ExplicitExactOrMultiple";
    }
}

const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
        const std::vector<LayerRequirement>& layers) const {
    std::lock_guard lock(mLock);
@@ -146,6 +163,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
    const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;

    if (!touchActive && idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
        ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
        return getMinRefreshRateByPolicyLocked();
    }

@@ -168,7 +186,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
    }

    for (const auto& layer : layers) {
        ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote);
        ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
              layerVoteTypeString(layer.vote).c_str(), layer.weight);
        if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
            continue;
        }
@@ -254,10 +273,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
                    return 1.0f / iter;
                }();
                ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
                      layer.vote == LayerVoteType::ExplicitExactOrMultiple
                              ? "ExplicitExactOrMultiple"
                              : "Heuristic",
                      weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore);
                      layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod,
                      scores[i].first->name.c_str(), layerScore);
                scores[i].second += weight * layerScore;
                continue;
            }
@@ -276,6 +293,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
        // range instead of picking a random score from the app range.
        if (std::all_of(scores.begin(), scores.end(),
                        [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
            ALOGV("layers not scored - choose %s",
                  getMaxRefreshRateByPolicyLocked().getName().c_str());
            return getMaxRefreshRateByPolicyLocked();
        } else {
            return *bestRefreshRate;
+3 −0
Original line number Diff line number Diff line
@@ -255,6 +255,9 @@ public:
    // Stores the current configId the device operates at
    void setCurrentConfigId(HwcConfigIndexType configId) EXCLUDES(mLock);

    // Returns a string that represents the layer vote type
    static std::string layerVoteTypeString(LayerVoteType vote);

    RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
                       HwcConfigIndexType currentConfigId);

Loading