/* * 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "LayerHistoryTest" #include #include #include #include #include #include #include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" using testing::_; using testing::Return; using testing::ReturnRef; namespace android::scheduler { using MockLayer = android::mock::MockLayer; using android::mock::createDisplayMode; using android::mock::createVrrDisplayMode; // WARNING: LEGACY TESTS FOR LEGACY FRONT END // Update LayerHistoryIntegrationTest instead class LayerHistoryTest : public testing::Test { protected: 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 Fps LO_FPS = 30_Hz; static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs(); static constexpr Fps HI_FPS = 90_Hz; static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs(); LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); } LayerHistory& history() { return mScheduler->mutableLayerHistory(); } const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); } LayerHistory::Summary summarizeLayerHistory(nsecs_t now) { // LayerHistory::summarize makes no guarantee of the order of the elements in the summary // however, for testing only, a stable order is required, therefore we sort the list here. // Any tests requiring ordered results must create layers with names. auto summary = history().summarize(*mScheduler->refreshRateSelector(), now); std::sort(summary.begin(), summary.end(), [](const RefreshRateSelector::LayerRequirement& lhs, const RefreshRateSelector::LayerRequirement& rhs) -> bool { return lhs.name < rhs.name; }); return summary; } size_t layerCount() const { return mScheduler->layerHistorySize(); } size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayerInfos.size(); } auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mActiveLayerInfos; return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { return pair.second.second->isFrequent(now).isFrequent; }); } auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mActiveLayerInfos; return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { return pair.second.second->isAnimating(now); }); } auto clearLayerHistoryCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mActiveLayerInfos; return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { return pair.second.second->isFrequent(now).clearHistory; }); } void setDefaultLayerVote(Layer* layer, LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { auto [found, layerPair] = history().findLayer(layer->getSequence()); if (found != LayerHistory::LayerStatus::NotFound) { layerPair->second->setDefaultLayerVote(vote); } } auto createLayer() { return sp::make(mFlinger.flinger()); } auto createLayer(std::string name) { return sp::make(mFlinger.flinger(), std::move(name)); } auto createLayer(std::string name, uint32_t uid) { return sp::make(mFlinger.flinger(), std::move(name), std::move(uid)); } void recordFramesAndExpect(const sp& layer, nsecs_t& time, Fps frameRate, Fps desiredRefreshRate, int numFrames) { LayerHistory::Summary summary; for (int i = 0; i < numFrames; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += frameRate.getPeriodNsecs(); summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); } static constexpr auto kVrrModeId = DisplayModeId(2); std::shared_ptr mSelector = std::make_shared( makeModes(createDisplayMode(DisplayModeId(0), LO_FPS), createDisplayMode(DisplayModeId(1), HI_FPS), createVrrDisplayMode(kVrrModeId, HI_FPS, hal::VrrConfig{.minFrameIntervalNs = HI_FPS.getPeriodNsecs()})), DisplayModeId(0)); mock::SchedulerCallback mSchedulerCallback; TestableSurfaceFlinger mFlinger; TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback); }; namespace { using namespace com::android::graphics::surfaceflinger; TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) .WillOnce(Return(FrameRateCompatibility::NoVote)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = systemTime(); // No layers returned if no layers are active. EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); history().record(layer->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); history().setDefaultFrameRateCompatibility(layer->getSequence(), layer->getDefaultFrameRateCompatibility(), true /* contentDetectionEnabled */); EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(1, activeLayerCount()); } TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) .WillOnce(Return(FrameRateCompatibility::Min)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = systemTime(); EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); history().record(layer->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); history().setDefaultFrameRateCompatibility(layer->getSequence(), layer->getDefaultFrameRateCompatibility(), true /* contentDetectionEnabled */); auto summary = summarizeLayerHistory(time); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); // history().registerLayer(layer, LayerHistory::LayerVoteType::Max); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = systemTime(); // No layers returned if no layers are active. EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); // Max returned if active layers have insufficient history. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { history().record(layer->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); time += LO_FPS_PERIOD; } // Max is returned since we have enough history but there is no timestamp votes. for (int i = 0; i < 10; i++) { history().record(layer->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); time += LO_FPS_PERIOD; } } TEST_F(LayerHistoryTest, gameFrameRateOverrideMapping) { SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 60.0f})); auto overridePair = history().getGameFrameRateOverride(0); EXPECT_EQ(0_Hz, overridePair.first); EXPECT_EQ(60_Hz, overridePair.second); history().updateGameModeFrameRateOverride(FrameRateOverride({0, 40.0f})); history().updateGameModeFrameRateOverride(FrameRateOverride({1, 120.0f})); overridePair = history().getGameFrameRateOverride(0); EXPECT_EQ(40_Hz, overridePair.first); EXPECT_EQ(60_Hz, overridePair.second); overridePair = history().getGameFrameRateOverride(1); EXPECT_EQ(120_Hz, overridePair.first); EXPECT_EQ(0_Hz, overridePair.second); history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 0.0f})); history().updateGameModeFrameRateOverride(FrameRateOverride({1, 0.0f})); overridePair = history().getGameFrameRateOverride(0); EXPECT_EQ(40_Hz, overridePair.first); EXPECT_EQ(0_Hz, overridePair.second); overridePair = history().getGameFrameRateOverride(1); EXPECT_EQ(0_Hz, overridePair.first); EXPECT_EQ(0_Hz, overridePair.second); } TEST_F(LayerHistoryTest, oneLayerGameFrameRateOverride) { SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); const uid_t uid = 0; const Fps gameDefaultFrameRate = Fps::fromValue(30.0f); const Fps gameModeFrameRate = Fps::fromValue(60.0f); const auto layer = createLayer("GameFrameRateLayer", uid); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); // update game default frame rate override history().updateGameDefaultFrameRateOverride( FrameRateOverride({uid, gameDefaultFrameRate.getValue()})); nsecs_t time = systemTime(); LayerHistory::Summary summary; for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += gameDefaultFrameRate.getPeriodNsecs(); summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote); ASSERT_EQ(30.0_Hz, summary[0].desiredRefreshRate); // test against setFrameRate vote const Fps setFrameRate = Fps::fromValue(120.0f); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(setFrameRate, Layer::FrameRateCompatibility::Default))); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += setFrameRate.getPeriodNsecs(); summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote); ASSERT_EQ(120.0_Hz, summary[0].desiredRefreshRate); // update game mode frame rate override history().updateGameModeFrameRateOverride( FrameRateOverride({uid, gameModeFrameRate.getValue()})); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += gameModeFrameRate.getPeriodNsecs(); summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote); ASSERT_EQ(60.0_Hz, summary[0].desiredRefreshRate); } 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->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); auto summary = summarizeLayerHistory(time); ASSERT_EQ(1, summarizeLayerHistory(time).size()); // Layer is still considered inactive so we expect to get Min EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); history().record(layer->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); summary = summarizeLayerHistory(time); EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(0, activeLayerCount()); } TEST_F(LayerHistoryTest, explicitTimestamp) { 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(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(LO_FPS, summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_TRUE(summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_TRUE(summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became inactive time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_TRUE(summarizeLayerHistory(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(73.4_Hz, 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became infrequent, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(73.4_Hz, summarizeLayerHistory(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(73.4_Hz, 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became infrequent, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } TEST_F(LayerHistoryTest, oneLayerExplicitGte_vrr) { // Set the test to be on a vrr mode. SET_FLAG_FOR_TEST(flags::vrr_config, true); mSelector->setActiveMode(kVrrModeId, HI_FPS); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte, Seamlessness::OnlySeamless, FrameRateCategory::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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); // layer became inactive, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } // Test for MRR device with VRR features enabled. TEST_F(LayerHistoryTest, oneLayerExplicitGte_nonVrr) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true); // The vrr_config flag is explicitly not set false because this test for an MRR device // should still work in a VRR-capable world. auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte, Seamlessness::OnlySeamless, FrameRateCategory::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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); // layer became infrequent, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default, Seamlessness::OnlySeamless, FrameRateCategory::High))); // Set default to Min so it is obvious that the vote reset triggered. 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } // There is only 1 LayerRequirement due to the disabled flag frame_rate_category_mrr. ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } TEST_F(LayerHistoryTest, oneLayerExplicitCategory) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default, Seamlessness::OnlySeamless, FrameRateCategory::High))); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // First LayerRequirement is the frame rate specification EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); // layer became infrequent, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); } // This test case should be the same as oneLayerNoVote except instead of layer vote is NoVote, // the category is NoPreference. TEST_F(LayerHistoryTest, oneLayerCategoryNoPreference) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default, Seamlessness::OnlySeamless, FrameRateCategory::NoPreference))); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } EXPECT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer became infrequent time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); EXPECT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default, Seamlessness::OnlySeamless, FrameRateCategory::High))); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } // There are 2 LayerRequirement's due to the frame rate category. ASSERT_EQ(2, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // First LayerRequirement is the layer's category specification EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); // Second LayerRequirement is the frame rate specification EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[1].vote); EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[1].frameRateCategory); // layer became infrequent, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(2, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); } TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategoryNotVisibleDoesNotVote) { SET_FLAG_FOR_TEST(flags::misc1, true); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(12.34_Hz, Layer::FrameRateCompatibility::Default, Seamlessness::OnlySeamless, FrameRateCategory::High))); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } // Layer is not visible, so the layer is moved to inactive, infrequent, and it will not have // votes to consider for refresh rate selection. ASSERT_EQ(0, summarizeLayerHistory(time).size()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } TEST_F(LayerHistoryTest, multipleLayers) { auto layer1 = createLayer("A"); auto layer2 = createLayer("B"); auto layer3 = createLayer("C"); EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); 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->getSequence(), layer1->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); // layer2 is frequent and has high refresh rate. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2->getSequence(), layer2->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; summary = summarizeLayerHistory(time); } // layer1 is still active but infrequent. history().record(layer1->getSequence(), layer1->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); EXPECT_EQ(HI_FPS, summarizeLayerHistory(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 < 2 * PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2->getSequence(), layer2->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer2 still has low refresh rate. // layer3 has high refresh rate but not enough history. constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD; for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { if (i % RATIO == 0) { history().record(layer2->getSequence(), layer2->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); } history().record(layer3->getSequence(), layer3->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; summary = summarizeLayerHistory(time); } ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LO_FPS, 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->getSequence(), layer3->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); summary = summarizeLayerHistory(time); ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); // layer1 expires. layer1.clear(); summary = summarizeLayerHistory(time); ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate); EXPECT_EQ(2, layerCount()); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); // layer2 still has low refresh rate. // layer3 becomes inactive. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer2->getSequence(), layer2->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += LO_FPS_PERIOD; summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer2 expires. layer2.clear(); summary = summarizeLayerHistory(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 + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) { history().record(layer3->getSequence(), layer3->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(HI_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(1, layerCount()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); // layer3 expires. layer3.clear(); summary = summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); 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)); } // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); EXPECT_EQ(1, layerCount()); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(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 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; EXPECT_EQ(1, layerCount()); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } // More quick frames will get us to frequent again history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; 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)); } TEST_F(LayerHistoryTest, invisibleExplicitLayer) { SET_FLAG_FOR_TEST(flags::misc1, false); auto explicitVisiblelayer = createLayer(); auto explicitInvisiblelayer = createLayer(); EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree()) .WillRepeatedly(Return( Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false)); EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree()) .WillRepeatedly(Return( Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); nsecs_t time = systemTime(); // Post a buffer to the layers to make them active history().record(explicitVisiblelayer->getSequence(), explicitVisiblelayer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(explicitInvisiblelayer->getSequence(), explicitInvisiblelayer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(2, layerCount()); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); } TEST_F(LayerHistoryTest, invisibleExplicitLayerDoesNotVote) { SET_FLAG_FOR_TEST(flags::misc1, true); auto explicitVisiblelayer = createLayer(); auto explicitInvisiblelayer = createLayer(); EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree()) .WillRepeatedly(Return( Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false)); EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree()) .WillRepeatedly(Return( Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); nsecs_t time = systemTime(); // Post a buffer to the layers to make them active history().record(explicitVisiblelayer->getSequence(), explicitVisiblelayer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(explicitInvisiblelayer->getSequence(), explicitInvisiblelayer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(2, layerCount()); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); } 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)); // another update with the same cadence keep in infrequent history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); 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)); // an update as animation will immediately vote for Max history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::AnimationTX); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(1, animatingLayerCount(time)); } TEST_F(LayerHistoryTest, frontBufferedLayerVotesMax) { SET_FLAG_FOR_TEST(flags::vrr_config, true); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer, isFrontBuffered()).WillRepeatedly(Return(true)); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); // Layer still active due to front buffering, but it's infrequent. time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, 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->getSequence(), layer->getLayerProps(), 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(1, clearLayerHistoryCount(time)); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); 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, inconclusiveLayerBecomingFrequent) { 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->getSequence(), layer->getLayerProps(), 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 infrequent buffers after long inactivity should make the layer // inconclusive but frequent. time += std::chrono::nanoseconds(3s).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); // posting more buffers should make the layer frequent and switch the refresh rate to max // by clearing the history history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(1, clearLayerHistoryCount(time)); 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(); 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->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); } float expectedFramerate = 1e9f / MAX_FREQUENT_LAYER_PERIOD_NS.count(); EXPECT_FLOAT_EQ(expectedFramerate, history().getLayerFramerate(time, layer->getSequence())); } 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::fromValue(fps), 60_Hz, 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, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 30_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 30_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 60_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); } TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) { SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, false); 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, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); } TEST_F(LayerHistoryTest, heuristicLayerNotOscillating_useKnownRefreshRate) { SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, true); 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, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 27.1_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); } TEST_F(LayerHistoryTest, smallDirtyLayer) { 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)); LayerHistory::Summary summary; // layer is active but infrequent. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { auto props = layer->getLayerProps(); if (i % 3 == 0) { props.isSmallDirty = false; } else { props.isSmallDirty = true; } history().record(layer->getSequence(), props, time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_GE(HI_FPS, summary[0].desiredRefreshRate); } TEST_F(LayerHistoryTest, smallDirtyInMultiLayer) { auto layer1 = createLayer("UI"); auto layer2 = createLayer("Video"); EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer2, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(30_Hz, Layer::FrameRateCompatibility::Default))); nsecs_t time = systemTime(); EXPECT_EQ(2, layerCount()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); LayerHistory::Summary summary; // layer1 is updating small dirty. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) { auto props = layer1->getLayerProps(); props.isSmallDirty = true; history().record(layer1->getSequence(), props, 0 /*presentTime*/, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer2->getSequence(), layer2->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; summary = summarizeLayerHistory(time); } ASSERT_EQ(1, summary.size()); ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote); ASSERT_EQ(30_Hz, summary[0].desiredRefreshRate); } class LayerHistoryTestParameterized : public LayerHistoryTest, public testing::WithParamInterface { }; 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->getSequence(), heuristicLayer->getLayerProps(), startTime, startTime, LayerHistory::LayerUpdateType::Buffer); history().record(infrequentLayer->getSequence(), heuristicLayer->getLayerProps(), 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->getSequence(), heuristicLayer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) { ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates, totalInfrequentLayerUpdates); lastInfrequentUpdate = time; history().record(infrequentLayer->getSequence(), infrequentLayer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); infrequentLayerUpdates++; } if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) { ASSERT_NE(0, summarizeLayerHistory(time).size()); ASSERT_GE(2, summarizeLayerHistory(time).size()); bool max = false; bool min = false; Fps heuristic; for (const auto& layer : summarizeLayerHistory(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_EQ(24_Hz, heuristic); EXPECT_FALSE(max); if (summarizeLayerHistory(time).size() == 2) { EXPECT_TRUE(min); } } } } } INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); } // namespace } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wextra"