blob: 83fa20ef34ac5e27f0c2469f438237043616cb19 [file] [log] [blame]
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -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 */
Ady Abraham2139f732019-11-13 18:56:40 -080016
Ady Abraham8a82ba62020-01-17 12:43:17 -080017// #define LOG_NDEBUG 0
18#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080020#include "RefreshRateConfigs.h"
Ady Abraham8a82ba62020-01-17 12:43:17 -080021#include <android-base/stringprintf.h>
22#include <utils/Trace.h>
23#include <chrono>
24#include <cmath>
25
Ady Abraham5b8afb5a2020-03-06 14:57:26 -080026#undef LOG_TAG
27#define LOG_TAG "RefreshRateConfigs"
28
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080029namespace android::scheduler {
Marin Shalamanov53fc11d2020-11-20 14:00:13 +010030namespace {
31std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
32 return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %.2fHz",
33 layer.name.c_str(),
34 RefreshRateConfigs::layerVoteTypeString(layer.vote).c_str(), weight,
35 toString(layer.seamlessness).c_str(), layer.desiredRefreshRate);
36}
37} // namespace
Ady Abraham2139f732019-11-13 18:56:40 -080038
39using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080040using RefreshRate = RefreshRateConfigs::RefreshRate;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080041
Marin Shalamanov46084422020-10-13 12:33:42 +020042std::string RefreshRate::toString() const {
43 return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
44 getConfigId().value(), hwcConfig->getId(), getFps(),
45 hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup());
46}
47
Ady Abrahama6b676e2020-05-27 14:29:09 -070048std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
49 switch (vote) {
50 case LayerVoteType::NoVote:
51 return "NoVote";
52 case LayerVoteType::Min:
53 return "Min";
54 case LayerVoteType::Max:
55 return "Max";
56 case LayerVoteType::Heuristic:
57 return "Heuristic";
58 case LayerVoteType::ExplicitDefault:
59 return "ExplicitDefault";
60 case LayerVoteType::ExplicitExactOrMultiple:
61 return "ExplicitExactOrMultiple";
62 }
63}
64
Marin Shalamanovb6674e72020-11-06 13:05:57 +010065std::string RefreshRateConfigs::Policy::toString() const {
Marin Shalamanov30b0b3c2020-10-13 19:15:06 +020066 return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
67 ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
68 defaultConfig.value(), allowGroupSwitching, primaryRange.min,
69 primaryRange.max, appRequestRange.min, appRequestRange.max);
70}
71
Ady Abraham4ccdcb42020-02-11 17:34:34 -080072std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
73 nsecs_t displayPeriod) const {
74 auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod);
75 if (displayFramesRem <= MARGIN_FOR_PERIOD_CALCULATION ||
76 std::abs(displayFramesRem - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) {
77 displayFramesQuot++;
78 displayFramesRem = 0;
79 }
80
81 return {displayFramesQuot, displayFramesRem};
82}
83
Steven Thomasbb374322020-04-28 22:47:16 -070084const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
Ady Abrahamdfd62162020-06-10 16:11:56 -070085 const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
86 GlobalSignals* outSignalsConsidered) const {
Ady Abraham8a82ba62020-01-17 12:43:17 -080087 ATRACE_CALL();
Marin Shalamanov46084422020-10-13 12:33:42 +020088 ALOGV("getBestRefreshRate %zu layers", layers.size());
Ady Abraham8a82ba62020-01-17 12:43:17 -080089
Ady Abrahamdfd62162020-06-10 16:11:56 -070090 if (outSignalsConsidered) *outSignalsConsidered = {};
91 const auto setTouchConsidered = [&] {
92 if (outSignalsConsidered) {
93 outSignalsConsidered->touch = true;
94 }
95 };
96
97 const auto setIdleConsidered = [&] {
98 if (outSignalsConsidered) {
99 outSignalsConsidered->idle = true;
100 }
101 };
102
Ady Abraham8a82ba62020-01-17 12:43:17 -0800103 std::lock_guard lock(mLock);
104
105 int noVoteLayers = 0;
106 int minVoteLayers = 0;
107 int maxVoteLayers = 0;
Ady Abraham71c437d2020-01-31 15:56:57 -0800108 int explicitDefaultVoteLayers = 0;
109 int explicitExactOrMultipleVoteLayers = 0;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800110 float maxExplicitWeight = 0;
Marin Shalamanov46084422020-10-13 12:33:42 +0200111 int seamedLayers = 0;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800112 for (const auto& layer : layers) {
Ady Abraham6fb599b2020-03-05 13:48:22 -0800113 if (layer.vote == LayerVoteType::NoVote) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800114 noVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800115 } else if (layer.vote == LayerVoteType::Min) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800116 minVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800117 } else if (layer.vote == LayerVoteType::Max) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800118 maxVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800119 } else if (layer.vote == LayerVoteType::ExplicitDefault) {
Ady Abraham71c437d2020-01-31 15:56:57 -0800120 explicitDefaultVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800121 maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
122 } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
Ady Abraham71c437d2020-01-31 15:56:57 -0800123 explicitExactOrMultipleVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800124 maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
125 }
Marin Shalamanov46084422020-10-13 12:33:42 +0200126
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100127 if (layer.seamlessness == Seamlessness::SeamedAndSeamless) {
Marin Shalamanov46084422020-10-13 12:33:42 +0200128 seamedLayers++;
129 }
Ady Abraham6fb599b2020-03-05 13:48:22 -0800130 }
131
Alec Mouri11232a22020-05-14 18:06:25 -0700132 const bool hasExplicitVoteLayers =
133 explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0;
134
Steven Thomasf734df42020-04-13 21:09:28 -0700135 // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
136 // selected a refresh rate to see if we should apply touch boost.
Ady Abrahamdfd62162020-06-10 16:11:56 -0700137 if (globalSignals.touch && !hasExplicitVoteLayers) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700138 ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
Ady Abrahamdfd62162020-06-10 16:11:56 -0700139 setTouchConsidered();
Steven Thomasf734df42020-04-13 21:09:28 -0700140 return getMaxRefreshRateByPolicyLocked();
Ady Abraham8a82ba62020-01-17 12:43:17 -0800141 }
142
Alec Mouri11232a22020-05-14 18:06:25 -0700143 // If the primary range consists of a single refresh rate then we can only
144 // move out the of range if layers explicitly request a different refresh
145 // rate.
146 const Policy* policy = getCurrentPolicyLocked();
147 const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
148
Ady Abrahamdfd62162020-06-10 16:11:56 -0700149 if (!globalSignals.touch && globalSignals.idle &&
150 !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700151 ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
Ady Abrahamdfd62162020-06-10 16:11:56 -0700152 setIdleConsidered();
Steven Thomasbb374322020-04-28 22:47:16 -0700153 return getMinRefreshRateByPolicyLocked();
154 }
155
Steven Thomasdebafed2020-05-18 17:30:35 -0700156 if (layers.empty() || noVoteLayers == layers.size()) {
157 return getMaxRefreshRateByPolicyLocked();
Steven Thomasbb374322020-04-28 22:47:16 -0700158 }
159
Ady Abraham8a82ba62020-01-17 12:43:17 -0800160 // Only if all layers want Min we should return Min
161 if (noVoteLayers + minVoteLayers == layers.size()) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700162 ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
Steven Thomasf734df42020-04-13 21:09:28 -0700163 return getMinRefreshRateByPolicyLocked();
Ady Abraham8a82ba62020-01-17 12:43:17 -0800164 }
165
Ady Abraham8a82ba62020-01-17 12:43:17 -0800166 // Find the best refresh rate based on score
167 std::vector<std::pair<const RefreshRate*, float>> scores;
Steven Thomasf734df42020-04-13 21:09:28 -0700168 scores.reserve(mAppRequestRefreshRates.size());
Ady Abraham8a82ba62020-01-17 12:43:17 -0800169
Steven Thomasf734df42020-04-13 21:09:28 -0700170 for (const auto refreshRate : mAppRequestRefreshRates) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800171 scores.emplace_back(refreshRate, 0.0f);
172 }
173
Marin Shalamanov46084422020-10-13 12:33:42 +0200174 const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig);
175
Ady Abraham8a82ba62020-01-17 12:43:17 -0800176 for (const auto& layer : layers) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700177 ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
178 layerVoteTypeString(layer.vote).c_str(), layer.weight);
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800179 if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800180 continue;
181 }
182
Ady Abraham71c437d2020-01-31 15:56:57 -0800183 auto weight = layer.weight;
Ady Abraham71c437d2020-01-31 15:56:57 -0800184
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800185 for (auto i = 0u; i < scores.size(); i++) {
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100186 const bool isSeamlessSwitch =
187 scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup();
Marin Shalamanov46084422020-10-13 12:33:42 +0200188
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100189 if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
190 ALOGV("%s ignores %s to avoid non-seamless switch. Current config = %s",
191 formatLayerInfo(layer, weight).c_str(), scores[i].first->toString().c_str(),
192 mCurrentRefreshRate->toString().c_str());
Marin Shalamanov46084422020-10-13 12:33:42 +0200193 continue;
194 }
195
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100196 if (layer.seamlessness == Seamlessness::SeamedAndSeamless && !isSeamlessSwitch &&
197 !layer.focused) {
198 ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
199 " Current config = %s",
200 formatLayerInfo(layer, weight).c_str(), scores[i].first->toString().c_str(),
201 mCurrentRefreshRate->toString().c_str());
202 continue;
203 }
204
205 // Layers with default seamlessness vote for the current config group if
206 // there are layers with seamlessness=SeamedAndSeamless and for the default
207 // config group otherwise. In second case, if the current config group is different
208 // from the default, this means a layer with seamlessness=SeamedAndSeamless has just
209 // disappeared.
210 const bool isInPolicyForDefault = seamedLayers > 0
211 ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup()
212 : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup();
213
214 if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault &&
215 !layer.focused) {
216 ALOGV("%s ignores %s. Current config = %s", formatLayerInfo(layer, weight).c_str(),
217 scores[i].first->toString().c_str(), mCurrentRefreshRate->toString().c_str());
Marin Shalamanov46084422020-10-13 12:33:42 +0200218 continue;
219 }
220
Steven Thomasf734df42020-04-13 21:09:28 -0700221 bool inPrimaryRange =
222 scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
Alec Mouri11232a22020-05-14 18:06:25 -0700223 if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
Ady Abraham20c029c2020-07-06 12:58:05 -0700224 !(layer.focused && layer.vote == LayerVoteType::ExplicitDefault)) {
225 // Only focused layers with ExplicitDefault frame rate settings are allowed to score
Ady Abrahamaae5ed52020-06-26 09:32:43 -0700226 // refresh rates outside the primary range.
Steven Thomasf734df42020-04-13 21:09:28 -0700227 continue;
228 }
229
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800230 // If the layer wants Max, give higher score to the higher refresh rate
231 if (layer.vote == LayerVoteType::Max) {
232 const auto ratio = scores[i].first->fps / scores.back().first->fps;
233 // use ratio^2 to get a lower score the more we get further from peak
234 const auto layerScore = ratio * ratio;
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100235 ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800236 scores[i].first->name.c_str(), layerScore);
237 scores[i].second += weight * layerScore;
238 continue;
Ady Abraham71c437d2020-01-31 15:56:57 -0800239 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800240
Ady Abrahamabc27602020-04-08 17:20:29 -0700241 const auto displayPeriod = scores[i].first->hwcConfig->getVsyncPeriod();
Ady Abrahamdec1a412020-01-24 10:23:50 -0800242 const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800243 if (layer.vote == LayerVoteType::ExplicitDefault) {
244 const auto layerScore = [&]() {
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800245 // Find the actual rate the layer will render, assuming
246 // that layerPeriod is the minimal time to render a frame
247 auto actualLayerPeriod = displayPeriod;
248 int multiplier = 1;
249 while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
250 multiplier++;
251 actualLayerPeriod = displayPeriod * multiplier;
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800252 }
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800253 return std::min(1.0f,
254 static_cast<float>(layerPeriod) /
255 static_cast<float>(actualLayerPeriod));
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800256 }();
257
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100258 ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
259 scores[i].first->name.c_str(), layerScore);
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800260 scores[i].second += weight * layerScore;
261 continue;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800262 }
263
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800264 if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
265 layer.vote == LayerVoteType::Heuristic) {
Ady Abrahamb1b9d412020-06-01 19:53:52 -0700266 const auto layerScore = [&] {
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800267 // Calculate how many display vsyncs we need to present a single frame for this
268 // layer
269 const auto [displayFramesQuot, displayFramesRem] =
270 getDisplayFrames(layerPeriod, displayPeriod);
271 static constexpr size_t MAX_FRAMES_TO_FIT =
272 10; // Stop calculating when score < 0.1
273 if (displayFramesRem == 0) {
274 // Layer desired refresh rate matches the display rate.
275 return 1.0f;
276 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800277
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800278 if (displayFramesQuot == 0) {
279 // Layer desired refresh rate is higher the display rate.
280 return (static_cast<float>(layerPeriod) /
281 static_cast<float>(displayPeriod)) *
282 (1.0f / (MAX_FRAMES_TO_FIT + 1));
283 }
284
285 // Layer desired refresh rate is lower the display rate. Check how well it fits
286 // the cadence
287 auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
288 int iter = 2;
289 while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
290 diff = diff - (displayPeriod - diff);
291 iter++;
292 }
293
294 return 1.0f / iter;
295 }();
Marin Shalamanov46084422020-10-13 12:33:42 +0200296 // Slightly prefer seamless switches.
297 constexpr float kSeamedSwitchPenalty = 0.95f;
298 const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100299 ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
Ady Abrahama6b676e2020-05-27 14:29:09 -0700300 scores[i].first->name.c_str(), layerScore);
Marin Shalamanov46084422020-10-13 12:33:42 +0200301 scores[i].second += weight * layerScore * seamlessness;
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800302 continue;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800303 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800304 }
305 }
306
Ady Abraham34702102020-02-10 14:12:05 -0800307 // Now that we scored all the refresh rates we need to pick the one that got the highest score.
308 // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
309 // or the lower otherwise.
310 const RefreshRate* bestRefreshRate = maxVoteLayers > 0
311 ? getBestRefreshRate(scores.rbegin(), scores.rend())
312 : getBestRefreshRate(scores.begin(), scores.end());
313
Alec Mouri11232a22020-05-14 18:06:25 -0700314 if (primaryRangeIsSingleRate) {
315 // If we never scored any layers, then choose the rate from the primary
316 // range instead of picking a random score from the app range.
317 if (std::all_of(scores.begin(), scores.end(),
318 [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700319 ALOGV("layers not scored - choose %s",
320 getMaxRefreshRateByPolicyLocked().getName().c_str());
Alec Mouri11232a22020-05-14 18:06:25 -0700321 return getMaxRefreshRateByPolicyLocked();
322 } else {
323 return *bestRefreshRate;
324 }
325 }
326
Steven Thomasf734df42020-04-13 21:09:28 -0700327 // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
328 // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
329 // vote we should not change it if we get a touch event. Only apply touch boost if it will
330 // actually increase the refresh rate over the normal selection.
331 const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
Alec Mouri11232a22020-05-14 18:06:25 -0700332
Ady Abrahamdfd62162020-06-10 16:11:56 -0700333 if (globalSignals.touch && explicitDefaultVoteLayers == 0 &&
Steven Thomasf734df42020-04-13 21:09:28 -0700334 bestRefreshRate->fps < touchRefreshRate.fps) {
Ady Abrahamdfd62162020-06-10 16:11:56 -0700335 setTouchConsidered();
Ady Abrahama6b676e2020-05-27 14:29:09 -0700336 ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
Steven Thomasf734df42020-04-13 21:09:28 -0700337 return touchRefreshRate;
338 }
339
Ady Abrahamde7156e2020-02-28 17:29:39 -0800340 return *bestRefreshRate;
Ady Abraham34702102020-02-10 14:12:05 -0800341}
342
343template <typename Iter>
344const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800345 constexpr auto EPSILON = 0.001f;
Ady Abrahamde7156e2020-02-28 17:29:39 -0800346 const RefreshRate* bestRefreshRate = begin->first;
347 float max = begin->second;
Ady Abraham34702102020-02-10 14:12:05 -0800348 for (auto i = begin; i != end; ++i) {
349 const auto [refreshRate, score] = *i;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800350 ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
351
Ady Abrahamdec1a412020-01-24 10:23:50 -0800352 ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
Ady Abraham8a82ba62020-01-17 12:43:17 -0800353
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800354 if (score > max * (1 + EPSILON)) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800355 max = score;
356 bestRefreshRate = refreshRate;
357 }
358 }
359
Ady Abraham34702102020-02-10 14:12:05 -0800360 return bestRefreshRate;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800361}
362
Ady Abraham2139f732019-11-13 18:56:40 -0800363const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
364 return mRefreshRates;
365}
366
367const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
368 std::lock_guard lock(mLock);
Steven Thomasf734df42020-04-13 21:09:28 -0700369 return getMinRefreshRateByPolicyLocked();
370}
371
372const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
Marin Shalamanov46084422020-10-13 12:33:42 +0200373 for (auto refreshRate : mPrimaryRefreshRates) {
374 if (mCurrentRefreshRate->getConfigGroup() == refreshRate->getConfigGroup()) {
375 return *refreshRate;
376 }
377 }
378 ALOGE("Can't find min refresh rate by policy with the same config group"
379 " as the current config %s",
380 mCurrentRefreshRate->toString().c_str());
381 // Defaulting to the lowest refresh rate
Steven Thomasf734df42020-04-13 21:09:28 -0700382 return *mPrimaryRefreshRates.front();
Ady Abraham2139f732019-11-13 18:56:40 -0800383}
384
385const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
386 std::lock_guard lock(mLock);
Steven Thomasf734df42020-04-13 21:09:28 -0700387 return getMaxRefreshRateByPolicyLocked();
388}
389
390const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
Marin Shalamanov46084422020-10-13 12:33:42 +0200391 for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) {
392 const auto& refreshRate = (**it);
393 if (mCurrentRefreshRate->getConfigGroup() == refreshRate.getConfigGroup()) {
394 return refreshRate;
395 }
396 }
397 ALOGE("Can't find max refresh rate by policy with the same config group"
398 " as the current config %s",
399 mCurrentRefreshRate->toString().c_str());
400 // Defaulting to the highest refresh rate
Steven Thomasf734df42020-04-13 21:09:28 -0700401 return *mPrimaryRefreshRates.back();
Ady Abraham2139f732019-11-13 18:56:40 -0800402}
403
404const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
405 std::lock_guard lock(mLock);
406 return *mCurrentRefreshRate;
407}
408
Ana Krulec5d477912020-02-07 12:02:38 -0800409const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
410 std::lock_guard lock(mLock);
Ana Krulec3d367c82020-02-25 15:02:01 -0800411 return getCurrentRefreshRateByPolicyLocked();
412}
413
414const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const {
Steven Thomasf734df42020-04-13 21:09:28 -0700415 if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
416 mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
Ana Krulec5d477912020-02-07 12:02:38 -0800417 return *mCurrentRefreshRate;
418 }
Steven Thomasd4071902020-03-24 16:02:53 -0700419 return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
Ana Krulec5d477912020-02-07 12:02:38 -0800420}
421
Ady Abraham2139f732019-11-13 18:56:40 -0800422void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
423 std::lock_guard lock(mLock);
Ady Abraham2e1dd892020-03-05 13:48:36 -0800424 mCurrentRefreshRate = mRefreshRates.at(configId).get();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800425}
426
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800427RefreshRateConfigs::RefreshRateConfigs(
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800428 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
Ady Abrahamb1b9d412020-06-01 19:53:52 -0700429 HwcConfigIndexType currentConfigId)
430 : mKnownFrameRates(constructKnownFrameRates(configs)) {
Ady Abrahamabc27602020-04-08 17:20:29 -0700431 LOG_ALWAYS_FATAL_IF(configs.empty());
432 LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
433
434 for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
435 const auto& config = configs.at(static_cast<size_t>(configId.value()));
436 const float fps = 1e9f / config->getVsyncPeriod();
437 mRefreshRates.emplace(configId,
438 std::make_unique<RefreshRate>(configId, config,
Marin Shalamanov46084422020-10-13 12:33:42 +0200439 base::StringPrintf("%.2ffps", fps), fps,
Ady Abrahamabc27602020-04-08 17:20:29 -0700440 RefreshRate::ConstructorTag(0)));
441 if (configId == currentConfigId) {
442 mCurrentRefreshRate = mRefreshRates.at(configId).get();
443 }
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800444 }
Ady Abrahamabc27602020-04-08 17:20:29 -0700445
446 std::vector<const RefreshRate*> sortedConfigs;
447 getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
448 mDisplayManagerPolicy.defaultConfig = currentConfigId;
449 mMinSupportedRefreshRate = sortedConfigs.front();
450 mMaxSupportedRefreshRate = sortedConfigs.back();
451 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800452}
453
Steven Thomasd4071902020-03-24 16:02:53 -0700454bool RefreshRateConfigs::isPolicyValid(const Policy& policy) {
455 // defaultConfig must be a valid config, and within the given refresh rate range.
456 auto iter = mRefreshRates.find(policy.defaultConfig);
457 if (iter == mRefreshRates.end()) {
Marin Shalamanovb6674e72020-11-06 13:05:57 +0100458 ALOGE("Default config is not found.");
Steven Thomasd4071902020-03-24 16:02:53 -0700459 return false;
460 }
461 const RefreshRate& refreshRate = *iter->second;
Steven Thomasf734df42020-04-13 21:09:28 -0700462 if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
Marin Shalamanovb6674e72020-11-06 13:05:57 +0100463 ALOGE("Default config is not in the primary range.");
Steven Thomasd4071902020-03-24 16:02:53 -0700464 return false;
465 }
Steven Thomasf734df42020-04-13 21:09:28 -0700466 return policy.appRequestRange.min <= policy.primaryRange.min &&
467 policy.appRequestRange.max >= policy.primaryRange.max;
Steven Thomasd4071902020-03-24 16:02:53 -0700468}
469
470status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
Ady Abraham2139f732019-11-13 18:56:40 -0800471 std::lock_guard lock(mLock);
Steven Thomasd4071902020-03-24 16:02:53 -0700472 if (!isPolicyValid(policy)) {
Marin Shalamanovb6674e72020-11-06 13:05:57 +0100473 ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100474 return BAD_VALUE;
475 }
Steven Thomasd4071902020-03-24 16:02:53 -0700476 Policy previousPolicy = *getCurrentPolicyLocked();
477 mDisplayManagerPolicy = policy;
478 if (*getCurrentPolicyLocked() == previousPolicy) {
479 return CURRENT_POLICY_UNCHANGED;
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100480 }
Ady Abraham2139f732019-11-13 18:56:40 -0800481 constructAvailableRefreshRates();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100482 return NO_ERROR;
483}
484
Steven Thomasd4071902020-03-24 16:02:53 -0700485status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100486 std::lock_guard lock(mLock);
Steven Thomasd4071902020-03-24 16:02:53 -0700487 if (policy && !isPolicyValid(*policy)) {
488 return BAD_VALUE;
489 }
490 Policy previousPolicy = *getCurrentPolicyLocked();
491 mOverridePolicy = policy;
492 if (*getCurrentPolicyLocked() == previousPolicy) {
493 return CURRENT_POLICY_UNCHANGED;
494 }
495 constructAvailableRefreshRates();
496 return NO_ERROR;
497}
498
499const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const {
500 return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy;
501}
502
503RefreshRateConfigs::Policy RefreshRateConfigs::getCurrentPolicy() const {
504 std::lock_guard lock(mLock);
505 return *getCurrentPolicyLocked();
506}
507
508RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const {
509 std::lock_guard lock(mLock);
510 return mDisplayManagerPolicy;
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100511}
512
513bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
514 std::lock_guard lock(mLock);
Steven Thomasf734df42020-04-13 21:09:28 -0700515 for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100516 if (refreshRate->configId == config) {
517 return true;
518 }
519 }
520 return false;
Ady Abraham2139f732019-11-13 18:56:40 -0800521}
522
523void RefreshRateConfigs::getSortedRefreshRateList(
524 const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
525 std::vector<const RefreshRate*>* outRefreshRates) {
526 outRefreshRates->clear();
527 outRefreshRates->reserve(mRefreshRates.size());
528 for (const auto& [type, refreshRate] : mRefreshRates) {
Ady Abraham2e1dd892020-03-05 13:48:36 -0800529 if (shouldAddRefreshRate(*refreshRate)) {
Ady Abraham2139f732019-11-13 18:56:40 -0800530 ALOGV("getSortedRefreshRateList: config %d added to list policy",
Ady Abraham2e1dd892020-03-05 13:48:36 -0800531 refreshRate->configId.value());
532 outRefreshRates->push_back(refreshRate.get());
Ady Abraham2139f732019-11-13 18:56:40 -0800533 }
534 }
535
536 std::sort(outRefreshRates->begin(), outRefreshRates->end(),
537 [](const auto refreshRate1, const auto refreshRate2) {
Ady Abrahamabc27602020-04-08 17:20:29 -0700538 if (refreshRate1->hwcConfig->getVsyncPeriod() !=
539 refreshRate2->hwcConfig->getVsyncPeriod()) {
540 return refreshRate1->hwcConfig->getVsyncPeriod() >
541 refreshRate2->hwcConfig->getVsyncPeriod();
Steven Thomasd4071902020-03-24 16:02:53 -0700542 } else {
Ady Abrahamabc27602020-04-08 17:20:29 -0700543 return refreshRate1->hwcConfig->getConfigGroup() >
544 refreshRate2->hwcConfig->getConfigGroup();
Steven Thomasd4071902020-03-24 16:02:53 -0700545 }
Ady Abraham2139f732019-11-13 18:56:40 -0800546 });
547}
548
549void RefreshRateConfigs::constructAvailableRefreshRates() {
550 // Filter configs based on current policy and sort based on vsync period
Steven Thomasd4071902020-03-24 16:02:53 -0700551 const Policy* policy = getCurrentPolicyLocked();
Ady Abrahamabc27602020-04-08 17:20:29 -0700552 const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
Steven Thomasf734df42020-04-13 21:09:28 -0700553 ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
554 " appRequestRange=[%.2f %.2f]",
555 policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
556 policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);
Ady Abrahamabc27602020-04-08 17:20:29 -0700557
Steven Thomasf734df42020-04-13 21:09:28 -0700558 auto filterRefreshRates = [&](float min, float max, const char* listName,
559 std::vector<const RefreshRate*>* outRefreshRates) {
560 getSortedRefreshRateList(
561 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
562 const auto& hwcConfig = refreshRate.hwcConfig;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800563
Steven Thomasf734df42020-04-13 21:09:28 -0700564 return hwcConfig->getHeight() == defaultConfig->getHeight() &&
565 hwcConfig->getWidth() == defaultConfig->getWidth() &&
566 hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
567 hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
568 (policy->allowGroupSwitching ||
569 hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
570 refreshRate.inPolicy(min, max);
571 },
572 outRefreshRates);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800573
Steven Thomasf734df42020-04-13 21:09:28 -0700574 LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
575 "No matching configs for %s range: min=%.0f max=%.0f", listName, min,
576 max);
577 auto stringifyRefreshRates = [&]() -> std::string {
578 std::string str;
579 for (auto refreshRate : *outRefreshRates) {
580 base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
581 }
582 return str;
583 };
584 ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
585 };
586
587 filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
588 &mPrimaryRefreshRates);
589 filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
590 &mAppRequestRefreshRates);
Ady Abraham2139f732019-11-13 18:56:40 -0800591}
592
Ady Abrahamb1b9d412020-06-01 19:53:52 -0700593std::vector<float> RefreshRateConfigs::constructKnownFrameRates(
594 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
595 std::vector<float> knownFrameRates = {24.0f, 30.0f, 45.0f, 60.0f, 72.0f};
596 knownFrameRates.reserve(knownFrameRates.size() + configs.size());
597
598 // Add all supported refresh rates to the set
599 for (const auto& config : configs) {
600 const auto refreshRate = 1e9f / config->getVsyncPeriod();
601 knownFrameRates.emplace_back(refreshRate);
602 }
603
604 // Sort and remove duplicates
605 const auto frameRatesEqual = [](float a, float b) { return std::abs(a - b) <= 0.01f; };
606 std::sort(knownFrameRates.begin(), knownFrameRates.end());
607 knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
608 frameRatesEqual),
609 knownFrameRates.end());
610 return knownFrameRates;
611}
612
613float RefreshRateConfigs::findClosestKnownFrameRate(float frameRate) const {
614 if (frameRate <= *mKnownFrameRates.begin()) {
615 return *mKnownFrameRates.begin();
616 }
617
618 if (frameRate >= *std::prev(mKnownFrameRates.end())) {
619 return *std::prev(mKnownFrameRates.end());
620 }
621
622 auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate);
623
624 const auto distance1 = std::abs(frameRate - *lowerBound);
625 const auto distance2 = std::abs(frameRate - *std::prev(lowerBound));
626 return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
627}
628
Ana Krulecb9afd792020-06-11 13:16:15 -0700629RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const {
630 std::lock_guard lock(mLock);
631 const auto& deviceMin = getMinRefreshRate();
632 const auto& minByPolicy = getMinRefreshRateByPolicyLocked();
633 const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked();
634
635 // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
636 // the min allowed refresh rate is higher than the device min, we do not want to enable the
637 // timer.
638 if (deviceMin < minByPolicy) {
639 return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
640 }
641 if (minByPolicy == maxByPolicy) {
642 // Do not sent the call to toggle off kernel idle timer if the device min and policy min and
643 // max are all the same. This saves us extra unnecessary calls to sysprop.
644 if (deviceMin == minByPolicy) {
645 return RefreshRateConfigs::KernelIdleTimerAction::NoChange;
646 }
647 return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
648 }
649 // Turn on the timer in all other cases.
650 return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
651}
652
Ady Abraham62f216c2020-10-13 19:07:23 -0700653void RefreshRateConfigs::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
654 if (frameRateOverride.frameRateHz > 0 && frameRateOverride.frameRateHz < 1) {
Ady Abraham0bb6a472020-10-12 10:22:13 -0700655 return;
656 }
657
658 std::lock_guard lock(mLock);
Ady Abraham62f216c2020-10-13 19:07:23 -0700659 if (frameRateOverride.frameRateHz != 0) {
660 mPreferredRefreshRateForUid[frameRateOverride.uid] = frameRateOverride.frameRateHz;
Ady Abraham0bb6a472020-10-12 10:22:13 -0700661 } else {
Ady Abraham62f216c2020-10-13 19:07:23 -0700662 mPreferredRefreshRateForUid.erase(frameRateOverride.uid);
Ady Abraham0bb6a472020-10-12 10:22:13 -0700663 }
664}
665
666int RefreshRateConfigs::getRefreshRateDividerForUid(uid_t uid) const {
Ady Abraham0bb6a472020-10-12 10:22:13 -0700667 std::lock_guard lock(mLock);
668
669 const auto iter = mPreferredRefreshRateForUid.find(uid);
670 if (iter == mPreferredRefreshRateForUid.end()) {
671 return 1;
672 }
673
Ady Abraham62f216c2020-10-13 19:07:23 -0700674 // This calculation needs to be in sync with the java code
675 // in DisplayManagerService.getDisplayInfoForFrameRateOverride
676 constexpr float kThreshold = 0.1f;
Ady Abraham0bb6a472020-10-12 10:22:13 -0700677 const auto refreshRateHz = iter->second;
678 const auto numPeriods = mCurrentRefreshRate->getFps() / refreshRateHz;
679 const auto numPeriodsRounded = std::round(numPeriods);
680 if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
681 return 1;
682 }
683
Ady Abraham62f216c2020-10-13 19:07:23 -0700684 return static_cast<int>(numPeriodsRounded);
685}
686
687std::vector<FrameRateOverride> RefreshRateConfigs::getFrameRateOverrides() {
688 std::lock_guard lock(mLock);
689 std::vector<FrameRateOverride> overrides;
690 overrides.reserve(mPreferredRefreshRateForUid.size());
691
692 for (const auto [uid, frameRate] : mPreferredRefreshRateForUid) {
693 overrides.emplace_back(FrameRateOverride{uid, frameRate});
694 }
695
696 return overrides;
Ady Abraham0bb6a472020-10-12 10:22:13 -0700697}
698
Marin Shalamanovba421a82020-11-10 21:49:26 +0100699void RefreshRateConfigs::dump(std::string& result) const {
700 std::lock_guard lock(mLock);
701 base::StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): %s\n\n",
702 mDisplayManagerPolicy.toString().c_str());
703 scheduler::RefreshRateConfigs::Policy currentPolicy = *getCurrentPolicyLocked();
704 if (mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
705 base::StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): %s\n\n",
706 currentPolicy.toString().c_str());
707 }
708
709 auto config = mCurrentRefreshRate->hwcConfig;
710 base::StringAppendF(&result, "Current config: %s\n", mCurrentRefreshRate->toString().c_str());
711
712 result.append("Refresh rates:\n");
713 for (const auto& [id, refreshRate] : mRefreshRates) {
714 config = refreshRate->hwcConfig;
715 base::StringAppendF(&result, "\t%s\n", refreshRate->toString().c_str());
716 }
717
718 result.append("\n");
719}
720
Ady Abraham2139f732019-11-13 18:56:40 -0800721} // namespace android::scheduler