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

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

Merge "SF: tune infrequent layers for animations"

parents 490c032a 86ac5c5b
Loading
Loading
Loading
Loading
+37 −6
Original line number Diff line number Diff line
@@ -77,12 +77,43 @@ bool LayerInfo::isFrameTimeValid(const FrameTimeData& frameTime) const {

bool LayerInfo::isFrequent(nsecs_t now) const {
    using fps_approx_ops::operator>=;
    // If we know nothing about this layer we consider it as frequent as it might be the start
    // of an animation.
    // If we know nothing about this layer (e.g. after touch event),
    // we consider it as frequent as it might be the start of an animation.
    if (mFrameTimes.size() < kFrequentLayerWindowSize) {
        return true;
    }
    return getFps(now) >= kMinFpsForFrequentLayer;

    // Non-active layers are also infrequent
    if (mLastUpdatedTime < getActiveLayerThreshold(now)) {
        return false;
    }

    // We check whether we can classify this layer as frequent or infrequent:
    //  - frequent: a layer posted kFrequentLayerWindowSize within
    //              kMaxPeriodForFrequentLayerNs of each other.
    // -  infrequent: a layer posted kFrequentLayerWindowSize with longer
    //                gaps than kFrequentLayerWindowSize.
    // If we can't determine the layer classification yet, we return the last
    // classification.
    bool isFrequent = true;
    bool isInfrequent = true;
    const auto n = mFrameTimes.size() - 1;
    for (size_t i = 0; i < kFrequentLayerWindowSize - 1; i++) {
        if (mFrameTimes[n - i].queueTime - mFrameTimes[n - i - 1].queueTime <
            kMaxPeriodForFrequentLayerNs.count()) {
            isInfrequent = false;
        } else {
            isFrequent = false;
        }
    }

    if (isFrequent || isInfrequent) {
        return isFrequent;
    }

    // If we can't determine whether the layer is frequent or not, we return
    // the last known classification.
    return !mLastRefreshRate.infrequent;
}

Fps LayerInfo::getFps(nsecs_t now) const {
@@ -235,14 +266,14 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se
    if (isAnimating(now)) {
        ATRACE_FORMAT_INSTANT("animating");
        ALOGV("%s is animating", mName.c_str());
        mLastRefreshRate.animatingOrInfrequent = true;
        mLastRefreshRate.animating = true;
        return {LayerHistory::LayerVoteType::Max, Fps()};
    }

    if (!isFrequent(now)) {
        ATRACE_FORMAT_INSTANT("infrequent");
        ALOGV("%s is infrequent", mName.c_str());
        mLastRefreshRate.animatingOrInfrequent = true;
        mLastRefreshRate.infrequent = true;
        // Infrequent layers vote for mininal refresh rate for
        // battery saving purposes and also to prevent b/135718869.
        return {LayerHistory::LayerVoteType::Min, Fps()};
@@ -251,7 +282,7 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se
    // If the layer was previously tagged as animating or infrequent, we clear
    // the history as it is likely the layer just changed its behavior
    // and we should not look at stale data
    if (mLastRefreshRate.animatingOrInfrequent) {
    if (mLastRefreshRate.animating || mLastRefreshRate.infrequent) {
        clearHistory(now);
    }

+5 −2
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ class LayerInfo {
    // Layer is considered frequent if the earliest value in the window of most recent present times
    // 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 kFrequentLayerWindowSize = 3;
    static constexpr size_t kFrequentLayerWindowSize = 4;
    static constexpr Fps kMinFpsForFrequentLayer = 10_Hz;
    static constexpr auto kMaxPeriodForFrequentLayerNs =
            std::chrono::nanoseconds(kMinFpsForFrequentLayer.getPeriodNsecs()) + 1ms;
@@ -214,7 +214,10 @@ private:
        Fps reported;
        // Whether the last reported rate for LayerInfo::getRefreshRate()
        // was due to animation or infrequent updates
        bool animatingOrInfrequent = false;
        bool animating = false;
        // Whether the last reported rate for LayerInfo::getRefreshRate()
        // was due to infrequent updates
        bool infrequent = false;
    };

    // Class to store past calculated refresh rate and determine whether
+83 −3
Original line number Diff line number Diff line
@@ -51,8 +51,6 @@ protected:
    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::kMaxPeriodForFrequentLayerNs;
    static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfo::kFrequentLayerWindowSize;
    static constexpr auto PRESENT_TIME_HISTORY_DURATION = LayerInfo::HISTORY_DURATION;
    static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
            LayerInfo::RefreshRateHistory::HISTORY_DURATION;

    static constexpr Fps LO_FPS = 30_Hz;
    static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs();
@@ -607,7 +605,7 @@ TEST_F(LayerHistoryTest, inactiveLayers) {
    // advance the time for the previous frame to be inactive
    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();

    // Now event if we post a quick few frame we should stay infrequent
    // Now even if we post a quick few frame we should stay infrequent
    for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
        time += HI_FPS_PERIOD;
@@ -706,6 +704,88 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) {
    EXPECT_EQ(1, animatingLayerCount(time));
}

TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) {
    auto layer = createLayer();

    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));

    nsecs_t time = systemTime();

    EXPECT_EQ(1, layerCount());
    EXPECT_EQ(0, activeLayerCount());
    EXPECT_EQ(0, frequentLayerCount(time));
    EXPECT_EQ(0, animatingLayerCount(time));

    // Fill up the window with frequent updates
    for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) {
        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
        time += (60_Hz).getPeriodNsecs();

        EXPECT_EQ(1, layerCount());
        ASSERT_EQ(1, summarizeLayerHistory(time).size());
        EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
        EXPECT_EQ(1, activeLayerCount());
        EXPECT_EQ(1, frequentLayerCount(time));
    }

    // posting a buffer after long inactivity should retain the layer as active
    time += std::chrono::nanoseconds(3s).count();
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(1, summarizeLayerHistory(time).size());
    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
    EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
    EXPECT_EQ(1, activeLayerCount());
    EXPECT_EQ(1, frequentLayerCount(time));
    EXPECT_EQ(0, animatingLayerCount(time));

    // posting more infrequent buffer should make the layer infrequent
    time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count();
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count();
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(1, summarizeLayerHistory(time).size());
    EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
    EXPECT_EQ(1, activeLayerCount());
    EXPECT_EQ(0, frequentLayerCount(time));
    EXPECT_EQ(0, animatingLayerCount(time));

    // posting another buffer should keep the layer infrequent
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(1, summarizeLayerHistory(time).size());
    EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
    EXPECT_EQ(1, activeLayerCount());
    EXPECT_EQ(0, frequentLayerCount(time));
    EXPECT_EQ(0, animatingLayerCount(time));

    // posting more buffers would mean starting of an animation, so making the layer frequent
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(1, summarizeLayerHistory(time).size());
    EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
    EXPECT_EQ(1, activeLayerCount());
    EXPECT_EQ(1, frequentLayerCount(time));
    EXPECT_EQ(0, animatingLayerCount(time));

    // posting a buffer after long inactivity should retain the layer as active
    time += std::chrono::nanoseconds(3s).count();
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(1, summarizeLayerHistory(time).size());
    EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
    EXPECT_EQ(1, activeLayerCount());
    EXPECT_EQ(1, frequentLayerCount(time));
    EXPECT_EQ(0, animatingLayerCount(time));

    // posting another buffer should keep the layer frequent
    time += (60_Hz).getPeriodNsecs();
    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
    ASSERT_EQ(1, summarizeLayerHistory(time).size());
    EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
    EXPECT_EQ(1, activeLayerCount());
    EXPECT_EQ(1, frequentLayerCount(time));
    EXPECT_EQ(0, animatingLayerCount(time));
}

TEST_F(LayerHistoryTest, getFramerate) {
    auto layer = createLayer();