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

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

SurfaceFlinger: clear LayerHistory on first touch

 - Restructure the code in RefreshRateConfigs to be able to clear
   LayerHistory frames on the first touch event. Without this change we
   clear the history on every frame as long as the touch timer hasn't
   expired.
 - Add log prints for debugging

Test: Play 24fps video in YouTube PIP mode and rotate the device - no jank
Test: Chrome playing video - no refresh rate switching
Test: Hide/Show keyboard when inputting text
Test: Running Hay Day and observing refresh rate
Bug: 157096772
Change-Id: I7cabecd6ea27ec335e773aa22bb111fa8ec89195
parent dfb63ba7
Loading
Loading
Loading
Loading
+13 −9
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

@@ -90,7 +94,7 @@ LayerHistoryV2::~LayerHistoryV2() = default;
void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
                                   LayerVoteType type) {
    const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate);
    auto info = std::make_unique<LayerInfoV2>(highRefreshRatePeriod, type);
    auto info = std::make_unique<LayerInfoV2>(layer->getName(), highRefreshRatePeriod, type);
    std::lock_guard lock(mLock);
    mLayerInfos.emplace_back(layer, std::move(info));
}
+8 −2
Original line number Diff line number Diff line
@@ -27,8 +27,10 @@

namespace android::scheduler {

LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote)
      : mHighRefreshRatePeriod(highRefreshRatePeriod),
LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
                         LayerHistory::LayerVoteType defaultVote)
      : mName(name),
        mHighRefreshRatePeriod(highRefreshRatePeriod),
        mDefaultVote(defaultVote),
        mLayerVote({defaultVote, 0.0f}) {}

@@ -191,18 +193,22 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {

std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
    if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
        ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type));
        return {mLayerVote.type, mLayerVote.fps};
    }

    if (!isFrequent(now)) {
        ALOGV("%s is infrequent", mName.c_str());
        return {LayerHistory::LayerVoteType::Min, 0};
    }

    auto refreshRate = calculateRefreshRateIfPossible();
    if (refreshRate.has_value()) {
        ALOGV("%s calculated refresh rate: %.2f", mName.c_str(), refreshRate.value());
        return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
    }

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

+4 −1
Original line number Diff line number Diff line
@@ -54,7 +54,8 @@ class LayerInfoV2 {
    friend class LayerHistoryTestV2;

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

    LayerInfoV2(const LayerInfo&) = delete;
    LayerInfoV2& operator=(const LayerInfoV2&) = delete;
@@ -106,6 +107,8 @@ private:
    bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const;
    bool isFrameTimeValid(const FrameTimeData&) const;

    const std::string mName;

    // Used for sanitizing the heuristic data
    const nsecs_t mHighRefreshRatePeriod;
    LayerHistory::LayerVoteType mDefaultVote;
+31 −7
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);
@@ -103,7 +120,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
    ATRACE_CALL();
    ALOGV("getRefreshRateForContent %zu layers", layers.size());

    *touchConsidered = false;
    if (touchConsidered) *touchConsidered = false;
    std::lock_guard lock(mLock);

    int noVoteLayers = 0;
@@ -134,7 +151,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
    // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
    // selected a refresh rate to see if we should apply touch boost.
    if (touchActive && !hasExplicitVoteLayers) {
        *touchConsidered = true;
        ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
        if (touchConsidered) *touchConsidered = true;
        return getMaxRefreshRateByPolicyLocked();
    }

@@ -145,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();
    }

@@ -154,6 +173,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(

    // Only if all layers want Min we should return Min
    if (noVoteLayers + minVoteLayers == layers.size()) {
        ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
        return getMinRefreshRateByPolicyLocked();
    }

@@ -166,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;
        }
@@ -251,9 +272,9 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(

                    return 1.0f / iter;
                }();
                ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f",
                      layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(),
                      layerScore);
                ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
                      layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod,
                      scores[i].first->name.c_str(), layerScore);
                scores[i].second += weight * layerScore;
                continue;
            }
@@ -272,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;
@@ -286,7 +309,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(

    if (touchActive && explicitDefaultVoteLayers == 0 &&
        bestRefreshRate->fps < touchRefreshRate.fps) {
        *touchConsidered = true;
        if (touchConsidered) *touchConsidered = true;
        ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
        return touchRefreshRate;
    }

+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