diff options
Diffstat (limited to 'services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp')
-rw-r--r-- | services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp | 624 |
1 files changed, 559 insertions, 65 deletions
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index cae317bd5d..b67ebcaa49 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019 The Android Open Source Project + * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "LayerHistoryTest" +#include <Layer.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <log/log.h> @@ -30,53 +31,102 @@ #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/MockLayer.h" +#include "mock/MockSchedulerCallback.h" using testing::_; using testing::Return; -namespace android::scheduler { +namespace android { + +namespace scheduler { class LayerHistoryTest : public testing::Test { protected: - static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::PresentTimeHistory::HISTORY_SIZE; - static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::MAX_FREQUENT_LAYER_PERIOD_NS; + static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE; + 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 float LO_FPS = 30.f; - static constexpr nsecs_t LO_FPS_PERIOD = 33'333'333; + static constexpr Fps LO_FPS{30.f}; + static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs(); - static constexpr float HI_FPS = 90.f; - static constexpr nsecs_t HI_FPS_PERIOD = 11'111'111; + static constexpr Fps HI_FPS{90.f}; + static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs(); LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); } - impl::LayerHistory& history() { return *mScheduler->mutableLayerHistory(); } - const impl::LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); } + void SetUp() override { ASSERT_TRUE(mScheduler->hasLayerHistory()); } + + LayerHistory& history() { return *mScheduler->mutableLayerHistory(); } + const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); } size_t layerCount() const { return mScheduler->layerHistorySize(); } size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; } - size_t frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { + auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mLayerInfos; - return std::count_if(infos.begin(), infos.begin() + history().mActiveLayersEnd, + return std::count_if(infos.begin(), + infos.begin() + static_cast<long>(history().mActiveLayersEnd), [now](const auto& pair) { return pair.second->isFrequent(now); }); } + auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { + const auto& infos = history().mLayerInfos; + return std::count_if(infos.begin(), + infos.begin() + static_cast<long>(history().mActiveLayersEnd), + [now](const auto& pair) { return pair.second->isAnimating(now); }); + } + + void setDefaultLayerVote(Layer* layer, + LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { + for (auto& [layerUnsafe, info] : history().mLayerInfos) { + if (layerUnsafe == layer) { + info->setDefaultLayerVote(vote); + return; + } + } + } + auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); } + auto createLayer(std::string name) { + return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name))); + } + + void recordFramesAndExpect(const sp<mock::MockLayer>& layer, nsecs_t& time, Fps frameRate, + Fps desiredRefreshRate, int numFrames) { + LayerHistory::Summary summary; + for (int i = 0; i < numFrames; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += frameRate.getPeriodNsecs(); + + summary = history().summarize(time); + } - Hwc2::mock::Display mDisplay; - RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0) + ASSERT_EQ(1, summary.size()); + ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + ASSERT_TRUE(desiredRefreshRate.equalsWithMargin(summary[0].desiredRefreshRate)) + << "Frame rate is " << frameRate; + } + + RefreshRateConfigs mConfigs{{DisplayMode::Builder(0) + .setId(DisplayModeId(0)) .setVsyncPeriod(int32_t(LO_FPS_PERIOD)) - .setConfigGroup(0) + .setGroup(0) .build(), - HWC2::Display::Config::Builder(mDisplay, 1) + DisplayMode::Builder(1) + .setId(DisplayModeId(1)) .setVsyncPeriod(int32_t(HI_FPS_PERIOD)) - .setConfigGroup(0) + .setGroup(0) .build()}, - HwcConfigIndexType(0)}; - TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, false)}; - TestableSurfaceFlinger mFlinger; + DisplayModeId(0)}; + + mock::NoOpSchedulerCallback mSchedulerCallback; - const nsecs_t mTime = systemTime(); + TestableScheduler* const mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback); + + TestableSurfaceFlinger mFlinger; }; namespace { @@ -84,51 +134,227 @@ namespace { TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); - // no layers are returned if no layers are active. - ASSERT_TRUE(history().summarize(mTime).empty()); + const nsecs_t time = systemTime(); + + // No layers returned if no layers are active. + EXPECT_TRUE(history().summarize(time).empty()); EXPECT_EQ(0, activeLayerCount()); - // no layers are returned if active layers have insufficient history. + // Max returned if active layers have insufficient history. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { - history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer); - ASSERT_TRUE(history().summarize(mTime).empty()); + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } - // High FPS is returned once enough history has been recorded. + // Max is returned since we have enough history but there is no timestamp votes. for (int i = 0; i < 10; i++) { - history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer); - ASSERT_EQ(1, history().summarize(mTime).size()); - EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime)[0].desiredRefreshRate); + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } } +TEST_F(LayerHistoryTest, oneInvisibleLayer) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + auto summary = history().summarize(time); + ASSERT_EQ(1, history().summarize(time).size()); + // Layer is still considered inactive so we expect to get Min + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + + summary = history().summarize(time); + EXPECT_TRUE(history().summarize(time).empty()); + EXPECT_EQ(0, activeLayerCount()); +} + TEST_F(LayerHistoryTest, explicitTimestamp) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); - nsecs_t time = mTime; + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += LO_FPS_PERIOD; + } + + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote); + EXPECT_TRUE(LO_FPS.equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, oneLayerNoVote) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::NoVote); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_TRUE(history().summarize(time).empty()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_TRUE(history().summarize(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, oneLayerMinVote) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Min); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_TRUE(history().summarize(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, oneLayerMaxVote) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Max); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; } - ASSERT_EQ(1, history().summarize(mTime).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(mTime)[0].desiredRefreshRate); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_TRUE(history().summarize(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, oneLayerExplicitVote) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly( + Return(Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::Default))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive, but the vote stays + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly(Return( + Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::ExactOrMultiple))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + history().summarize(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive, but the vote stays + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + history().summarize(time)[0].vote); + EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); } TEST_F(LayerHistoryTest, multipleLayers) { @@ -137,30 +363,31 @@ TEST_F(LayerHistoryTest, multipleLayers) { auto layer3 = createLayer(); EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1)); EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1)); EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1)); EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); - nsecs_t time = mTime; + + nsecs_t time = systemTime(); EXPECT_EQ(3, layerCount()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); + LayerHistory::Summary summary; + // layer1 is active but infrequent. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + summary = history().summarize(time); } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate); + ASSERT_EQ(1, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); @@ -168,26 +395,31 @@ TEST_F(LayerHistoryTest, multipleLayers) { for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; + summary = history().summarize(time); } // layer1 is still active but infrequent. history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer); - ASSERT_EQ(2, history().summarize(time).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate); - EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate); + ASSERT_EQ(2, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); + ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); + EXPECT_TRUE(HI_FPS.equalsWithMargin(history().summarize(time)[1].desiredRefreshRate)); + EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer1 is no longer active. // layer2 is frequent and has low refresh rate. - for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + for (int i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; + summary = history().summarize(time); } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate); + ASSERT_EQ(1, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -201,26 +433,36 @@ TEST_F(LayerHistoryTest, multipleLayers) { history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; + summary = history().summarize(time); } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate); + ASSERT_EQ(2, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); // layer3 becomes recently active. history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer); - ASSERT_EQ(2, history().summarize(time).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate); - EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate); + summary = history().summarize(time); + ASSERT_EQ(2, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); + EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate)); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); // layer1 expires. layer1.clear(); - ASSERT_EQ(2, history().summarize(time).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate); - EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate); + summary = history().summarize(time); + ASSERT_EQ(2, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); + EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate)); EXPECT_EQ(2, layerCount()); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); @@ -230,42 +472,294 @@ TEST_F(LayerHistoryTest, multipleLayers) { for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; + summary = history().summarize(time); } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate); + ASSERT_EQ(1, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer2 expires. layer2.clear(); - ASSERT_TRUE(history().summarize(time).empty()); + summary = history().summarize(time); + EXPECT_TRUE(summary.empty()); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); // layer3 becomes active and has high refresh rate. - for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) { history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; + summary = history().summarize(time); } - ASSERT_EQ(1, history().summarize(time).size()); - EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[0].desiredRefreshRate); + ASSERT_EQ(1, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer3 expires. layer3.clear(); - ASSERT_TRUE(history().summarize(time).empty()); + summary = history().summarize(time); + EXPECT_TRUE(summary.empty()); EXPECT_EQ(0, layerCount()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } +TEST_F(LayerHistoryTest, inactiveLayers) { + auto layer = createLayer(); + + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + nsecs_t time = systemTime(); + + // the very first updates makes the layer frequent + for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + } + + // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + // 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 + for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + } + + // More quick frames will get us to frequent again + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, invisibleExplicitLayer) { + auto explicitVisiblelayer = createLayer(); + auto explicitInvisiblelayer = createLayer(); + + EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree()) + .WillRepeatedly(Return( + Layer::FrameRate(Fps(60.0f), Layer::FrameRateCompatibility::ExactOrMultiple))); + + EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false)); + EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree()) + .WillRepeatedly(Return( + Layer::FrameRate(Fps(90.0f), Layer::FrameRateCompatibility::ExactOrMultiple))); + + nsecs_t time = systemTime(); + + // Post a buffer to the layers to make them active + history().record(explicitVisiblelayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + history().record(explicitInvisiblelayer.get(), time, time, + LayerHistory::LayerUpdateType::Buffer); + + EXPECT_EQ(2, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + history().summarize(time)[0].vote); + EXPECT_TRUE(Fps(60.0f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate)); + EXPECT_EQ(2, activeLayerCount()); + EXPECT_EQ(2, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, infrequentAnimatingLayer) { + 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)); + + // layer is active but infrequent. + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + } + + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // another update with the same cadence keep in infrequent + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // an update as animation will immediately vote for Max + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(1, animatingLayerCount(time)); +} + +TEST_F(LayerHistoryTest, heuristicLayer60Hz) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + nsecs_t time = systemTime(); + for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) { + recordFramesAndExpect(layer, time, Fps(fps), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); + } +} + +TEST_F(LayerHistoryTest, heuristicLayer60_30Hz) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + nsecs_t time = systemTime(); + recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); + + recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(30.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(30.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(60.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); +} + +TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + nsecs_t time = systemTime(); + + recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(26.90f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(26.00f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(26.90f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); +} + +class LayerHistoryTestParameterized : public LayerHistoryTest, + public testing::WithParamInterface<std::chrono::nanoseconds> { +}; + +TEST_P(LayerHistoryTestParameterized, HeuristicLayerWithInfrequentLayer) { + std::chrono::nanoseconds infrequentUpdateDelta = GetParam(); + auto heuristicLayer = createLayer("HeuristicLayer"); + + EXPECT_CALL(*heuristicLayer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*heuristicLayer, getFrameRateForLayerTree()) + .WillRepeatedly(Return(Layer::FrameRate())); + + auto infrequentLayer = createLayer("InfrequentLayer"); + EXPECT_CALL(*infrequentLayer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*infrequentLayer, getFrameRateForLayerTree()) + .WillRepeatedly(Return(Layer::FrameRate())); + + const nsecs_t startTime = systemTime(); + + const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns; + history().record(heuristicLayer.get(), startTime, startTime, + LayerHistory::LayerUpdateType::Buffer); + history().record(infrequentLayer.get(), startTime, startTime, + LayerHistory::LayerUpdateType::Buffer); + + nsecs_t time = startTime; + nsecs_t lastInfrequentUpdate = startTime; + const int totalInfrequentLayerUpdates = FREQUENT_LAYER_WINDOW_SIZE * 5; + int infrequentLayerUpdates = 0; + while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) { + time += heuristicUpdateDelta.count(); + history().record(heuristicLayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + + if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) { + ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates, + totalInfrequentLayerUpdates); + lastInfrequentUpdate = time; + history().record(infrequentLayer.get(), time, time, + LayerHistory::LayerUpdateType::Buffer); + infrequentLayerUpdates++; + } + + if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) { + ASSERT_NE(0, history().summarize(time).size()); + ASSERT_GE(2, history().summarize(time).size()); + + bool max = false; + bool min = false; + Fps heuristic{0.0}; + for (const auto& layer : history().summarize(time)) { + if (layer.vote == LayerHistory::LayerVoteType::Heuristic) { + heuristic = layer.desiredRefreshRate; + } else if (layer.vote == LayerHistory::LayerVoteType::Max) { + max = true; + } else if (layer.vote == LayerHistory::LayerVoteType::Min) { + min = true; + } + } + + if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) { + EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic)); + EXPECT_FALSE(max); + if (history().summarize(time).size() == 2) { + EXPECT_TRUE(min); + } + } + } + } +} + +INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, + ::testing::Values(1s, 2s, 3s, 4s, 5s)); + } // namespace -} // namespace android::scheduler +} // namespace scheduler +} // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file |