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

Commit b87afa51 authored by Ady Abraham's avatar Ady Abraham Committed by Automerger Merge Worker
Browse files

Merge "SurfaceFlinger: more aggressive infrequent layer detection" into...

Merge "SurfaceFlinger: more aggressive infrequent layer detection" into rvc-dev am: 51a1625a am: 7053d901

Change-Id: I15a6a38f7063ba4332ff615896576efa486b4182
parents 6a6afa8f 7053d901
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -90,7 +90,7 @@ LayerHistoryV2::~LayerHistoryV2() = default;
void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
                                   LayerVoteType type) {
                                   LayerVoteType type) {
    const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate);
    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);
    std::lock_guard lock(mLock);
    mLayerInfos.emplace_back(layer, std::move(info));
    mLayerInfos.emplace_back(layer, std::move(info));
}
}
+19 −36
Original line number Original line Diff line number Diff line
@@ -27,8 +27,10 @@


namespace android::scheduler {
namespace android::scheduler {


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


@@ -45,54 +47,31 @@ void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
    }
    }
}
}


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 {
bool LayerInfoV2::isFrequent(nsecs_t now) const {
    // Find the first valid frame time
    for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) {
    auto it = mFrameTimes.begin();
        if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) {
    for (; it != mFrameTimes.end(); ++it) {
            ALOGV("%s infrequent (last frame is %.2fms ago", mName.c_str(),
        if (isFrameTimeValid(*it)) {
                  (now - mFrameTimes.back().queueTime) / 1e6f);
            break;
            return false;
        }
        }
        }


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

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


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


    // 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 {
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
    // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
    // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
    if (mFrameTimes.size() < 2) {
    if (mFrameTimes.size() < 2) {
        return false;
        return false;
    }
    }


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

    if (mFrameTimes.size() < HISTORY_SIZE &&
    if (mFrameTimes.size() < HISTORY_SIZE &&
        mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
        mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
        return false;
        return false;
@@ -167,18 +146,22 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {


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


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


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


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


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


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


    LayerInfoV2(const LayerInfo&) = delete;
    LayerInfoV2(const LayerInfo&) = delete;
    LayerInfoV2& operator=(const LayerInfoV2&) = delete;
    LayerInfoV2& operator=(const LayerInfoV2&) = delete;
@@ -83,11 +84,7 @@ public:
    nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
    nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }


    void clearHistory() {
    void clearHistory() {
        // Mark mFrameTimeValidSince to now to ignore all previous frame times.
        mFrameTimes.clear();
        // 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;
        mLastReportedRefreshRate = 0.0f;
    }
    }


@@ -101,7 +98,8 @@ private:
    bool isFrequent(nsecs_t now) const;
    bool isFrequent(nsecs_t now) const;
    bool hasEnoughDataForHeuristic() const;
    bool hasEnoughDataForHeuristic() const;
    std::optional<float> calculateRefreshRateIfPossible();
    std::optional<float> calculateRefreshRateIfPossible();
    bool isFrameTimeValid(const FrameTimeData&) const;

    const std::string mName;


    // Used for sanitizing the heuristic data
    // Used for sanitizing the heuristic data
    const nsecs_t mHighRefreshRatePeriod;
    const nsecs_t mHighRefreshRatePeriod;
@@ -118,8 +116,6 @@ private:
    } mLayerVote;
    } mLayerVote;


    std::deque<FrameTimeData> mFrameTimes;
    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 size_t HISTORY_SIZE = 90;
    static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
    static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
};
};
+11 −6
Original line number Original line Diff line number Diff line
@@ -103,7 +103,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
    ATRACE_CALL();
    ATRACE_CALL();
    ALOGV("getRefreshRateForContent %zu layers", layers.size());
    ALOGV("getRefreshRateForContent %zu layers", layers.size());


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


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


@@ -145,6 +146,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(


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


@@ -243,9 +245,11 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(


                    return 1.0f / iter;
                    return 1.0f / iter;
                }();
                }();
                ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f",
                ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
                      layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(),
                      layer.vote == LayerVoteType::ExplicitExactOrMultiple
                      layerScore);
                              ? "ExplicitExactOrMultiple"
                              : "Heuristic",
                      weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore);
                scores[i].second += weight * layerScore;
                scores[i].second += weight * layerScore;
                continue;
                continue;
            }
            }
@@ -266,7 +270,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
    const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
    const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
    if (touchActive && explicitDefaultVoteLayers == 0 &&
    if (touchActive && explicitDefaultVoteLayers == 0 &&
        bestRefreshRate->fps < touchRefreshRate.fps) {
        bestRefreshRate->fps < touchRefreshRate.fps) {
        *touchConsidered = true;
        if (touchConsidered) *touchConsidered = true;
        ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
        return touchRefreshRate;
        return touchRefreshRate;
    }
    }


+14 −18
Original line number Original line Diff line number Diff line
@@ -526,7 +526,9 @@ void Scheduler::idleTimerCallback(TimerState state) {


void Scheduler::touchTimerCallback(TimerState state) {
void Scheduler::touchTimerCallback(TimerState state) {
    const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
    const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
    handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
    if (handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */)) {
        mLayerHistory->clear();
    }
    ATRACE_INT("TouchState", static_cast<int>(touch));
    ATRACE_INT("TouchState", static_cast<int>(touch));
}
}


@@ -549,18 +551,19 @@ void Scheduler::dump(std::string& result) const {
}
}


template <class T>
template <class T>
void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
bool Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
    ConfigEvent event = ConfigEvent::None;
    ConfigEvent event = ConfigEvent::None;
    HwcConfigIndexType newConfigId;
    HwcConfigIndexType newConfigId;
    bool touchConsidered = false;
    {
    {
        std::lock_guard<std::mutex> lock(mFeatureStateLock);
        std::lock_guard<std::mutex> lock(mFeatureStateLock);
        if (*currentState == newState) {
        if (*currentState == newState) {
            return;
            return touchConsidered;
        }
        }
        *currentState = newState;
        *currentState = newState;
        newConfigId = calculateRefreshRateConfigIndexType();
        newConfigId = calculateRefreshRateConfigIndexType(&touchConsidered);
        if (mFeatures.configId == newConfigId) {
        if (mFeatures.configId == newConfigId) {
            return;
            return touchConsidered;
        }
        }
        mFeatures.configId = newConfigId;
        mFeatures.configId = newConfigId;
        if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) {
        if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) {
@@ -569,10 +572,12 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO
    }
    }
    const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
    const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
    mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
    mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
    return touchConsidered;
}
}


HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType(bool* touchConsidered) {
    ATRACE_CALL();
    ATRACE_CALL();
    if (touchConsidered) *touchConsidered = false;


    // If Display Power is not in normal operation we want to be in performance mode. When coming
    // If Display Power is not in normal operation we want to be in performance mode. When coming
    // back to normal mode, a grace period is given with DisplayPowerTimer.
    // back to normal mode, a grace period is given with DisplayPowerTimer.
@@ -607,18 +612,9 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
                .getConfigId();
                .getConfigId();
    }
    }


    bool touchConsidered;
    return mRefreshRateConfigs
    const auto& ret = mRefreshRateConfigs
            .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle, touchConsidered)
                              .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle,
                                                  &touchConsidered)
            .getConfigId();
            .getConfigId();
    if (touchConsidered) {
        // Clear layer history if refresh rate was selected based on touch to allow
        // the hueristic to pick up with the new rate.
        mLayerHistory->clear();
    }

    return ret;
}
}


std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
Loading