Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +19 −10 Original line number Original line Diff line number Diff line Loading @@ -57,16 +57,23 @@ public: } } ~RefreshRateConfigs() = default; ~RefreshRateConfigs() = default; const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() { const std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() { return mRefreshRates; return mRefreshRates; } } const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; } std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) { const auto& refreshRate = mRefreshRates.find(type); if (refreshRate != mRefreshRates.end()) { return refreshRate->second; } return nullptr; } private: private: void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { // This is the rate that HWC encapsulates right now when the device is in DOZE mode. // This is the rate that HWC encapsulates right now when the device is in DOZE mode. mRefreshRates.emplace(RefreshRateType::POWER_SAVING, mRefreshRates.emplace(RefreshRateType::POWER_SAVING, RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}); std::make_shared<RefreshRate>( RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0})); if (configs.size() < 1) { if (configs.size() < 1) { ALOGE("Device does not have valid configs. Config size is 0."); ALOGE("Device does not have valid configs. Config size is 0."); Loading @@ -90,9 +97,10 @@ private: if (vsyncPeriod != 0) { if (vsyncPeriod != 0) { const float fps = 1e9 / vsyncPeriod; const float fps = 1e9 / vsyncPeriod; mRefreshRates.emplace(RefreshRateType::DEFAULT, mRefreshRates.emplace(RefreshRateType::DEFAULT, std::make_shared<RefreshRate>( RefreshRate{configIdToVsyncPeriod[0].first, RefreshRate{configIdToVsyncPeriod[0].first, base::StringPrintf("%2.ffps", fps), base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)}); static_cast<uint32_t>(fps)})); } } if (configs.size() < 2) { if (configs.size() < 2) { Loading @@ -105,13 +113,14 @@ private: if (vsyncPeriod != 0) { if (vsyncPeriod != 0) { const float fps = 1e9 / vsyncPeriod; const float fps = 1e9 / vsyncPeriod; mRefreshRates.emplace(RefreshRateType::PERFORMANCE, mRefreshRates.emplace(RefreshRateType::PERFORMANCE, std::make_shared<RefreshRate>( RefreshRate{configIdToVsyncPeriod[1].first, RefreshRate{configIdToVsyncPeriod[1].first, base::StringPrintf("%2.ffps", fps), base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)}); static_cast<uint32_t>(fps)})); } } } } std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates; std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates; }; }; } // namespace scheduler } // namespace scheduler Loading services/surfaceflinger/Scheduler/RefreshRateStats.h +11 −5 Original line number Original line Diff line number Diff line Loading @@ -85,10 +85,13 @@ public: std::unordered_map<std::string, int64_t> totalTime; std::unordered_map<std::string, int64_t> totalTime; for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) { for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) { int64_t totalTimeForConfig = 0; int64_t totalTimeForConfig = 0; if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) { if (!config) { totalTimeForConfig = mConfigModesTotalTime.at(config.configId); continue; } } totalTime[config.name] = totalTimeForConfig; if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) { totalTimeForConfig = mConfigModesTotalTime.at(config->configId); } totalTime[config->name] = totalTimeForConfig; } } return totalTime; return totalTime; } } Loading Loading @@ -124,8 +127,11 @@ private: mConfigModesTotalTime[mode] += timeElapsedMs; mConfigModesTotalTime[mode] += timeElapsedMs; for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) { for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) { if (config.configId == mode) { if (!config) { mTimeStats->recordRefreshRate(config.fps, timeElapsed); continue; } if (config->configId == mode) { mTimeStats->recordRefreshRate(config->fps, timeElapsed); } } } } } } Loading services/surfaceflinger/SurfaceFlinger.cpp +19 −10 Original line number Original line Diff line number Diff line Loading @@ -592,10 +592,11 @@ void SurfaceFlinger::bootFinished() const auto displayId = getInternalDisplayIdLocked(); const auto displayId = getInternalDisplayIdLocked(); LOG_ALWAYS_FATAL_IF(!displayId); LOG_ALWAYS_FATAL_IF(!displayId); const auto performanceRefreshRate = const auto& performanceRefreshRate = mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) { if (performanceRefreshRate && isConfigAllowed(*displayId, performanceRefreshRate->configId)) { setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); } else { } else { setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); Loading Loading @@ -1471,17 +1472,24 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co LOG_ALWAYS_FATAL_IF(!displayId); LOG_ALWAYS_FATAL_IF(!displayId); const auto displayToken = getInternalDisplayTokenLocked(); const auto displayToken = getInternalDisplayTokenLocked(); auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId; const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate); const auto display = getDisplayDeviceLocked(displayToken); if (!refreshRateConfig) { if (desiredConfigId == display->getActiveConfig()) { ALOGV("Skipping refresh rate change request for unsupported rate."); return; return; } } const int desiredConfigId = refreshRateConfig->configId; if (!isConfigAllowed(*displayId, desiredConfigId)) { if (!isConfigAllowed(*displayId, desiredConfigId)) { ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); return; return; } } const auto display = getDisplayDeviceLocked(displayToken); if (desiredConfigId == display->getActiveConfig()) { return; } mPhaseOffsets->setRefreshRateType(refreshRate); mPhaseOffsets->setRefreshRateType(refreshRate); setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event); setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event); } } Loading Loading @@ -5797,12 +5805,12 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal( int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId); int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId); if (!isConfigAllowed(*displayId, currentConfigIndex)) { if (!isConfigAllowed(*displayId, currentConfigIndex)) { for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) { for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) { if (isConfigAllowed(*displayId, config.configId)) { if (config && isConfigAllowed(*displayId, config->configId)) { // TODO: we switch to the first allowed config. In the future // TODO: we switch to the first allowed config. In the future // we may want to enhance this logic to pick a similar config // we may want to enhance this logic to pick a similar config // to the current one // to the current one ALOGV("Old config is not allowed - switching to config %d", config.configId); ALOGV("Old config is not allowed - switching to config %d", config->configId); setDesiredActiveConfig(displayToken, config.configId, setDesiredActiveConfig(displayToken, config->configId, Scheduler::ConfigEvent::Changed); Scheduler::ConfigEvent::Changed); break; break; } } Loading @@ -5812,9 +5820,10 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal( // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT, // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT, // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed. // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed. if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) { if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) { const auto performanceRefreshRate = const auto& performanceRefreshRate = mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) { if (performanceRefreshRate && isConfigAllowed(*displayId, performanceRefreshRate->configId)) { setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed); setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed); } } } } Loading services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ cc_test { "LayerMetadataTest.cpp", "LayerMetadataTest.cpp", "SchedulerTest.cpp", "SchedulerTest.cpp", "SchedulerUtilsTest.cpp", "SchedulerUtilsTest.cpp", "RefreshRateConfigsTest.cpp", "RefreshRateStatsTest.cpp", "RefreshRateStatsTest.cpp", "TimeStatsTest.cpp", "TimeStatsTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockComposer.cpp", Loading services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp 0 → 100644 +164 −0 Original line number Original line Diff line number Diff line /* * Copyright 2019 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. */ #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" #include <gmock/gmock.h> #include <log/log.h> #include <thread> #include "DisplayHardware/HWC2.h" #include "Scheduler/RefreshRateConfigs.h" #include "mock/DisplayHardware/MockDisplay.h" using namespace std::chrono_literals; using testing::_; namespace android { namespace scheduler { using RefreshRateType = RefreshRateConfigs::RefreshRateType; using RefreshRate = RefreshRateConfigs::RefreshRate; class RefreshRateConfigsTest : public testing::Test { protected: static constexpr int CONFIG_ID_60 = 0; static constexpr int CONFIG_ID_90 = 1; static constexpr int64_t VSYNC_60 = 16666667; static constexpr int64_t VSYNC_90 = 11111111; RefreshRateConfigsTest(); ~RefreshRateConfigsTest(); void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) { ASSERT_EQ(left.configId, right.configId); ASSERT_EQ(left.name, right.name); ASSERT_EQ(left.fps, right.fps); } }; RefreshRateConfigsTest::RefreshRateConfigsTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); } RefreshRateConfigsTest::~RefreshRateConfigsTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } namespace { /* ------------------------------------------------------------------------ * Test cases */ TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; RefreshRateConfigs configs(displayConfigs); // We always store a configuration for screen off. const auto& rates = configs.getRefreshRates(); ASSERT_EQ(1, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); ASSERT_NE(rates.end(), powerSavingRate); ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT)); RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedConfig, *powerSavingRate->second); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT)); // Sanity check that getRefreshRate() does not modify the underlying configs. ASSERT_EQ(1, configs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { auto display = new Hwc2::mock::Display(); std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); config60.setVsyncPeriod(VSYNC_60); displayConfigs.push_back(config60.build()); RefreshRateConfigs configs(displayConfigs); const auto& rates = configs.getRefreshRates(); ASSERT_EQ(2, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); ASSERT_NE(rates.end(), powerSavingRate); ASSERT_NE(rates.end(), defaultRate); ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60}; assertRatesEqual(expectedDefaultConfig, *defaultRate->second); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); // Sanity check that getRefreshRate() does not modify the underlying configs. ASSERT_EQ(2, configs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { auto display = new Hwc2::mock::Display(); std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); config60.setVsyncPeriod(VSYNC_60); displayConfigs.push_back(config60.build()); auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); config90.setVsyncPeriod(VSYNC_90); displayConfigs.push_back(config90.build()); RefreshRateConfigs configs(displayConfigs); const auto& rates = configs.getRefreshRates(); ASSERT_EQ(3, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE); ASSERT_NE(rates.end(), powerSavingRate); ASSERT_NE(rates.end(), defaultRate); ASSERT_NE(rates.end(), performanceRate); RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60}; assertRatesEqual(expectedDefaultConfig, *defaultRate->second); RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90}; assertRatesEqual(expectedPerformanceConfig, *performanceRate->second); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); assertRatesEqual(expectedPerformanceConfig, *configs.getRefreshRate(RefreshRateType::PERFORMANCE)); } } // namespace } // namespace scheduler } // namespace android Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +19 −10 Original line number Original line Diff line number Diff line Loading @@ -57,16 +57,23 @@ public: } } ~RefreshRateConfigs() = default; ~RefreshRateConfigs() = default; const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() { const std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() { return mRefreshRates; return mRefreshRates; } } const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; } std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) { const auto& refreshRate = mRefreshRates.find(type); if (refreshRate != mRefreshRates.end()) { return refreshRate->second; } return nullptr; } private: private: void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { // This is the rate that HWC encapsulates right now when the device is in DOZE mode. // This is the rate that HWC encapsulates right now when the device is in DOZE mode. mRefreshRates.emplace(RefreshRateType::POWER_SAVING, mRefreshRates.emplace(RefreshRateType::POWER_SAVING, RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}); std::make_shared<RefreshRate>( RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0})); if (configs.size() < 1) { if (configs.size() < 1) { ALOGE("Device does not have valid configs. Config size is 0."); ALOGE("Device does not have valid configs. Config size is 0."); Loading @@ -90,9 +97,10 @@ private: if (vsyncPeriod != 0) { if (vsyncPeriod != 0) { const float fps = 1e9 / vsyncPeriod; const float fps = 1e9 / vsyncPeriod; mRefreshRates.emplace(RefreshRateType::DEFAULT, mRefreshRates.emplace(RefreshRateType::DEFAULT, std::make_shared<RefreshRate>( RefreshRate{configIdToVsyncPeriod[0].first, RefreshRate{configIdToVsyncPeriod[0].first, base::StringPrintf("%2.ffps", fps), base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)}); static_cast<uint32_t>(fps)})); } } if (configs.size() < 2) { if (configs.size() < 2) { Loading @@ -105,13 +113,14 @@ private: if (vsyncPeriod != 0) { if (vsyncPeriod != 0) { const float fps = 1e9 / vsyncPeriod; const float fps = 1e9 / vsyncPeriod; mRefreshRates.emplace(RefreshRateType::PERFORMANCE, mRefreshRates.emplace(RefreshRateType::PERFORMANCE, std::make_shared<RefreshRate>( RefreshRate{configIdToVsyncPeriod[1].first, RefreshRate{configIdToVsyncPeriod[1].first, base::StringPrintf("%2.ffps", fps), base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)}); static_cast<uint32_t>(fps)})); } } } } std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates; std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates; }; }; } // namespace scheduler } // namespace scheduler Loading
services/surfaceflinger/Scheduler/RefreshRateStats.h +11 −5 Original line number Original line Diff line number Diff line Loading @@ -85,10 +85,13 @@ public: std::unordered_map<std::string, int64_t> totalTime; std::unordered_map<std::string, int64_t> totalTime; for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) { for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) { int64_t totalTimeForConfig = 0; int64_t totalTimeForConfig = 0; if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) { if (!config) { totalTimeForConfig = mConfigModesTotalTime.at(config.configId); continue; } } totalTime[config.name] = totalTimeForConfig; if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) { totalTimeForConfig = mConfigModesTotalTime.at(config->configId); } totalTime[config->name] = totalTimeForConfig; } } return totalTime; return totalTime; } } Loading Loading @@ -124,8 +127,11 @@ private: mConfigModesTotalTime[mode] += timeElapsedMs; mConfigModesTotalTime[mode] += timeElapsedMs; for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) { for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) { if (config.configId == mode) { if (!config) { mTimeStats->recordRefreshRate(config.fps, timeElapsed); continue; } if (config->configId == mode) { mTimeStats->recordRefreshRate(config->fps, timeElapsed); } } } } } } Loading
services/surfaceflinger/SurfaceFlinger.cpp +19 −10 Original line number Original line Diff line number Diff line Loading @@ -592,10 +592,11 @@ void SurfaceFlinger::bootFinished() const auto displayId = getInternalDisplayIdLocked(); const auto displayId = getInternalDisplayIdLocked(); LOG_ALWAYS_FATAL_IF(!displayId); LOG_ALWAYS_FATAL_IF(!displayId); const auto performanceRefreshRate = const auto& performanceRefreshRate = mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) { if (performanceRefreshRate && isConfigAllowed(*displayId, performanceRefreshRate->configId)) { setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); } else { } else { setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); Loading Loading @@ -1471,17 +1472,24 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co LOG_ALWAYS_FATAL_IF(!displayId); LOG_ALWAYS_FATAL_IF(!displayId); const auto displayToken = getInternalDisplayTokenLocked(); const auto displayToken = getInternalDisplayTokenLocked(); auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId; const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate); const auto display = getDisplayDeviceLocked(displayToken); if (!refreshRateConfig) { if (desiredConfigId == display->getActiveConfig()) { ALOGV("Skipping refresh rate change request for unsupported rate."); return; return; } } const int desiredConfigId = refreshRateConfig->configId; if (!isConfigAllowed(*displayId, desiredConfigId)) { if (!isConfigAllowed(*displayId, desiredConfigId)) { ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); return; return; } } const auto display = getDisplayDeviceLocked(displayToken); if (desiredConfigId == display->getActiveConfig()) { return; } mPhaseOffsets->setRefreshRateType(refreshRate); mPhaseOffsets->setRefreshRateType(refreshRate); setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event); setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event); } } Loading Loading @@ -5797,12 +5805,12 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal( int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId); int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId); if (!isConfigAllowed(*displayId, currentConfigIndex)) { if (!isConfigAllowed(*displayId, currentConfigIndex)) { for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) { for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) { if (isConfigAllowed(*displayId, config.configId)) { if (config && isConfigAllowed(*displayId, config->configId)) { // TODO: we switch to the first allowed config. In the future // TODO: we switch to the first allowed config. In the future // we may want to enhance this logic to pick a similar config // we may want to enhance this logic to pick a similar config // to the current one // to the current one ALOGV("Old config is not allowed - switching to config %d", config.configId); ALOGV("Old config is not allowed - switching to config %d", config->configId); setDesiredActiveConfig(displayToken, config.configId, setDesiredActiveConfig(displayToken, config->configId, Scheduler::ConfigEvent::Changed); Scheduler::ConfigEvent::Changed); break; break; } } Loading @@ -5812,9 +5820,10 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal( // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT, // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT, // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed. // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed. if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) { if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) { const auto performanceRefreshRate = const auto& performanceRefreshRate = mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) { if (performanceRefreshRate && isConfigAllowed(*displayId, performanceRefreshRate->configId)) { setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed); setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed); } } } } Loading
services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ cc_test { "LayerMetadataTest.cpp", "LayerMetadataTest.cpp", "SchedulerTest.cpp", "SchedulerTest.cpp", "SchedulerUtilsTest.cpp", "SchedulerUtilsTest.cpp", "RefreshRateConfigsTest.cpp", "RefreshRateStatsTest.cpp", "RefreshRateStatsTest.cpp", "TimeStatsTest.cpp", "TimeStatsTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockComposer.cpp", Loading
services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp 0 → 100644 +164 −0 Original line number Original line Diff line number Diff line /* * Copyright 2019 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. */ #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" #include <gmock/gmock.h> #include <log/log.h> #include <thread> #include "DisplayHardware/HWC2.h" #include "Scheduler/RefreshRateConfigs.h" #include "mock/DisplayHardware/MockDisplay.h" using namespace std::chrono_literals; using testing::_; namespace android { namespace scheduler { using RefreshRateType = RefreshRateConfigs::RefreshRateType; using RefreshRate = RefreshRateConfigs::RefreshRate; class RefreshRateConfigsTest : public testing::Test { protected: static constexpr int CONFIG_ID_60 = 0; static constexpr int CONFIG_ID_90 = 1; static constexpr int64_t VSYNC_60 = 16666667; static constexpr int64_t VSYNC_90 = 11111111; RefreshRateConfigsTest(); ~RefreshRateConfigsTest(); void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) { ASSERT_EQ(left.configId, right.configId); ASSERT_EQ(left.name, right.name); ASSERT_EQ(left.fps, right.fps); } }; RefreshRateConfigsTest::RefreshRateConfigsTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); } RefreshRateConfigsTest::~RefreshRateConfigsTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } namespace { /* ------------------------------------------------------------------------ * Test cases */ TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; RefreshRateConfigs configs(displayConfigs); // We always store a configuration for screen off. const auto& rates = configs.getRefreshRates(); ASSERT_EQ(1, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); ASSERT_NE(rates.end(), powerSavingRate); ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT)); RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedConfig, *powerSavingRate->second); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT)); // Sanity check that getRefreshRate() does not modify the underlying configs. ASSERT_EQ(1, configs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { auto display = new Hwc2::mock::Display(); std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); config60.setVsyncPeriod(VSYNC_60); displayConfigs.push_back(config60.build()); RefreshRateConfigs configs(displayConfigs); const auto& rates = configs.getRefreshRates(); ASSERT_EQ(2, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); ASSERT_NE(rates.end(), powerSavingRate); ASSERT_NE(rates.end(), defaultRate); ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60}; assertRatesEqual(expectedDefaultConfig, *defaultRate->second); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); // Sanity check that getRefreshRate() does not modify the underlying configs. ASSERT_EQ(2, configs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { auto display = new Hwc2::mock::Display(); std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); config60.setVsyncPeriod(VSYNC_60); displayConfigs.push_back(config60.build()); auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); config90.setVsyncPeriod(VSYNC_90); displayConfigs.push_back(config90.build()); RefreshRateConfigs configs(displayConfigs); const auto& rates = configs.getRefreshRates(); ASSERT_EQ(3, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE); ASSERT_NE(rates.end(), powerSavingRate); ASSERT_NE(rates.end(), defaultRate); ASSERT_NE(rates.end(), performanceRate); RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60}; assertRatesEqual(expectedDefaultConfig, *defaultRate->second); RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90}; assertRatesEqual(expectedPerformanceConfig, *performanceRate->second); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); assertRatesEqual(expectedPerformanceConfig, *configs.getRefreshRate(RefreshRateType::PERFORMANCE)); } } // namespace } // namespace scheduler } // namespace android