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

Commit 0a1cc96f authored by Alec Mouri's avatar Alec Mouri
Browse files

Cleanup dumpsys for refresh configs for non-90hz devices.

Also add tests exercising RefreshRateConfigs behavior.

Bug: 127846986
Test: libsurfaceflinger_unittest
Test: dumpsys SurfaceFlinger
Change-Id: Idad91cf2a0a0b9661382d1b0011306fb4e36902b
parent 5e1371af
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -57,16 +57,23 @@ public:
    }
    ~RefreshRateConfigs() = default;

    const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() {
    const std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() {
        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:
    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.
        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) {
            ALOGE("Device does not have valid configs. Config size is 0.");
@@ -90,9 +97,10 @@ private:
        if (vsyncPeriod != 0) {
            const float fps = 1e9 / vsyncPeriod;
            mRefreshRates.emplace(RefreshRateType::DEFAULT,
                                  std::make_shared<RefreshRate>(
                                          RefreshRate{configIdToVsyncPeriod[0].first,
                                                      base::StringPrintf("%2.ffps", fps),
                                              static_cast<uint32_t>(fps)});
                                                      static_cast<uint32_t>(fps)}));
        }

        if (configs.size() < 2) {
@@ -105,13 +113,14 @@ private:
        if (vsyncPeriod != 0) {
            const float fps = 1e9 / vsyncPeriod;
            mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
                                  std::make_shared<RefreshRate>(
                                          RefreshRate{configIdToVsyncPeriod[1].first,
                                                      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
+11 −5
Original line number Diff line number Diff line
@@ -85,10 +85,13 @@ public:
        std::unordered_map<std::string, int64_t> totalTime;
        for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
            int64_t totalTimeForConfig = 0;
            if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
                totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
            if (!config) {
                continue;
            }
            totalTime[config.name] = totalTimeForConfig;
            if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) {
                totalTimeForConfig = mConfigModesTotalTime.at(config->configId);
            }
            totalTime[config->name] = totalTimeForConfig;
        }
        return totalTime;
    }
@@ -124,8 +127,11 @@ private:

        mConfigModesTotalTime[mode] += timeElapsedMs;
        for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
            if (config.configId == mode) {
                mTimeStats->recordRefreshRate(config.fps, timeElapsed);
            if (!config) {
                continue;
            }
            if (config->configId == mode) {
                mTimeStats->recordRefreshRate(config->fps, timeElapsed);
            }
        }
    }
+19 −10
Original line number Diff line number Diff line
@@ -570,10 +570,11 @@ void SurfaceFlinger::bootFinished()
        const auto displayId = getInternalDisplayIdLocked();
        LOG_ALWAYS_FATAL_IF(!displayId);

        const auto performanceRefreshRate =
        const auto& performanceRefreshRate =
                mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);

        if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
        if (performanceRefreshRate &&
            isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
            setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
        } else {
            setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
@@ -1448,17 +1449,24 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co
    LOG_ALWAYS_FATAL_IF(!displayId);
    const auto displayToken = getInternalDisplayTokenLocked();

    auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId;
    const auto display = getDisplayDeviceLocked(displayToken);
    if (desiredConfigId == display->getActiveConfig()) {
    const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate);
    if (!refreshRateConfig) {
        ALOGV("Skipping refresh rate change request for unsupported rate.");
        return;
    }

    const int desiredConfigId = refreshRateConfig->configId;

    if (!isConfigAllowed(*displayId, desiredConfigId)) {
        ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
        return;
    }

    const auto display = getDisplayDeviceLocked(displayToken);
    if (desiredConfigId == display->getActiveConfig()) {
        return;
    }

    mPhaseOffsets->setRefreshRateType(refreshRate);
    setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
}
@@ -5745,12 +5753,12 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(
    int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
    if (!isConfigAllowed(*displayId, currentConfigIndex)) {
        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
                // we may want to enhance this logic to pick a similar config
                // to the current one
                ALOGV("Old config is not allowed - switching to config %d", config.configId);
                setDesiredActiveConfig(displayToken, config.configId,
                ALOGV("Old config is not allowed - switching to config %d", config->configId);
                setDesiredActiveConfig(displayToken, config->configId,
                                       Scheduler::ConfigEvent::Changed);
                break;
            }
@@ -5760,9 +5768,10 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(
    // 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.
    if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) {
        const auto performanceRefreshRate =
        const auto& performanceRefreshRate =
                mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
        if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
        if (performanceRefreshRate &&
            isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
            setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
        }
    }
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ cc_test {
        "LayerMetadataTest.cpp",
        "SchedulerTest.cpp",
        "SchedulerUtilsTest.cpp",
        "RefreshRateConfigsTest.cpp",
        "RefreshRateStatsTest.cpp",
        "TimeStatsTest.cpp",
        "mock/DisplayHardware/MockComposer.cpp",
+164 −0
Original line number 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