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