blob: 2fd100f876419a8d076275fc09e8ee39e8d2541c [file] [log] [blame]
Ana Krulecb43429d2019-01-09 14:28:51 -08001/*
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
Dominik Laskowski98041832019-08-01 18:35:59 -070019#include <android-base/stringprintf.h>
20
Ana Krulecb43429d2019-01-09 14:28:51 -080021#include <algorithm>
22#include <numeric>
Dominik Laskowski98041832019-08-01 18:35:59 -070023#include <type_traits>
Ana Krulecb43429d2019-01-09 14:28:51 -080024
Ana Krulec4593b692019-01-11 22:07:25 -080025#include "DisplayHardware/HWComposer.h"
26#include "Scheduler/SchedulerUtils.h"
27
Dominik Laskowski98041832019-08-01 18:35:59 -070028namespace android::scheduler {
29
30enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 };
31
32inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateConfigEvent rhs) {
33 using T = std::underlying_type_t<RefreshRateConfigEvent>;
34 return static_cast<RefreshRateConfigEvent>(static_cast<T>(lhs) | static_cast<T>(rhs));
35}
Ana Krulecb43429d2019-01-09 14:28:51 -080036
37/**
Ady Abraham1902d072019-03-01 17:18:59 -080038 * This class is used to encapsulate configuration for refresh rates. It holds information
Ana Krulecb43429d2019-01-09 14:28:51 -080039 * about available refresh rates on the device, and the mapping between the numbers and human
40 * readable names.
41 */
42class RefreshRateConfigs {
43public:
Steven Thomas2bbaabe2019-08-28 16:08:35 -070044 // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance
Ana Krulecb43429d2019-01-09 14:28:51 -080045 // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
Steven Thomas2bbaabe2019-08-28 16:08:35 -070046 enum class RefreshRateType { DEFAULT, PERFORMANCE };
Ana Krulecb43429d2019-01-09 14:28:51 -080047
48 struct RefreshRate {
Ana Krulecb43429d2019-01-09 14:28:51 -080049 // This config ID corresponds to the position of the config in the vector that is stored
50 // on the device.
51 int configId;
52 // Human readable name of the refresh rate.
53 std::string name;
Alec Mourifb571ea2019-01-24 18:42:10 -080054 // Refresh rate in frames per second, rounded to the nearest integer.
55 uint32_t fps = 0;
Steven Thomas2bbaabe2019-08-28 16:08:35 -070056 // Vsync period in nanoseconds.
57 nsecs_t vsyncPeriod;
58 // Hwc config Id (returned from HWC2::Display::Config::getId())
59 hwc2_config_t hwcId;
Ana Krulecb43429d2019-01-09 14:28:51 -080060 };
61
Steven Thomas2bbaabe2019-08-28 16:08:35 -070062 // Returns true if this device is doing refresh rate switching. This won't change at runtime.
63 bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; }
64
65 // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access
66 // from multiple threads. This can only be called if refreshRateSwitching() returns true.
Ana Krulecb43429d2019-01-09 14:28:51 -080067 // TODO(b/122916473): Get this information from configs prepared by vendors, instead of
68 // baking them in.
Steven Thomas2bbaabe2019-08-28 16:08:35 -070069 const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const {
70 LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported);
71 return mRefreshRateMap;
Alec Mouri0a1cc962019-03-14 12:33:02 -070072 }
Ana Krulecb43429d2019-01-09 14:28:51 -080073
Steven Thomas2bbaabe2019-08-28 16:08:35 -070074 const RefreshRate& getRefreshRateFromType(RefreshRateType type) const {
75 if (!mRefreshRateSwitchingSupported) {
76 return getCurrentRefreshRate().second;
77 } else {
78 auto refreshRate = mRefreshRateMap.find(type);
79 LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end());
80 return refreshRate->second;
81 }
82 }
83
84 std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const {
85 int currentConfig = mCurrentConfig;
86 if (mRefreshRateSwitchingSupported) {
87 for (const auto& [type, refresh] : mRefreshRateMap) {
88 if (refresh.configId == currentConfig) {
89 return {type, refresh};
90 }
91 }
92 LOG_ALWAYS_FATAL();
93 }
94 return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]};
95 }
96
97 const RefreshRate& getRefreshRateFromConfigId(int configId) const {
98 LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size());
99 return mRefreshRates[configId];
100 }
101
102 RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const {
103 if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT;
104
105 for (const auto& [type, refreshRate] : mRefreshRateMap) {
106 if (refreshRate.hwcId == hwcId) {
Ady Abraham796beb02019-04-11 15:23:07 -0700107 return type;
108 }
109 }
110
111 return RefreshRateType::DEFAULT;
112 }
113
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700114 void setCurrentConfig(int config) {
115 LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size());
116 mCurrentConfig = config;
117 }
Dominik Laskowski22488f62019-03-28 09:53:04 -0700118
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700119 struct InputConfig {
120 hwc2_config_t hwcId = 0;
121 nsecs_t vsyncPeriod = 0;
122 };
Ana Krulec4593b692019-01-11 22:07:25 -0800123
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700124 RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
125 int currentConfig) {
126 init(refreshRateSwitching, configs, currentConfig);
127 }
128
129 RefreshRateConfigs(bool refreshRateSwitching,
130 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
131 int currentConfig) {
132 std::vector<InputConfig> inputConfigs;
133 for (const auto& config : configs) {
134 inputConfigs.push_back({config->getId(), config->getVsyncPeriod()});
Ana Krulec4593b692019-01-11 22:07:25 -0800135 }
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700136 init(refreshRateSwitching, inputConfigs, currentConfig);
Ana Krulec4593b692019-01-11 22:07:25 -0800137 }
138
Dominik Laskowski22488f62019-03-28 09:53:04 -0700139private:
Steven Thomas2bbaabe2019-08-28 16:08:35 -0700140 void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
141 int currentConfig) {
142 mRefreshRateSwitchingSupported = refreshRateSwitching;
143 LOG_ALWAYS_FATAL_IF(configs.empty());
144 LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size());
145 mCurrentConfig = currentConfig;
146
147 auto buildRefreshRate = [&](int configId) -> RefreshRate {
148 const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod;
149 const float fps = 1e9 / vsyncPeriod;
150 return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps),
151 vsyncPeriod, configs[configId].hwcId};
152 };
153
154 for (int i = 0; i < configs.size(); ++i) {
155 mRefreshRates.push_back(buildRefreshRate(i));
156 }
157
158 if (!mRefreshRateSwitchingSupported) return;
159
160 auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> {
161 if (configs.size() < 2) {
162 return {};
163 }
164
165 std::vector<const RefreshRate*> sortedRefreshRates;
166 for (const auto& refreshRate : mRefreshRates) {
167 sortedRefreshRates.push_back(&refreshRate);
168 }
169 std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(),
170 [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) {
171 return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
172 });
173
174 // When the configs are ordered by the resync rate, we assume that
175 // the first one is DEFAULT and the second one is PERFORMANCE,
176 // i.e. the higher rate.
177 if (sortedRefreshRates[0]->vsyncPeriod == 0 ||
178 sortedRefreshRates[1]->vsyncPeriod == 0) {
179 return {};
180 }
181
182 return std::pair<int, int>(sortedRefreshRates[0]->configId,
183 sortedRefreshRates[1]->configId);
184 };
185
186 auto defaultAndPerfConfigs = findDefaultAndPerfConfigs();
187 if (!defaultAndPerfConfigs) {
188 mRefreshRateSwitchingSupported = false;
189 return;
190 }
191
192 mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first];
193 mRefreshRateMap[RefreshRateType::PERFORMANCE] =
194 mRefreshRates[defaultAndPerfConfigs->second];
195 }
196
197 // Whether this device is doing refresh rate switching or not. This must not change after this
198 // object is initialized.
199 bool mRefreshRateSwitchingSupported;
200 // The list of refresh rates, indexed by display config ID. This must not change after this
201 // object is initialized.
202 std::vector<RefreshRate> mRefreshRates;
203 // The mapping of refresh rate type to RefreshRate. This must not change after this object is
204 // initialized.
205 std::map<RefreshRateType, RefreshRate> mRefreshRateMap;
206 // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on
207 // the main thread, and read by the Scheduler (and other objects) on other threads, so it's
208 // atomic.
209 std::atomic<int> mCurrentConfig;
Ana Krulecb43429d2019-01-09 14:28:51 -0800210};
211
Dominik Laskowski98041832019-08-01 18:35:59 -0700212} // namespace android::scheduler