blob: 0646c7dfd5f479e3073cc721a889fa432b6e34d1 [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 {
Ady Abraham2139f732019-11-13 18:56:40 -080030
31using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080032using RefreshRate = RefreshRateConfigs::RefreshRate;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080033
Marin Shalamanov46084422020-10-13 12:33:42 +020034std::string RefreshRate::toString() const {
35 return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
36 getConfigId().value(), hwcConfig->getId(), getFps(),
37 hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup());
38}
39
Ady Abrahama6b676e2020-05-27 14:29:09 -070040std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
41 switch (vote) {
42 case LayerVoteType::NoVote:
43 return "NoVote";
44 case LayerVoteType::Min:
45 return "Min";
46 case LayerVoteType::Max:
47 return "Max";
48 case LayerVoteType::Heuristic:
49 return "Heuristic";
50 case LayerVoteType::ExplicitDefault:
51 return "ExplicitDefault";
52 case LayerVoteType::ExplicitExactOrMultiple:
53 return "ExplicitExactOrMultiple";
54 }
55}
56
Marin Shalamanovb6674e72020-11-06 13:05:57 +010057std::string RefreshRateConfigs::Policy::toString() const {
Marin Shalamanov30b0b3c2020-10-13 19:15:06 +020058 return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
59 ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
60 defaultConfig.value(), allowGroupSwitching, primaryRange.min,
61 primaryRange.max, appRequestRange.min, appRequestRange.max);
62}
63
Ady Abraham8a82ba62020-01-17 12:43:17 -080064const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
65 const std::vector<LayerRequirement>& layers) const {
Ady Abraham2139f732019-11-13 18:56:40 -080066 std::lock_guard lock(mLock);
Ady Abrahamdec1a412020-01-24 10:23:50 -080067 int contentFramerate = 0;
68 int explicitContentFramerate = 0;
Ady Abraham8a82ba62020-01-17 12:43:17 -080069 for (const auto& layer : layers) {
Ady Abrahamdec1a412020-01-24 10:23:50 -080070 const auto desiredRefreshRateRound = round<int>(layer.desiredRefreshRate);
Ady Abraham71c437d2020-01-31 15:56:57 -080071 if (layer.vote == LayerVoteType::ExplicitDefault ||
72 layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
Ady Abrahamdec1a412020-01-24 10:23:50 -080073 if (desiredRefreshRateRound > explicitContentFramerate) {
74 explicitContentFramerate = desiredRefreshRateRound;
Ady Abraham8a82ba62020-01-17 12:43:17 -080075 }
76 } else {
Ady Abrahamdec1a412020-01-24 10:23:50 -080077 if (desiredRefreshRateRound > contentFramerate) {
78 contentFramerate = desiredRefreshRateRound;
Ady Abraham8a82ba62020-01-17 12:43:17 -080079 }
80 }
81 }
82
Ady Abrahamdec1a412020-01-24 10:23:50 -080083 if (explicitContentFramerate != 0) {
Ady Abraham8a82ba62020-01-17 12:43:17 -080084 contentFramerate = explicitContentFramerate;
Ady Abrahamdec1a412020-01-24 10:23:50 -080085 } else if (contentFramerate == 0) {
Ady Abrahamabc27602020-04-08 17:20:29 -070086 contentFramerate = round<int>(mMaxSupportedRefreshRate->getFps());
Ady Abraham8a82ba62020-01-17 12:43:17 -080087 }
Ady Abraham8a82ba62020-01-17 12:43:17 -080088 ATRACE_INT("ContentFPS", contentFramerate);
89
Ady Abraham2139f732019-11-13 18:56:40 -080090 // Find the appropriate refresh rate with minimal error
Steven Thomasf734df42020-04-13 21:09:28 -070091 auto iter = min_element(mPrimaryRefreshRates.cbegin(), mPrimaryRefreshRates.cend(),
Ady Abraham2139f732019-11-13 18:56:40 -080092 [contentFramerate](const auto& lhs, const auto& rhs) -> bool {
93 return std::abs(lhs->fps - contentFramerate) <
94 std::abs(rhs->fps - contentFramerate);
95 });
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080096
Ady Abraham2139f732019-11-13 18:56:40 -080097 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
98 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
99 // align well with both
100 const RefreshRate* bestSoFar = *iter;
101 constexpr float MARGIN = 0.05f;
102 float ratio = (*iter)->fps / contentFramerate;
103 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
Steven Thomasf734df42020-04-13 21:09:28 -0700104 while (iter != mPrimaryRefreshRates.cend()) {
Ady Abraham2139f732019-11-13 18:56:40 -0800105 ratio = (*iter)->fps / contentFramerate;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800106
Ady Abraham2139f732019-11-13 18:56:40 -0800107 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
108 bestSoFar = *iter;
109 break;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800110 }
Ady Abraham2139f732019-11-13 18:56:40 -0800111 ++iter;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800112 }
113 }
114
Ady Abraham2139f732019-11-13 18:56:40 -0800115 return *bestSoFar;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800116}
117
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800118std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
119 nsecs_t displayPeriod) const {
120 auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod);
121 if (displayFramesRem <= MARGIN_FOR_PERIOD_CALCULATION ||
122 std::abs(displayFramesRem - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) {
123 displayFramesQuot++;
124 displayFramesRem = 0;
125 }
126
127 return {displayFramesQuot, displayFramesRem};
128}
129
Steven Thomasbb374322020-04-28 22:47:16 -0700130const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
Ady Abrahamdfd62162020-06-10 16:11:56 -0700131 const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
132 GlobalSignals* outSignalsConsidered) const {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800133 ATRACE_CALL();
Marin Shalamanov46084422020-10-13 12:33:42 +0200134 ALOGV("getBestRefreshRate %zu layers", layers.size());
Ady Abraham8a82ba62020-01-17 12:43:17 -0800135
Ady Abrahamdfd62162020-06-10 16:11:56 -0700136 if (outSignalsConsidered) *outSignalsConsidered = {};
137 const auto setTouchConsidered = [&] {
138 if (outSignalsConsidered) {
139 outSignalsConsidered->touch = true;
140 }
141 };
142
143 const auto setIdleConsidered = [&] {
144 if (outSignalsConsidered) {
145 outSignalsConsidered->idle = true;
146 }
147 };
148
Ady Abraham8a82ba62020-01-17 12:43:17 -0800149 std::lock_guard lock(mLock);
150
151 int noVoteLayers = 0;
152 int minVoteLayers = 0;
153 int maxVoteLayers = 0;
Ady Abraham71c437d2020-01-31 15:56:57 -0800154 int explicitDefaultVoteLayers = 0;
155 int explicitExactOrMultipleVoteLayers = 0;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800156 float maxExplicitWeight = 0;
Marin Shalamanov46084422020-10-13 12:33:42 +0200157 int seamedLayers = 0;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800158 for (const auto& layer : layers) {
Ady Abraham6fb599b2020-03-05 13:48:22 -0800159 if (layer.vote == LayerVoteType::NoVote) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800160 noVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800161 } else if (layer.vote == LayerVoteType::Min) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800162 minVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800163 } else if (layer.vote == LayerVoteType::Max) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800164 maxVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800165 } else if (layer.vote == LayerVoteType::ExplicitDefault) {
Ady Abraham71c437d2020-01-31 15:56:57 -0800166 explicitDefaultVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800167 maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
168 } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
Ady Abraham71c437d2020-01-31 15:56:57 -0800169 explicitExactOrMultipleVoteLayers++;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800170 maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
171 }
Marin Shalamanov46084422020-10-13 12:33:42 +0200172
173 if (!layer.shouldBeSeamless) {
174 seamedLayers++;
175 }
Ady Abraham6fb599b2020-03-05 13:48:22 -0800176 }
177
Alec Mouri11232a22020-05-14 18:06:25 -0700178 const bool hasExplicitVoteLayers =
179 explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0;
180
Steven Thomasf734df42020-04-13 21:09:28 -0700181 // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
182 // selected a refresh rate to see if we should apply touch boost.
Ady Abrahamdfd62162020-06-10 16:11:56 -0700183 if (globalSignals.touch && !hasExplicitVoteLayers) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700184 ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
Ady Abrahamdfd62162020-06-10 16:11:56 -0700185 setTouchConsidered();
Steven Thomasf734df42020-04-13 21:09:28 -0700186 return getMaxRefreshRateByPolicyLocked();
Ady Abraham8a82ba62020-01-17 12:43:17 -0800187 }
188
Alec Mouri11232a22020-05-14 18:06:25 -0700189 // If the primary range consists of a single refresh rate then we can only
190 // move out the of range if layers explicitly request a different refresh
191 // rate.
192 const Policy* policy = getCurrentPolicyLocked();
193 const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
194
Ady Abrahamdfd62162020-06-10 16:11:56 -0700195 if (!globalSignals.touch && globalSignals.idle &&
196 !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700197 ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
Ady Abrahamdfd62162020-06-10 16:11:56 -0700198 setIdleConsidered();
Steven Thomasbb374322020-04-28 22:47:16 -0700199 return getMinRefreshRateByPolicyLocked();
200 }
201
Steven Thomasdebafed2020-05-18 17:30:35 -0700202 if (layers.empty() || noVoteLayers == layers.size()) {
203 return getMaxRefreshRateByPolicyLocked();
Steven Thomasbb374322020-04-28 22:47:16 -0700204 }
205
Ady Abraham8a82ba62020-01-17 12:43:17 -0800206 // Only if all layers want Min we should return Min
207 if (noVoteLayers + minVoteLayers == layers.size()) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700208 ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
Steven Thomasf734df42020-04-13 21:09:28 -0700209 return getMinRefreshRateByPolicyLocked();
Ady Abraham8a82ba62020-01-17 12:43:17 -0800210 }
211
Ady Abraham8a82ba62020-01-17 12:43:17 -0800212 // Find the best refresh rate based on score
213 std::vector<std::pair<const RefreshRate*, float>> scores;
Steven Thomasf734df42020-04-13 21:09:28 -0700214 scores.reserve(mAppRequestRefreshRates.size());
Ady Abraham8a82ba62020-01-17 12:43:17 -0800215
Steven Thomasf734df42020-04-13 21:09:28 -0700216 for (const auto refreshRate : mAppRequestRefreshRates) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800217 scores.emplace_back(refreshRate, 0.0f);
218 }
219
Marin Shalamanov46084422020-10-13 12:33:42 +0200220 const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig);
221
Ady Abraham8a82ba62020-01-17 12:43:17 -0800222 for (const auto& layer : layers) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700223 ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
224 layerVoteTypeString(layer.vote).c_str(), layer.weight);
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800225 if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800226 continue;
227 }
228
Ady Abraham71c437d2020-01-31 15:56:57 -0800229 auto weight = layer.weight;
Ady Abraham71c437d2020-01-31 15:56:57 -0800230
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800231 for (auto i = 0u; i < scores.size(); i++) {
Marin Shalamanov46084422020-10-13 12:33:42 +0200232 // If there are no layers with shouldBeSeamless=false and the current
233 // config group is different from the default one, this means a layer with
234 // shouldBeSeamless=false has just disappeared and we should switch back to
235 // the default config group.
236 const bool isSeamlessSwitch = seamedLayers > 0
237 ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup()
238 : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup();
239
240 if (layer.shouldBeSeamless && !isSeamlessSwitch) {
241 ALOGV("%s (weight %.2f) ignores %s (group=%d) to avoid non-seamless switch."
242 "Current config = %s",
243 layer.name.c_str(), weight, scores[i].first->name.c_str(),
244 scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str());
245 continue;
246 }
247
248 if (!layer.shouldBeSeamless && !isSeamlessSwitch && !layer.focused) {
249 ALOGV("%s (weight %.2f) ignores %s (group=%d) because it's not focused"
250 " and the switch is going to be seamed. Current config = %s",
251 layer.name.c_str(), weight, scores[i].first->name.c_str(),
252 scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str());
253 continue;
254 }
255
Steven Thomasf734df42020-04-13 21:09:28 -0700256 bool inPrimaryRange =
257 scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
Alec Mouri11232a22020-05-14 18:06:25 -0700258 if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
Ady Abraham20c029c2020-07-06 12:58:05 -0700259 !(layer.focused && layer.vote == LayerVoteType::ExplicitDefault)) {
260 // Only focused layers with ExplicitDefault frame rate settings are allowed to score
Ady Abrahamaae5ed52020-06-26 09:32:43 -0700261 // refresh rates outside the primary range.
Steven Thomasf734df42020-04-13 21:09:28 -0700262 continue;
263 }
264
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800265 // If the layer wants Max, give higher score to the higher refresh rate
266 if (layer.vote == LayerVoteType::Max) {
267 const auto ratio = scores[i].first->fps / scores.back().first->fps;
268 // use ratio^2 to get a lower score the more we get further from peak
269 const auto layerScore = ratio * ratio;
270 ALOGV("%s (Max, weight %.2f) gives %s score of %.2f", layer.name.c_str(), weight,
271 scores[i].first->name.c_str(), layerScore);
272 scores[i].second += weight * layerScore;
273 continue;
Ady Abraham71c437d2020-01-31 15:56:57 -0800274 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800275
Ady Abrahamabc27602020-04-08 17:20:29 -0700276 const auto displayPeriod = scores[i].first->hwcConfig->getVsyncPeriod();
Ady Abrahamdec1a412020-01-24 10:23:50 -0800277 const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800278 if (layer.vote == LayerVoteType::ExplicitDefault) {
279 const auto layerScore = [&]() {
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800280 // Find the actual rate the layer will render, assuming
281 // that layerPeriod is the minimal time to render a frame
282 auto actualLayerPeriod = displayPeriod;
283 int multiplier = 1;
284 while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
285 multiplier++;
286 actualLayerPeriod = displayPeriod * multiplier;
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800287 }
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800288 return std::min(1.0f,
289 static_cast<float>(layerPeriod) /
290 static_cast<float>(actualLayerPeriod));
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800291 }();
292
293 ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f",
294 layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(),
295 layerScore);
296 scores[i].second += weight * layerScore;
297 continue;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800298 }
299
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800300 if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
301 layer.vote == LayerVoteType::Heuristic) {
Ady Abrahamb1b9d412020-06-01 19:53:52 -0700302 const auto layerScore = [&] {
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800303 // Calculate how many display vsyncs we need to present a single frame for this
304 // layer
305 const auto [displayFramesQuot, displayFramesRem] =
306 getDisplayFrames(layerPeriod, displayPeriod);
307 static constexpr size_t MAX_FRAMES_TO_FIT =
308 10; // Stop calculating when score < 0.1
309 if (displayFramesRem == 0) {
310 // Layer desired refresh rate matches the display rate.
311 return 1.0f;
312 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800313
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800314 if (displayFramesQuot == 0) {
315 // Layer desired refresh rate is higher the display rate.
316 return (static_cast<float>(layerPeriod) /
317 static_cast<float>(displayPeriod)) *
318 (1.0f / (MAX_FRAMES_TO_FIT + 1));
319 }
320
321 // Layer desired refresh rate is lower the display rate. Check how well it fits
322 // the cadence
323 auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
324 int iter = 2;
325 while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
326 diff = diff - (displayPeriod - diff);
327 iter++;
328 }
329
330 return 1.0f / iter;
331 }();
Marin Shalamanov46084422020-10-13 12:33:42 +0200332 // Slightly prefer seamless switches.
333 constexpr float kSeamedSwitchPenalty = 0.95f;
334 const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
Ady Abrahama6b676e2020-05-27 14:29:09 -0700335 ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
336 layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod,
337 scores[i].first->name.c_str(), layerScore);
Marin Shalamanov46084422020-10-13 12:33:42 +0200338 scores[i].second += weight * layerScore * seamlessness;
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800339 continue;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800340 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800341 }
342 }
343
Ady Abraham34702102020-02-10 14:12:05 -0800344 // Now that we scored all the refresh rates we need to pick the one that got the highest score.
345 // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
346 // or the lower otherwise.
347 const RefreshRate* bestRefreshRate = maxVoteLayers > 0
348 ? getBestRefreshRate(scores.rbegin(), scores.rend())
349 : getBestRefreshRate(scores.begin(), scores.end());
350
Alec Mouri11232a22020-05-14 18:06:25 -0700351 if (primaryRangeIsSingleRate) {
352 // If we never scored any layers, then choose the rate from the primary
353 // range instead of picking a random score from the app range.
354 if (std::all_of(scores.begin(), scores.end(),
355 [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
Ady Abrahama6b676e2020-05-27 14:29:09 -0700356 ALOGV("layers not scored - choose %s",
357 getMaxRefreshRateByPolicyLocked().getName().c_str());
Alec Mouri11232a22020-05-14 18:06:25 -0700358 return getMaxRefreshRateByPolicyLocked();
359 } else {
360 return *bestRefreshRate;
361 }
362 }
363
Steven Thomasf734df42020-04-13 21:09:28 -0700364 // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
365 // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
366 // vote we should not change it if we get a touch event. Only apply touch boost if it will
367 // actually increase the refresh rate over the normal selection.
368 const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
Alec Mouri11232a22020-05-14 18:06:25 -0700369
Ady Abrahamdfd62162020-06-10 16:11:56 -0700370 if (globalSignals.touch && explicitDefaultVoteLayers == 0 &&
Steven Thomasf734df42020-04-13 21:09:28 -0700371 bestRefreshRate->fps < touchRefreshRate.fps) {
Ady Abrahamdfd62162020-06-10 16:11:56 -0700372 setTouchConsidered();
Ady Abrahama6b676e2020-05-27 14:29:09 -0700373 ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
Steven Thomasf734df42020-04-13 21:09:28 -0700374 return touchRefreshRate;
375 }
376
Ady Abrahamde7156e2020-02-28 17:29:39 -0800377 return *bestRefreshRate;
Ady Abraham34702102020-02-10 14:12:05 -0800378}
379
380template <typename Iter>
381const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800382 constexpr auto EPSILON = 0.001f;
Ady Abrahamde7156e2020-02-28 17:29:39 -0800383 const RefreshRate* bestRefreshRate = begin->first;
384 float max = begin->second;
Ady Abraham34702102020-02-10 14:12:05 -0800385 for (auto i = begin; i != end; ++i) {
386 const auto [refreshRate, score] = *i;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800387 ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
388
Ady Abrahamdec1a412020-01-24 10:23:50 -0800389 ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
Ady Abraham8a82ba62020-01-17 12:43:17 -0800390
Ady Abraham5b8afb5a2020-03-06 14:57:26 -0800391 if (score > max * (1 + EPSILON)) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800392 max = score;
393 bestRefreshRate = refreshRate;
394 }
395 }
396
Ady Abraham34702102020-02-10 14:12:05 -0800397 return bestRefreshRate;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800398}
399
Ady Abraham2139f732019-11-13 18:56:40 -0800400const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
401 return mRefreshRates;
402}
403
404const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
405 std::lock_guard lock(mLock);
Steven Thomasf734df42020-04-13 21:09:28 -0700406 return getMinRefreshRateByPolicyLocked();
407}
408
409const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
Marin Shalamanov46084422020-10-13 12:33:42 +0200410 for (auto refreshRate : mPrimaryRefreshRates) {
411 if (mCurrentRefreshRate->getConfigGroup() == refreshRate->getConfigGroup()) {
412 return *refreshRate;
413 }
414 }
415 ALOGE("Can't find min refresh rate by policy with the same config group"
416 " as the current config %s",
417 mCurrentRefreshRate->toString().c_str());
418 // Defaulting to the lowest refresh rate
Steven Thomasf734df42020-04-13 21:09:28 -0700419 return *mPrimaryRefreshRates.front();
Ady Abraham2139f732019-11-13 18:56:40 -0800420}
421
422const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
423 std::lock_guard lock(mLock);
Steven Thomasf734df42020-04-13 21:09:28 -0700424 return getMaxRefreshRateByPolicyLocked();
425}
426
427const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
Marin Shalamanov46084422020-10-13 12:33:42 +0200428 for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) {
429 const auto& refreshRate = (**it);
430 if (mCurrentRefreshRate->getConfigGroup() == refreshRate.getConfigGroup()) {
431 return refreshRate;
432 }
433 }
434 ALOGE("Can't find max refresh rate by policy with the same config group"
435 " as the current config %s",
436 mCurrentRefreshRate->toString().c_str());
437 // Defaulting to the highest refresh rate
Steven Thomasf734df42020-04-13 21:09:28 -0700438 return *mPrimaryRefreshRates.back();
Ady Abraham2139f732019-11-13 18:56:40 -0800439}
440
441const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
442 std::lock_guard lock(mLock);
443 return *mCurrentRefreshRate;
444}
445
Ana Krulec5d477912020-02-07 12:02:38 -0800446const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
447 std::lock_guard lock(mLock);
Ana Krulec3d367c82020-02-25 15:02:01 -0800448 return getCurrentRefreshRateByPolicyLocked();
449}
450
451const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const {
Steven Thomasf734df42020-04-13 21:09:28 -0700452 if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
453 mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
Ana Krulec5d477912020-02-07 12:02:38 -0800454 return *mCurrentRefreshRate;
455 }
Steven Thomasd4071902020-03-24 16:02:53 -0700456 return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
Ana Krulec5d477912020-02-07 12:02:38 -0800457}
458
Ady Abraham2139f732019-11-13 18:56:40 -0800459void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
460 std::lock_guard lock(mLock);
Ady Abraham2e1dd892020-03-05 13:48:36 -0800461 mCurrentRefreshRate = mRefreshRates.at(configId).get();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800462}
463
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800464RefreshRateConfigs::RefreshRateConfigs(
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800465 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
Ady Abrahamb1b9d412020-06-01 19:53:52 -0700466 HwcConfigIndexType currentConfigId)
467 : mKnownFrameRates(constructKnownFrameRates(configs)) {
Ady Abrahamabc27602020-04-08 17:20:29 -0700468 LOG_ALWAYS_FATAL_IF(configs.empty());
469 LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
470
471 for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
472 const auto& config = configs.at(static_cast<size_t>(configId.value()));
473 const float fps = 1e9f / config->getVsyncPeriod();
474 mRefreshRates.emplace(configId,
475 std::make_unique<RefreshRate>(configId, config,
Marin Shalamanov46084422020-10-13 12:33:42 +0200476 base::StringPrintf("%.2ffps", fps), fps,
Ady Abrahamabc27602020-04-08 17:20:29 -0700477 RefreshRate::ConstructorTag(0)));
478 if (configId == currentConfigId) {
479 mCurrentRefreshRate = mRefreshRates.at(configId).get();
480 }
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800481 }
Ady Abrahamabc27602020-04-08 17:20:29 -0700482
483 std::vector<const RefreshRate*> sortedConfigs;
484 getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
485 mDisplayManagerPolicy.defaultConfig = currentConfigId;
486 mMinSupportedRefreshRate = sortedConfigs.front();
487 mMaxSupportedRefreshRate = sortedConfigs.back();
488 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800489}
490
Steven Thomasd4071902020-03-24 16:02:53 -0700491bool RefreshRateConfigs::isPolicyValid(const Policy& policy) {
492 // defaultConfig must be a valid config, and within the given refresh rate range.
493 auto iter = mRefreshRates.find(policy.defaultConfig);
494 if (iter == mRefreshRates.end()) {
Marin Shalamanovb6674e72020-11-06 13:05:57 +0100495 ALOGE("Default config is not found.");
Steven Thomasd4071902020-03-24 16:02:53 -0700496 return false;
497 }
498 const RefreshRate& refreshRate = *iter->second;
Steven Thomasf734df42020-04-13 21:09:28 -0700499 if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
Marin Shalamanovb6674e72020-11-06 13:05:57 +0100500 ALOGE("Default config is not in the primary range.");
Steven Thomasd4071902020-03-24 16:02:53 -0700501 return false;
502 }
Steven Thomasf734df42020-04-13 21:09:28 -0700503 return policy.appRequestRange.min <= policy.primaryRange.min &&
504 policy.appRequestRange.max >= policy.primaryRange.max;
Steven Thomasd4071902020-03-24 16:02:53 -0700505}
506
507status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
Ady Abraham2139f732019-11-13 18:56:40 -0800508 std::lock_guard lock(mLock);
Steven Thomasd4071902020-03-24 16:02:53 -0700509 if (!isPolicyValid(policy)) {
Marin Shalamanovb6674e72020-11-06 13:05:57 +0100510 ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100511 return BAD_VALUE;
512 }
Steven Thomasd4071902020-03-24 16:02:53 -0700513 Policy previousPolicy = *getCurrentPolicyLocked();
514 mDisplayManagerPolicy = policy;
515 if (*getCurrentPolicyLocked() == previousPolicy) {
516 return CURRENT_POLICY_UNCHANGED;
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100517 }
Ady Abraham2139f732019-11-13 18:56:40 -0800518 constructAvailableRefreshRates();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100519 return NO_ERROR;
520}
521
Steven Thomasd4071902020-03-24 16:02:53 -0700522status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100523 std::lock_guard lock(mLock);
Steven Thomasd4071902020-03-24 16:02:53 -0700524 if (policy && !isPolicyValid(*policy)) {
525 return BAD_VALUE;
526 }
527 Policy previousPolicy = *getCurrentPolicyLocked();
528 mOverridePolicy = policy;
529 if (*getCurrentPolicyLocked() == previousPolicy) {
530 return CURRENT_POLICY_UNCHANGED;
531 }
532 constructAvailableRefreshRates();
533 return NO_ERROR;
534}
535
536const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const {
537 return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy;
538}
539
540RefreshRateConfigs::Policy RefreshRateConfigs::getCurrentPolicy() const {
541 std::lock_guard lock(mLock);
542 return *getCurrentPolicyLocked();
543}
544
545RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const {
546 std::lock_guard lock(mLock);
547 return mDisplayManagerPolicy;
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100548}
549
550bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
551 std::lock_guard lock(mLock);
Steven Thomasf734df42020-04-13 21:09:28 -0700552 for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100553 if (refreshRate->configId == config) {
554 return true;
555 }
556 }
557 return false;
Ady Abraham2139f732019-11-13 18:56:40 -0800558}
559
560void RefreshRateConfigs::getSortedRefreshRateList(
561 const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
562 std::vector<const RefreshRate*>* outRefreshRates) {
563 outRefreshRates->clear();
564 outRefreshRates->reserve(mRefreshRates.size());
565 for (const auto& [type, refreshRate] : mRefreshRates) {
Ady Abraham2e1dd892020-03-05 13:48:36 -0800566 if (shouldAddRefreshRate(*refreshRate)) {
Ady Abraham2139f732019-11-13 18:56:40 -0800567 ALOGV("getSortedRefreshRateList: config %d added to list policy",
Ady Abraham2e1dd892020-03-05 13:48:36 -0800568 refreshRate->configId.value());
569 outRefreshRates->push_back(refreshRate.get());
Ady Abraham2139f732019-11-13 18:56:40 -0800570 }
571 }
572
573 std::sort(outRefreshRates->begin(), outRefreshRates->end(),
574 [](const auto refreshRate1, const auto refreshRate2) {
Ady Abrahamabc27602020-04-08 17:20:29 -0700575 if (refreshRate1->hwcConfig->getVsyncPeriod() !=
576 refreshRate2->hwcConfig->getVsyncPeriod()) {
577 return refreshRate1->hwcConfig->getVsyncPeriod() >
578 refreshRate2->hwcConfig->getVsyncPeriod();
Steven Thomasd4071902020-03-24 16:02:53 -0700579 } else {
Ady Abrahamabc27602020-04-08 17:20:29 -0700580 return refreshRate1->hwcConfig->getConfigGroup() >
581 refreshRate2->hwcConfig->getConfigGroup();
Steven Thomasd4071902020-03-24 16:02:53 -0700582 }
Ady Abraham2139f732019-11-13 18:56:40 -0800583 });
584}
585
586void RefreshRateConfigs::constructAvailableRefreshRates() {
587 // Filter configs based on current policy and sort based on vsync period
Steven Thomasd4071902020-03-24 16:02:53 -0700588 const Policy* policy = getCurrentPolicyLocked();
Ady Abrahamabc27602020-04-08 17:20:29 -0700589 const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
Steven Thomasf734df42020-04-13 21:09:28 -0700590 ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
591 " appRequestRange=[%.2f %.2f]",
592 policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
593 policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);
Ady Abrahamabc27602020-04-08 17:20:29 -0700594
Steven Thomasf734df42020-04-13 21:09:28 -0700595 auto filterRefreshRates = [&](float min, float max, const char* listName,
596 std::vector<const RefreshRate*>* outRefreshRates) {
597 getSortedRefreshRateList(
598 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
599 const auto& hwcConfig = refreshRate.hwcConfig;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800600
Steven Thomasf734df42020-04-13 21:09:28 -0700601 return hwcConfig->getHeight() == defaultConfig->getHeight() &&
602 hwcConfig->getWidth() == defaultConfig->getWidth() &&
603 hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
604 hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
605 (policy->allowGroupSwitching ||
606 hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
607 refreshRate.inPolicy(min, max);
608 },
609 outRefreshRates);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800610
Steven Thomasf734df42020-04-13 21:09:28 -0700611 LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
612 "No matching configs for %s range: min=%.0f max=%.0f", listName, min,
613 max);
614 auto stringifyRefreshRates = [&]() -> std::string {
615 std::string str;
616 for (auto refreshRate : *outRefreshRates) {
617 base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
618 }
619 return str;
620 };
621 ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
622 };
623
624 filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
625 &mPrimaryRefreshRates);
626 filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
627 &mAppRequestRefreshRates);
Ady Abraham2139f732019-11-13 18:56:40 -0800628}
629
Ady Abrahamb1b9d412020-06-01 19:53:52 -0700630std::vector<float> RefreshRateConfigs::constructKnownFrameRates(
631 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
632 std::vector<float> knownFrameRates = {24.0f, 30.0f, 45.0f, 60.0f, 72.0f};
633 knownFrameRates.reserve(knownFrameRates.size() + configs.size());
634
635 // Add all supported refresh rates to the set
636 for (const auto& config : configs) {
637 const auto refreshRate = 1e9f / config->getVsyncPeriod();
638 knownFrameRates.emplace_back(refreshRate);
639 }
640
641 // Sort and remove duplicates
642 const auto frameRatesEqual = [](float a, float b) { return std::abs(a - b) <= 0.01f; };
643 std::sort(knownFrameRates.begin(), knownFrameRates.end());
644 knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
645 frameRatesEqual),
646 knownFrameRates.end());
647 return knownFrameRates;
648}
649
650float RefreshRateConfigs::findClosestKnownFrameRate(float frameRate) const {
651 if (frameRate <= *mKnownFrameRates.begin()) {
652 return *mKnownFrameRates.begin();
653 }
654
655 if (frameRate >= *std::prev(mKnownFrameRates.end())) {
656 return *std::prev(mKnownFrameRates.end());
657 }
658
659 auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate);
660
661 const auto distance1 = std::abs(frameRate - *lowerBound);
662 const auto distance2 = std::abs(frameRate - *std::prev(lowerBound));
663 return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
664}
665
Ana Krulecb9afd792020-06-11 13:16:15 -0700666RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const {
667 std::lock_guard lock(mLock);
668 const auto& deviceMin = getMinRefreshRate();
669 const auto& minByPolicy = getMinRefreshRateByPolicyLocked();
670 const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked();
671
672 // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
673 // the min allowed refresh rate is higher than the device min, we do not want to enable the
674 // timer.
675 if (deviceMin < minByPolicy) {
676 return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
677 }
678 if (minByPolicy == maxByPolicy) {
679 // Do not sent the call to toggle off kernel idle timer if the device min and policy min and
680 // max are all the same. This saves us extra unnecessary calls to sysprop.
681 if (deviceMin == minByPolicy) {
682 return RefreshRateConfigs::KernelIdleTimerAction::NoChange;
683 }
684 return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
685 }
686 // Turn on the timer in all other cases.
687 return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
688}
689
Ady Abraham0bb6a472020-10-12 10:22:13 -0700690void RefreshRateConfigs::setPreferredRefreshRateForUid(uid_t uid, float refreshRateHz) {
691 if (refreshRateHz > 0 && refreshRateHz < 1) {
692 return;
693 }
694
695 std::lock_guard lock(mLock);
696 if (refreshRateHz != 0) {
697 mPreferredRefreshRateForUid[uid] = refreshRateHz;
698 } else {
699 mPreferredRefreshRateForUid.erase(uid);
700 }
701}
702
703int RefreshRateConfigs::getRefreshRateDividerForUid(uid_t uid) const {
704 constexpr float kThreshold = 0.1f;
705 std::lock_guard lock(mLock);
706
707 const auto iter = mPreferredRefreshRateForUid.find(uid);
708 if (iter == mPreferredRefreshRateForUid.end()) {
709 return 1;
710 }
711
712 const auto refreshRateHz = iter->second;
713 const auto numPeriods = mCurrentRefreshRate->getFps() / refreshRateHz;
714 const auto numPeriodsRounded = std::round(numPeriods);
715 if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
716 return 1;
717 }
718
719 return static_cast<int>(numPeriods);
720}
721
Ady Abraham2139f732019-11-13 18:56:40 -0800722} // namespace android::scheduler