1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <algorithm> 20 #include <numeric> 21 22 #include "android-base/stringprintf.h" 23 24 #include "DisplayHardware/HWComposer.h" 25 #include "Scheduler/SchedulerUtils.h" 26 27 namespace android { 28 namespace scheduler { 29 30 /** 31 * This class is used to encapsulate configuration for refresh rates. It holds information 32 * about available refresh rates on the device, and the mapping between the numbers and human 33 * readable names. 34 */ 35 class RefreshRateConfigs { 36 public: 37 // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance 38 // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. 39 enum class RefreshRateType { DEFAULT, PERFORMANCE }; 40 41 struct RefreshRate { 42 // This config ID corresponds to the position of the config in the vector that is stored 43 // on the device. 44 int configId; 45 // Human readable name of the refresh rate. 46 std::string name; 47 // Refresh rate in frames per second, rounded to the nearest integer. 48 uint32_t fps = 0; 49 // Vsync period in nanoseconds. 50 nsecs_t vsyncPeriod; 51 // Hwc config Id (returned from HWC2::Display::Config::getId()) 52 hwc2_config_t hwcId; 53 }; 54 55 // Returns true if this device is doing refresh rate switching. This won't change at runtime. refreshRateSwitchingSupported()56 bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; } 57 58 // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access 59 // from multiple threads. This can only be called if refreshRateSwitching() returns true. 60 // TODO(b/122916473): Get this information from configs prepared by vendors, instead of 61 // baking them in. getRefreshRateMap()62 const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const { 63 LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported); 64 return mRefreshRateMap; 65 } 66 getRefreshRateFromType(RefreshRateType type)67 const RefreshRate& getRefreshRateFromType(RefreshRateType type) const { 68 if (!mRefreshRateSwitchingSupported) { 69 return getCurrentRefreshRate().second; 70 } else { 71 auto refreshRate = mRefreshRateMap.find(type); 72 LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end()); 73 return refreshRate->second; 74 } 75 } 76 getCurrentRefreshRate()77 std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const { 78 int currentConfig = mCurrentConfig; 79 if (mRefreshRateSwitchingSupported) { 80 for (const auto& [type, refresh] : mRefreshRateMap) { 81 if (refresh.configId == currentConfig) { 82 return {type, refresh}; 83 } 84 } 85 LOG_ALWAYS_FATAL(); 86 } 87 return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]}; 88 } 89 getRefreshRateFromConfigId(int configId)90 const RefreshRate& getRefreshRateFromConfigId(int configId) const { 91 LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size()); 92 return mRefreshRates[configId]; 93 } 94 getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId)95 RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const { 96 if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT; 97 98 for (const auto& [type, refreshRate] : mRefreshRateMap) { 99 if (refreshRate.hwcId == hwcId) { 100 return type; 101 } 102 } 103 104 return RefreshRateType::DEFAULT; 105 } 106 setCurrentConfig(int config)107 void setCurrentConfig(int config) { 108 LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size()); 109 mCurrentConfig = config; 110 } 111 112 struct InputConfig { 113 hwc2_config_t hwcId = 0; 114 nsecs_t vsyncPeriod = 0; 115 }; 116 RefreshRateConfigs(bool refreshRateSwitching,const std::vector<InputConfig> & configs,int currentConfig)117 RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs, 118 int currentConfig) { 119 init(refreshRateSwitching, configs, currentConfig); 120 } 121 RefreshRateConfigs(bool refreshRateSwitching,const std::vector<std::shared_ptr<const HWC2::Display::Config>> & configs,int currentConfig)122 RefreshRateConfigs(bool refreshRateSwitching, 123 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs, 124 int currentConfig) { 125 std::vector<InputConfig> inputConfigs; 126 for (const auto& config : configs) { 127 inputConfigs.push_back({config->getId(), config->getVsyncPeriod()}); 128 } 129 init(refreshRateSwitching, inputConfigs, currentConfig); 130 } 131 132 private: init(bool refreshRateSwitching,const std::vector<InputConfig> & configs,int currentConfig)133 void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs, 134 int currentConfig) { 135 mRefreshRateSwitchingSupported = refreshRateSwitching; 136 LOG_ALWAYS_FATAL_IF(configs.empty()); 137 LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size()); 138 mCurrentConfig = currentConfig; 139 140 auto buildRefreshRate = [&](int configId) -> RefreshRate { 141 const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod; 142 const float fps = 1e9 / vsyncPeriod; 143 return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps), 144 vsyncPeriod, configs[configId].hwcId}; 145 }; 146 147 for (int i = 0; i < configs.size(); ++i) { 148 mRefreshRates.push_back(buildRefreshRate(i)); 149 } 150 151 if (!mRefreshRateSwitchingSupported) return; 152 153 auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> { 154 if (configs.size() < 2) { 155 return {}; 156 } 157 158 std::vector<const RefreshRate*> sortedRefreshRates; 159 for (const auto& refreshRate : mRefreshRates) { 160 sortedRefreshRates.push_back(&refreshRate); 161 } 162 std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(), 163 [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) { 164 return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; 165 }); 166 167 // When the configs are ordered by the resync rate, we assume that 168 // the first one is DEFAULT and the second one is PERFORMANCE, 169 // i.e. the higher rate. 170 if (sortedRefreshRates[0]->vsyncPeriod == 0 || 171 sortedRefreshRates[1]->vsyncPeriod == 0) { 172 return {}; 173 } 174 175 return std::pair<int, int>(sortedRefreshRates[0]->configId, 176 sortedRefreshRates[1]->configId); 177 }; 178 179 auto defaultAndPerfConfigs = findDefaultAndPerfConfigs(); 180 if (!defaultAndPerfConfigs) { 181 mRefreshRateSwitchingSupported = false; 182 return; 183 } 184 185 mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first]; 186 mRefreshRateMap[RefreshRateType::PERFORMANCE] = 187 mRefreshRates[defaultAndPerfConfigs->second]; 188 } 189 190 // Whether this device is doing refresh rate switching or not. This must not change after this 191 // object is initialized. 192 bool mRefreshRateSwitchingSupported; 193 // The list of refresh rates, indexed by display config ID. This must not change after this 194 // object is initialized. 195 std::vector<RefreshRate> mRefreshRates; 196 // The mapping of refresh rate type to RefreshRate. This must not change after this object is 197 // initialized. 198 std::map<RefreshRateType, RefreshRate> mRefreshRateMap; 199 // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on 200 // the main thread, and read by the Scheduler (and other objects) on other threads, so it's 201 // atomic. 202 std::atomic<int> mCurrentConfig; 203 }; 204 205 } // namespace scheduler 206 } // namespace android 207