blob: 30483a2aff4df2049be0c4857b5ec3d49f5de8de [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
Marin Shalamanovbed7fd32020-12-21 20:02:20 +010020// TODO(b/129481165): remove the #pragma below and fix conversion issues
21#pragma clang diagnostic push
22#pragma clang diagnostic ignored "-Wextra"
23
Ady Abraham8a82ba62020-01-17 12:43:17 -080024#include <chrono>
25#include <cmath>
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070026
27#include <android-base/properties.h>
28#include <android-base/stringprintf.h>
29#include <ftl/enum.h>
Dominik Laskowskif8734e02022-08-26 09:06:59 -070030#include <ftl/fake_guard.h>
Dominik Laskowski36dced82022-09-02 09:24:00 -070031#include <ftl/match.h>
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070032#include <utils/Trace.h>
33
Ady Abraham4899ff82021-01-06 13:53:29 -080034#include "../SurfaceFlingerProperties.h"
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070035#include "RefreshRateConfigs.h"
Ady Abraham8a82ba62020-01-17 12:43:17 -080036
Ady Abraham5b8afb5a2020-03-06 14:57:26 -080037#undef LOG_TAG
38#define LOG_TAG "RefreshRateConfigs"
39
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080040namespace android::scheduler {
Marin Shalamanov53fc11d2020-11-20 14:00:13 +010041namespace {
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070042
Dominik Laskowskib0054a22022-03-03 09:03:06 -080043struct RefreshRateScore {
44 DisplayModeIterator modeIt;
Ady Abrahamae2e3c72022-08-13 05:12:13 +000045 float overallScore;
46 struct {
Ady Abraham62f51d92022-08-24 22:20:22 +000047 float modeBelowThreshold;
48 float modeAboveThreshold;
49 } fixedRateBelowThresholdLayersScore;
Dominik Laskowskib0054a22022-03-03 09:03:06 -080050};
51
Dominik Laskowskia8626ec2021-12-15 18:13:30 -080052constexpr RefreshRateConfigs::GlobalSignals kNoSignals;
53
Marin Shalamanov53fc11d2020-11-20 14:00:13 +010054std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -080055 return base::StringPrintf("%s (type=%s, weight=%.2f, seamlessness=%s) %s", layer.name.c_str(),
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070056 ftl::enum_string(layer.vote).c_str(), weight,
57 ftl::enum_string(layer.seamlessness).c_str(),
Marin Shalamanove8a663d2020-11-24 17:48:00 +010058 to_string(layer.desiredRefreshRate).c_str());
Marin Shalamanov53fc11d2020-11-20 14:00:13 +010059}
Marin Shalamanoveadf2e72020-12-10 15:35:28 +010060
Marin Shalamanova7fe3042021-01-29 21:02:08 +010061std::vector<Fps> constructKnownFrameRates(const DisplayModes& modes) {
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070062 std::vector<Fps> knownFrameRates = {24_Hz, 30_Hz, 45_Hz, 60_Hz, 72_Hz};
Marin Shalamanova7fe3042021-01-29 21:02:08 +010063 knownFrameRates.reserve(knownFrameRates.size() + modes.size());
Marin Shalamanoveadf2e72020-12-10 15:35:28 +010064
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070065 // Add all supported refresh rates.
Dominik Laskowskib0054a22022-03-03 09:03:06 -080066 for (const auto& [id, mode] : modes) {
67 knownFrameRates.push_back(mode->getFps());
Marin Shalamanoveadf2e72020-12-10 15:35:28 +010068 }
69
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070070 // Sort and remove duplicates.
71 std::sort(knownFrameRates.begin(), knownFrameRates.end(), isStrictlyLess);
Marin Shalamanoveadf2e72020-12-10 15:35:28 +010072 knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070073 isApproxEqual),
Marin Shalamanoveadf2e72020-12-10 15:35:28 +010074 knownFrameRates.end());
75 return knownFrameRates;
76}
77
Dominik Laskowskib0054a22022-03-03 09:03:06 -080078// The Filter is a `bool(const DisplayMode&)` predicate.
79template <typename Filter>
80std::vector<DisplayModeIterator> sortByRefreshRate(const DisplayModes& modes, Filter&& filter) {
81 std::vector<DisplayModeIterator> sortedModes;
82 sortedModes.reserve(modes.size());
Ady Abraham2139f732019-11-13 18:56:40 -080083
Dominik Laskowskib0054a22022-03-03 09:03:06 -080084 for (auto it = modes.begin(); it != modes.end(); ++it) {
85 const auto& [id, mode] = *it;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080086
Dominik Laskowskib0054a22022-03-03 09:03:06 -080087 if (filter(*mode)) {
88 ALOGV("%s: including mode %d", __func__, id.value());
89 sortedModes.push_back(it);
90 }
91 }
92
93 std::sort(sortedModes.begin(), sortedModes.end(), [](auto it1, auto it2) {
94 const auto& mode1 = it1->second;
95 const auto& mode2 = it2->second;
96
97 if (mode1->getVsyncPeriod() == mode2->getVsyncPeriod()) {
98 return mode1->getGroup() > mode2->getGroup();
99 }
100
101 return mode1->getVsyncPeriod() > mode2->getVsyncPeriod();
102 });
103
104 return sortedModes;
Marin Shalamanov46084422020-10-13 12:33:42 +0200105}
106
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800107bool canModesSupportFrameRateOverride(const std::vector<DisplayModeIterator>& sortedModes) {
108 for (const auto it1 : sortedModes) {
109 const auto& mode1 = it1->second;
110 for (const auto it2 : sortedModes) {
111 const auto& mode2 = it2->second;
112
113 if (RefreshRateConfigs::getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) {
114 return true;
115 }
116 }
117 }
118 return false;
119}
120
Dominik Laskowski36dced82022-09-02 09:24:00 -0700121std::string toString(const RefreshRateConfigs::PolicyVariant& policy) {
122 using namespace std::string_literals;
123
124 return ftl::match(
125 policy,
126 [](const RefreshRateConfigs::DisplayManagerPolicy& policy) {
127 return "DisplayManagerPolicy"s + policy.toString();
128 },
129 [](const RefreshRateConfigs::OverridePolicy& policy) {
130 return "OverridePolicy"s + policy.toString();
131 },
132 [](RefreshRateConfigs::NoOverridePolicy) { return "NoOverridePolicy"s; });
133}
134
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800135} // namespace
136
ramindanid72ba162022-09-09 21:33:40 +0000137struct RefreshRateConfigs::RefreshRateScoreComparator {
138 bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const {
139 const auto& [modeIt, overallScore, _] = lhs;
140
141 std::string name = to_string(modeIt->second->getFps());
142 ALOGV("%s sorting scores %.2f", name.c_str(), overallScore);
143
144 ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));
145
146 constexpr float kEpsilon = 0.0001f;
147 if (std::abs(overallScore - rhs.overallScore) > kEpsilon) {
148 return overallScore > rhs.overallScore;
149 }
150
151 // If overallScore tie we will pick the higher refresh rate if
152 // high refresh rate is the priority else the lower refresh rate.
153 if (refreshRateOrder == RefreshRateOrder::Descending) {
154 using fps_approx_ops::operator>;
155 return modeIt->second->getFps() > rhs.modeIt->second->getFps();
156 } else {
157 using fps_approx_ops::operator<;
158 return modeIt->second->getFps() < rhs.modeIt->second->getFps();
159 }
160 }
161
162 const RefreshRateOrder refreshRateOrder;
163};
164
Marin Shalamanovb6674e72020-11-06 13:05:57 +0100165std::string RefreshRateConfigs::Policy::toString() const {
Dominik Laskowski0acc3842022-04-07 11:23:42 -0700166 return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
167 ", primaryRange=%s, appRequestRange=%s}",
168 defaultMode.value(), allowGroupSwitching ? "true" : "false",
Dominik Laskowski953b7fd2022-01-08 19:34:59 -0800169 to_string(primaryRange).c_str(), to_string(appRequestRange).c_str());
Marin Shalamanov30b0b3c2020-10-13 19:15:06 +0200170}
171
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800172std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
173 nsecs_t displayPeriod) const {
Ady Abraham62a0be22020-12-08 16:54:10 -0800174 auto [quotient, remainder] = std::div(layerPeriod, displayPeriod);
175 if (remainder <= MARGIN_FOR_PERIOD_CALCULATION ||
176 std::abs(remainder - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) {
177 quotient++;
178 remainder = 0;
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800179 }
180
Ady Abraham62a0be22020-12-08 16:54:10 -0800181 return {quotient, remainder};
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800182}
183
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800184float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer,
185 Fps refreshRate) const {
Marin Shalamanov15a0fc62021-08-16 18:20:21 +0200186 constexpr float kScoreForFractionalPairs = .8f;
187
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800188 const auto displayPeriod = refreshRate.getPeriodNsecs();
Ady Abraham62a0be22020-12-08 16:54:10 -0800189 const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
190 if (layer.vote == LayerVoteType::ExplicitDefault) {
191 // Find the actual rate the layer will render, assuming
Marin Shalamanov15a0fc62021-08-16 18:20:21 +0200192 // that layerPeriod is the minimal period to render a frame.
193 // For example if layerPeriod is 20ms and displayPeriod is 16ms,
194 // then the actualLayerPeriod will be 32ms, because it is the
195 // smallest multiple of the display period which is >= layerPeriod.
Ady Abraham62a0be22020-12-08 16:54:10 -0800196 auto actualLayerPeriod = displayPeriod;
197 int multiplier = 1;
198 while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
199 multiplier++;
200 actualLayerPeriod = displayPeriod * multiplier;
201 }
Marin Shalamanov15a0fc62021-08-16 18:20:21 +0200202
203 // Because of the threshold we used above it's possible that score is slightly
204 // above 1.
Ady Abraham62a0be22020-12-08 16:54:10 -0800205 return std::min(1.0f,
206 static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
207 }
208
209 if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
210 layer.vote == LayerVoteType::Heuristic) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800211 if (isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) {
Ady Abraham05243be2021-09-16 15:58:52 -0700212 return kScoreForFractionalPairs;
Marin Shalamanov15a0fc62021-08-16 18:20:21 +0200213 }
214
Ady Abraham62a0be22020-12-08 16:54:10 -0800215 // Calculate how many display vsyncs we need to present a single frame for this
216 // layer
217 const auto [displayFramesQuotient, displayFramesRemainder] =
218 getDisplayFrames(layerPeriod, displayPeriod);
219 static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
220 if (displayFramesRemainder == 0) {
221 // Layer desired refresh rate matches the display rate.
Ady Abraham05243be2021-09-16 15:58:52 -0700222 return 1.0f;
Ady Abraham62a0be22020-12-08 16:54:10 -0800223 }
224
225 if (displayFramesQuotient == 0) {
226 // Layer desired refresh rate is higher than the display rate.
227 return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
228 (1.0f / (MAX_FRAMES_TO_FIT + 1));
229 }
230
231 // Layer desired refresh rate is lower than the display rate. Check how well it fits
232 // the cadence.
233 auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder));
234 int iter = 2;
235 while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
236 diff = diff - (displayPeriod - diff);
237 iter++;
238 }
239
Ady Abraham05243be2021-09-16 15:58:52 -0700240 return (1.0f / iter);
241 }
242
243 return 0;
244}
245
ramindanid72ba162022-09-09 21:33:40 +0000246float RefreshRateConfigs::calculateRefreshRateScoreForFps(Fps refreshRate) const {
247 const float ratio =
248 refreshRate.getValue() / mAppRequestRefreshRates.back()->second->getFps().getValue();
249 // Use ratio^2 to get a lower score the more we get further from peak
250 return ratio * ratio;
251}
252
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800253float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
Ady Abraham05243be2021-09-16 15:58:52 -0700254 bool isSeamlessSwitch) const {
Ady Abraham05243be2021-09-16 15:58:52 -0700255 // Slightly prefer seamless switches.
256 constexpr float kSeamedSwitchPenalty = 0.95f;
257 const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
258
259 // If the layer wants Max, give higher score to the higher refresh rate
260 if (layer.vote == LayerVoteType::Max) {
ramindanid72ba162022-09-09 21:33:40 +0000261 return calculateRefreshRateScoreForFps(refreshRate);
Ady Abraham62a0be22020-12-08 16:54:10 -0800262 }
263
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800264 if (layer.vote == LayerVoteType::ExplicitExact) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800265 const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate);
Andy Yu2ae6b6b2021-11-18 14:51:06 -0800266 if (mSupportsFrameRateOverrideByContent) {
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800267 // Since we support frame rate override, allow refresh rates which are
268 // multiples of the layer's request, as those apps would be throttled
269 // down to run at the desired refresh rate.
Ady Abrahamcc315492022-02-17 17:06:39 -0800270 return divisor > 0;
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800271 }
272
Ady Abrahamcc315492022-02-17 17:06:39 -0800273 return divisor == 1;
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800274 }
275
Ady Abrahamcc315492022-02-17 17:06:39 -0800276 // If the layer frame rate is a divisor of the refresh rate it should score
Ady Abraham05243be2021-09-16 15:58:52 -0700277 // the highest score.
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800278 if (getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) {
Ady Abraham05243be2021-09-16 15:58:52 -0700279 return 1.0f * seamlessness;
280 }
281
Ady Abrahamcc315492022-02-17 17:06:39 -0800282 // The layer frame rate is not a divisor of the refresh rate,
Ady Abraham05243be2021-09-16 15:58:52 -0700283 // there is a small penalty attached to the score to favor the frame rates
284 // the exactly matches the display refresh rate or a multiple.
Ady Abraham1c595502022-01-13 21:58:32 -0800285 constexpr float kNonExactMatchingPenalty = 0.95f;
Ady Abraham05243be2021-09-16 15:58:52 -0700286 return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness *
287 kNonExactMatchingPenalty;
Ady Abraham62a0be22020-12-08 16:54:10 -0800288}
289
ramindanid72ba162022-09-09 21:33:40 +0000290auto RefreshRateConfigs::getRankedRefreshRates(const std::vector<LayerRequirement>& layers,
291 GlobalSignals signals) const
292 -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
Marin Shalamanov4c7831e2021-06-08 20:44:06 +0200293 std::lock_guard lock(mLock);
294
ramindanid72ba162022-09-09 21:33:40 +0000295 if (mGetRankedRefreshRatesCache &&
296 mGetRankedRefreshRatesCache->arguments == std::make_pair(layers, signals)) {
297 return mGetRankedRefreshRatesCache->result;
Marin Shalamanov4c7831e2021-06-08 20:44:06 +0200298 }
299
ramindanid72ba162022-09-09 21:33:40 +0000300 const auto result = getRankedRefreshRatesLocked(layers, signals);
301 mGetRankedRefreshRatesCache = GetRankedRefreshRatesCache{{layers, signals}, result};
Marin Shalamanov4c7831e2021-06-08 20:44:06 +0200302 return result;
303}
304
ramindanid72ba162022-09-09 21:33:40 +0000305auto RefreshRateConfigs::getRankedRefreshRatesLocked(const std::vector<LayerRequirement>& layers,
306 GlobalSignals signals) const
307 -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000308 using namespace fps_approx_ops;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800309 ATRACE_CALL();
Dominik Laskowskia8626ec2021-12-15 18:13:30 -0800310 ALOGV("%s: %zu layers", __func__, layers.size());
Ady Abrahamdfd62162020-06-10 16:11:56 -0700311
ramindani38c84982022-08-29 18:02:57 +0000312 const auto& activeMode = *getActiveModeItLocked()->second;
313
314 // Keep the display at max refresh rate for the duration of powering on the display.
315 if (signals.powerOnImminent) {
316 ALOGV("Power On Imminent");
Ady Abraham37d46922022-10-05 13:08:51 -0700317 return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending,
318 /*preferredDisplayModeOpt*/ std::nullopt),
ramindanid72ba162022-09-09 21:33:40 +0000319 GlobalSignals{.powerOnImminent = true}};
ramindani38c84982022-08-29 18:02:57 +0000320 }
321
Ady Abraham8a82ba62020-01-17 12:43:17 -0800322 int noVoteLayers = 0;
323 int minVoteLayers = 0;
324 int maxVoteLayers = 0;
Ady Abraham71c437d2020-01-31 15:56:57 -0800325 int explicitDefaultVoteLayers = 0;
326 int explicitExactOrMultipleVoteLayers = 0;
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800327 int explicitExact = 0;
Marin Shalamanovae0b5352021-03-24 12:56:08 +0100328 int seamedFocusedLayers = 0;
Dominik Laskowskia8626ec2021-12-15 18:13:30 -0800329
Ady Abraham8a82ba62020-01-17 12:43:17 -0800330 for (const auto& layer : layers) {
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800331 switch (layer.vote) {
332 case LayerVoteType::NoVote:
333 noVoteLayers++;
334 break;
335 case LayerVoteType::Min:
336 minVoteLayers++;
337 break;
338 case LayerVoteType::Max:
339 maxVoteLayers++;
340 break;
341 case LayerVoteType::ExplicitDefault:
342 explicitDefaultVoteLayers++;
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800343 break;
344 case LayerVoteType::ExplicitExactOrMultiple:
345 explicitExactOrMultipleVoteLayers++;
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800346 break;
347 case LayerVoteType::ExplicitExact:
348 explicitExact++;
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800349 break;
350 case LayerVoteType::Heuristic:
351 break;
Ady Abraham6fb599b2020-03-05 13:48:22 -0800352 }
Marin Shalamanov46084422020-10-13 12:33:42 +0200353
Marin Shalamanovae0b5352021-03-24 12:56:08 +0100354 if (layer.seamlessness == Seamlessness::SeamedAndSeamless && layer.focused) {
355 seamedFocusedLayers++;
Marin Shalamanov46084422020-10-13 12:33:42 +0200356 }
Ady Abraham6fb599b2020-03-05 13:48:22 -0800357 }
358
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800359 const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 ||
360 explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0;
Alec Mouri11232a22020-05-14 18:06:25 -0700361
Marin Shalamanov8cd8a992021-09-14 23:22:49 +0200362 const Policy* policy = getCurrentPolicyLocked();
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800363 const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700364
Marin Shalamanov8cd8a992021-09-14 23:22:49 +0200365 // If the default mode group is different from the group of current mode,
366 // this means a layer requesting a seamed mode switch just disappeared and
367 // we should switch back to the default group.
368 // However if a seamed layer is still present we anchor around the group
369 // of the current mode, in order to prevent unnecessary seamed mode switches
370 // (e.g. when pausing a video playback).
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800371 const auto anchorGroup =
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700372 seamedFocusedLayers > 0 ? activeMode.getGroup() : defaultMode->getGroup();
Marin Shalamanov8cd8a992021-09-14 23:22:49 +0200373
Steven Thomasf734df42020-04-13 21:09:28 -0700374 // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
375 // selected a refresh rate to see if we should apply touch boost.
Dominik Laskowskia8626ec2021-12-15 18:13:30 -0800376 if (signals.touch && !hasExplicitVoteLayers) {
ramindanid72ba162022-09-09 21:33:40 +0000377 ALOGV("Touch Boost");
Ady Abraham37d46922022-10-05 13:08:51 -0700378 return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
379 /*preferredDisplayModeOpt*/ std::nullopt),
ramindanid72ba162022-09-09 21:33:40 +0000380 GlobalSignals{.touch = true}};
Ady Abraham8a82ba62020-01-17 12:43:17 -0800381 }
382
Alec Mouri11232a22020-05-14 18:06:25 -0700383 // If the primary range consists of a single refresh rate then we can only
384 // move out the of range if layers explicitly request a different refresh
385 // rate.
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100386 const bool primaryRangeIsSingleRate =
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700387 isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);
Alec Mouri11232a22020-05-14 18:06:25 -0700388
Dominik Laskowskia8626ec2021-12-15 18:13:30 -0800389 if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
ramindanid72ba162022-09-09 21:33:40 +0000390 ALOGV("Idle");
Ady Abraham37d46922022-10-05 13:08:51 -0700391 return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending,
392 /*preferredDisplayModeOpt*/ std::nullopt),
ramindanid72ba162022-09-09 21:33:40 +0000393 GlobalSignals{.idle = true}};
Steven Thomasbb374322020-04-28 22:47:16 -0700394 }
395
Steven Thomasdebafed2020-05-18 17:30:35 -0700396 if (layers.empty() || noVoteLayers == layers.size()) {
ramindanid72ba162022-09-09 21:33:40 +0000397 ALOGV("No layers with votes");
Ady Abraham37d46922022-10-05 13:08:51 -0700398 return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
399 /*preferredDisplayModeOpt*/ std::nullopt),
ramindanid72ba162022-09-09 21:33:40 +0000400 kNoSignals};
Steven Thomasbb374322020-04-28 22:47:16 -0700401 }
402
Ady Abraham8a82ba62020-01-17 12:43:17 -0800403 // Only if all layers want Min we should return Min
404 if (noVoteLayers + minVoteLayers == layers.size()) {
ramindanid72ba162022-09-09 21:33:40 +0000405 ALOGV("All layers Min");
Ady Abraham37d46922022-10-05 13:08:51 -0700406 return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending,
407 /*preferredDisplayModeOpt*/ std::nullopt),
ramindanid72ba162022-09-09 21:33:40 +0000408 kNoSignals};
Ady Abraham8a82ba62020-01-17 12:43:17 -0800409 }
410
Ady Abraham8a82ba62020-01-17 12:43:17 -0800411 // Find the best refresh rate based on score
Ady Abraham62a0be22020-12-08 16:54:10 -0800412 std::vector<RefreshRateScore> scores;
Steven Thomasf734df42020-04-13 21:09:28 -0700413 scores.reserve(mAppRequestRefreshRates.size());
Ady Abraham8a82ba62020-01-17 12:43:17 -0800414
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800415 for (const DisplayModeIterator modeIt : mAppRequestRefreshRates) {
416 scores.emplace_back(RefreshRateScore{modeIt, 0.0f});
Ady Abraham8a82ba62020-01-17 12:43:17 -0800417 }
418
419 for (const auto& layer : layers) {
rnlee3bd610662021-06-23 16:27:57 -0700420 ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(),
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700421 ftl::enum_string(layer.vote).c_str(), layer.weight,
rnlee3bd610662021-06-23 16:27:57 -0700422 layer.desiredRefreshRate.getValue());
Ady Abraham4ccdcb42020-02-11 17:34:34 -0800423 if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800424 continue;
425 }
426
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800427 const auto weight = layer.weight;
Ady Abraham71c437d2020-01-31 15:56:57 -0800428
Ady Abraham62f51d92022-08-24 22:20:22 +0000429 for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800430 const auto& [id, mode] = *modeIt;
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700431 const bool isSeamlessSwitch = mode->getGroup() == activeMode.getGroup();
Marin Shalamanov46084422020-10-13 12:33:42 +0200432
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100433 if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100434 ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s",
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800435 formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700436 to_string(activeMode).c_str());
Marin Shalamanov46084422020-10-13 12:33:42 +0200437 continue;
438 }
439
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100440 if (layer.seamlessness == Seamlessness::SeamedAndSeamless && !isSeamlessSwitch &&
441 !layer.focused) {
442 ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100443 " Current mode = %s",
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800444 formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700445 to_string(activeMode).c_str());
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100446 continue;
447 }
448
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100449 // Layers with default seamlessness vote for the current mode group if
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100450 // there are layers with seamlessness=SeamedAndSeamless and for the default
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100451 // mode group otherwise. In second case, if the current mode group is different
Marin Shalamanov53fc11d2020-11-20 14:00:13 +0100452 // from the default, this means a layer with seamlessness=SeamedAndSeamless has just
453 // disappeared.
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800454 const bool isInPolicyForDefault = mode->getGroup() == anchorGroup;
Marin Shalamanovae0b5352021-03-24 12:56:08 +0100455 if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) {
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100456 ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(),
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700457 to_string(*mode).c_str(), to_string(activeMode).c_str());
Marin Shalamanov46084422020-10-13 12:33:42 +0200458 continue;
459 }
460
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800461 const bool inPrimaryRange = policy->primaryRange.includes(mode->getFps());
Alec Mouri11232a22020-05-14 18:06:25 -0700462 if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800463 !(layer.focused &&
464 (layer.vote == LayerVoteType::ExplicitDefault ||
465 layer.vote == LayerVoteType::ExplicitExact))) {
Ady Abraham20c029c2020-07-06 12:58:05 -0700466 // Only focused layers with ExplicitDefault frame rate settings are allowed to score
Ady Abrahamaae5ed52020-06-26 09:32:43 -0700467 // refresh rates outside the primary range.
Steven Thomasf734df42020-04-13 21:09:28 -0700468 continue;
469 }
470
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000471 const float layerScore =
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800472 calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch);
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000473 const float weightedLayerScore = weight * layerScore;
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800474
Ady Abraham13cfb362022-08-13 05:12:13 +0000475 // Layer with fixed source has a special consideration which depends on the
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000476 // mConfig.frameRateMultipleThreshold. We don't want these layers to score
477 // refresh rates above the threshold, but we also don't want to favor the lower
478 // ones by having a greater number of layers scoring them. Instead, we calculate
479 // the score independently for these layers and later decide which
480 // refresh rates to add it. For example, desired 24 fps with 120 Hz threshold should not
481 // score 120 Hz, but desired 60 fps should contribute to the score.
482 const bool fixedSourceLayer = [](LayerVoteType vote) {
483 switch (vote) {
484 case LayerVoteType::ExplicitExactOrMultiple:
485 case LayerVoteType::Heuristic:
486 return true;
487 case LayerVoteType::NoVote:
488 case LayerVoteType::Min:
489 case LayerVoteType::Max:
490 case LayerVoteType::ExplicitDefault:
491 case LayerVoteType::ExplicitExact:
492 return false;
493 }
494 }(layer.vote);
Ady Abraham62f51d92022-08-24 22:20:22 +0000495 const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 &&
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000496 layer.desiredRefreshRate <
497 Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
Ady Abraham62f51d92022-08-24 22:20:22 +0000498 if (fixedSourceLayer && layerBelowThreshold) {
Ady Abraham13cfb362022-08-13 05:12:13 +0000499 const bool modeAboveThreshold =
500 mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
Ady Abraham62f51d92022-08-24 22:20:22 +0000501 if (modeAboveThreshold) {
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000502 ALOGV("%s gives %s fixed source (above threshold) score of %.4f",
503 formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
504 layerScore);
Ady Abraham62f51d92022-08-24 22:20:22 +0000505 fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000506 } else {
507 ALOGV("%s gives %s fixed source (below threshold) score of %.4f",
508 formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
509 layerScore);
Ady Abraham62f51d92022-08-24 22:20:22 +0000510 fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000511 }
512 } else {
513 ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
514 to_string(mode->getFps()).c_str(), layerScore);
515 overallScore += weightedLayerScore;
516 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800517 }
518 }
519
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000520 // We want to find the best refresh rate without the fixed source layers,
Ady Abraham62f51d92022-08-24 22:20:22 +0000521 // so we could know whether we should add the modeAboveThreshold scores or not.
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000522 // If the best refresh rate is already above the threshold, it means that
523 // some non-fixed source layers already scored it, so we can just add the score
524 // for all fixed source layers, even the ones that are above the threshold.
525 const bool maxScoreAboveThreshold = [&] {
526 if (mConfig.frameRateMultipleThreshold == 0 || scores.empty()) {
527 return false;
528 }
529
530 const auto maxScoreIt =
531 std::max_element(scores.begin(), scores.end(),
532 [](RefreshRateScore max, RefreshRateScore current) {
533 const auto& [modeIt, overallScore, _] = current;
534 return overallScore > max.overallScore;
535 });
536 ALOGV("%s is the best refresh rate without fixed source layers. It is %s the threshold for "
537 "refresh rate multiples",
538 to_string(maxScoreIt->modeIt->second->getFps()).c_str(),
539 maxScoreAboveThreshold ? "above" : "below");
540 return maxScoreIt->modeIt->second->getFps() >=
541 Fps::fromValue(mConfig.frameRateMultipleThreshold);
542 }();
543
544 // Now we can add the fixed rate layers score
Ady Abraham62f51d92022-08-24 22:20:22 +0000545 for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
546 overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold;
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000547 if (maxScoreAboveThreshold) {
Ady Abraham62f51d92022-08-24 22:20:22 +0000548 overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000549 }
550 ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(),
551 overallScore);
552 }
553
554 // Now that we scored all the refresh rates we need to pick the one that got the highest
ramindanid72ba162022-09-09 21:33:40 +0000555 // overallScore. Sort the scores based on their overallScore in descending order of priority.
556 const RefreshRateOrder refreshRateOrder =
557 maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending;
558 std::sort(scores.begin(), scores.end(),
559 RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder});
560 std::vector<RefreshRateRanking> rankedRefreshRates;
561 rankedRefreshRates.reserve(scores.size());
562
563 std::transform(scores.begin(), scores.end(), back_inserter(rankedRefreshRates),
564 [](const RefreshRateScore& score) {
565 return RefreshRateRanking{score.modeIt->second, score.overallScore};
566 });
Ady Abraham34702102020-02-10 14:12:05 -0800567
Ady Abraham37d46922022-10-05 13:08:51 -0700568 const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) {
569 return score.overallScore == 0;
570 });
571
Alec Mouri11232a22020-05-14 18:06:25 -0700572 if (primaryRangeIsSingleRate) {
573 // If we never scored any layers, then choose the rate from the primary
574 // range instead of picking a random score from the app range.
Ady Abraham37d46922022-10-05 13:08:51 -0700575 if (noLayerScore) {
ramindanid72ba162022-09-09 21:33:40 +0000576 ALOGV("Layers not scored");
Ady Abraham37d46922022-10-05 13:08:51 -0700577 return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
578 /*preferredDisplayModeOpt*/ std::nullopt),
ramindanid72ba162022-09-09 21:33:40 +0000579 kNoSignals};
Alec Mouri11232a22020-05-14 18:06:25 -0700580 } else {
ramindanid72ba162022-09-09 21:33:40 +0000581 return {rankedRefreshRates, kNoSignals};
Alec Mouri11232a22020-05-14 18:06:25 -0700582 }
583 }
584
Steven Thomasf734df42020-04-13 21:09:28 -0700585 // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
586 // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
587 // vote we should not change it if we get a touch event. Only apply touch boost if it will
588 // actually increase the refresh rate over the normal selection.
Ady Abraham5e4e9832021-06-14 13:40:56 -0700589 const bool touchBoostForExplicitExact = [&] {
Andy Yu2ae6b6b2021-11-18 14:51:06 -0800590 if (mSupportsFrameRateOverrideByContent) {
Ady Abraham5e4e9832021-06-14 13:40:56 -0700591 // Enable touch boost if there are other layers besides exact
592 return explicitExact + noVoteLayers != layers.size();
593 } else {
594 // Enable touch boost if there are no exact layers
595 return explicitExact == 0;
596 }
597 }();
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700598
ramindanid72ba162022-09-09 21:33:40 +0000599 const auto& touchRefreshRates =
Ady Abraham37d46922022-10-05 13:08:51 -0700600 getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
601 /*preferredDisplayModeOpt*/ std::nullopt);
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700602 using fps_approx_ops::operator<;
603
Dominik Laskowskia8626ec2021-12-15 18:13:30 -0800604 if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
ramindanid72ba162022-09-09 21:33:40 +0000605 scores.front().modeIt->second->getFps() <
606 touchRefreshRates.front().displayModePtr->getFps()) {
607 ALOGV("Touch Boost");
608 return {touchRefreshRates, GlobalSignals{.touch = true}};
Steven Thomasf734df42020-04-13 21:09:28 -0700609 }
610
Ady Abraham37d46922022-10-05 13:08:51 -0700611 // If we never scored any layers, and we don't favor high refresh rates, prefer to stay with the
612 // current config
613 if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) {
614 const auto preferredDisplayMode = activeMode.getId();
615 return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Ascending,
616 preferredDisplayMode),
617 kNoSignals};
618 }
619
ramindanid72ba162022-09-09 21:33:40 +0000620 return {rankedRefreshRates, kNoSignals};
Ady Abraham34702102020-02-10 14:12:05 -0800621}
622
Ady Abraham62a0be22020-12-08 16:54:10 -0800623std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
624groupLayersByUid(const std::vector<RefreshRateConfigs::LayerRequirement>& layers) {
625 std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> layersByUid;
626 for (const auto& layer : layers) {
627 auto iter = layersByUid.emplace(layer.ownerUid,
628 std::vector<const RefreshRateConfigs::LayerRequirement*>());
629 auto& layersWithSameUid = iter.first->second;
630 layersWithSameUid.push_back(&layer);
631 }
632
633 // Remove uids that can't have a frame rate override
634 for (auto iter = layersByUid.begin(); iter != layersByUid.end();) {
635 const auto& layersWithSameUid = iter->second;
636 bool skipUid = false;
637 for (const auto& layer : layersWithSameUid) {
638 if (layer->vote == RefreshRateConfigs::LayerVoteType::Max ||
639 layer->vote == RefreshRateConfigs::LayerVoteType::Heuristic) {
640 skipUid = true;
641 break;
642 }
643 }
644 if (skipUid) {
645 iter = layersByUid.erase(iter);
646 } else {
647 ++iter;
648 }
649 }
650
651 return layersByUid;
652}
653
Ady Abraham62a0be22020-12-08 16:54:10 -0800654RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides(
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800655 const std::vector<LayerRequirement>& layers, Fps displayRefreshRate,
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700656 GlobalSignals globalSignals) const {
Ady Abraham62a0be22020-12-08 16:54:10 -0800657 ATRACE_CALL();
Ady Abraham62a0be22020-12-08 16:54:10 -0800658
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800659 ALOGV("%s: %zu layers", __func__, layers.size());
660
Ady Abraham62a0be22020-12-08 16:54:10 -0800661 std::lock_guard lock(mLock);
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800662
663 std::vector<RefreshRateScore> scores;
664 scores.reserve(mDisplayModes.size());
665
666 for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) {
667 scores.emplace_back(RefreshRateScore{it, 0.0f});
668 }
669
670 std::sort(scores.begin(), scores.end(), [](const auto& lhs, const auto& rhs) {
671 const auto& mode1 = lhs.modeIt->second;
672 const auto& mode2 = rhs.modeIt->second;
673 return isStrictlyLess(mode1->getFps(), mode2->getFps());
674 });
675
Ady Abraham62a0be22020-12-08 16:54:10 -0800676 std::unordered_map<uid_t, std::vector<const LayerRequirement*>> layersByUid =
677 groupLayersByUid(layers);
678 UidToFrameRateOverride frameRateOverrides;
679 for (const auto& [uid, layersWithSameUid] : layersByUid) {
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800680 // Layers with ExplicitExactOrMultiple expect touch boost
681 const bool hasExplicitExactOrMultiple =
682 std::any_of(layersWithSameUid.cbegin(), layersWithSameUid.cend(),
683 [](const auto& layer) {
684 return layer->vote == LayerVoteType::ExplicitExactOrMultiple;
685 });
686
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700687 if (globalSignals.touch && hasExplicitExactOrMultiple) {
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800688 continue;
689 }
690
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000691 for (auto& [_, score, _1] : scores) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800692 score = 0;
Ady Abraham62a0be22020-12-08 16:54:10 -0800693 }
694
695 for (const auto& layer : layersWithSameUid) {
696 if (layer->vote == LayerVoteType::NoVote || layer->vote == LayerVoteType::Min) {
697 continue;
698 }
699
700 LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
Ady Abrahamdd5bfa92021-01-07 17:56:08 -0800701 layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
702 layer->vote != LayerVoteType::ExplicitExact);
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000703 for (auto& [modeIt, score, _] : scores) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800704 constexpr bool isSeamlessSwitch = true;
705 const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(),
706 isSeamlessSwitch);
707 score += layer->weight * layerScore;
Ady Abraham62a0be22020-12-08 16:54:10 -0800708 }
709 }
710
Ady Abrahamcc315492022-02-17 17:06:39 -0800711 // We just care about the refresh rates which are a divisor of the
Ady Abraham62a0be22020-12-08 16:54:10 -0800712 // display refresh rate
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800713 const auto it = std::remove_if(scores.begin(), scores.end(), [&](RefreshRateScore score) {
714 const auto& [id, mode] = *score.modeIt;
715 return getFrameRateDivisor(displayRefreshRate, mode->getFps()) == 0;
716 });
717 scores.erase(it, scores.end());
Ady Abraham62a0be22020-12-08 16:54:10 -0800718
719 // If we never scored any layers, we don't have a preferred frame rate
720 if (std::all_of(scores.begin(), scores.end(),
Ady Abrahamae2e3c72022-08-13 05:12:13 +0000721 [](RefreshRateScore score) { return score.overallScore == 0; })) {
Ady Abraham62a0be22020-12-08 16:54:10 -0800722 continue;
723 }
724
ramindanid72ba162022-09-09 21:33:40 +0000725 // Now that we scored all the refresh rates we need to pick the lowest refresh rate
726 // that got the highest score.
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800727 const DisplayModePtr& bestRefreshRate =
ramindanid72ba162022-09-09 21:33:40 +0000728 std::min_element(scores.begin(), scores.end(),
729 RefreshRateScoreComparator{.refreshRateOrder =
730 RefreshRateOrder::Ascending})
731 ->modeIt->second;
Ady Abraham5cc2e262021-03-25 13:09:17 -0700732 frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
Ady Abraham62a0be22020-12-08 16:54:10 -0800733 }
734
735 return frameRateOverrides;
736}
737
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100738std::optional<Fps> RefreshRateConfigs::onKernelTimerChanged(
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800739 std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const {
Ady Abraham2139f732019-11-13 18:56:40 -0800740 std::lock_guard lock(mLock);
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100741
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800742 const DisplayModePtr& current = desiredActiveModeId
743 ? mDisplayModes.get(*desiredActiveModeId)->get()
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700744 : getActiveModeItLocked()->second;
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100745
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800746 const DisplayModePtr& min = mMinRefreshRateModeIt->second;
747 if (current == min) {
748 return {};
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100749 }
750
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800751 const auto& mode = timerExpired ? min : current;
752 return mode->getFps();
Steven Thomasf734df42020-04-13 21:09:28 -0700753}
754
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800755const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700756 const auto& activeMode = *getActiveModeItLocked()->second;
757
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800758 for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) {
759 const auto& mode = modeIt->second;
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700760 if (activeMode.getGroup() == mode->getGroup()) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800761 return mode;
Marin Shalamanov46084422020-10-13 12:33:42 +0200762 }
763 }
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800764
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700765 ALOGE("Can't find min refresh rate by policy with the same mode group as the current mode %s",
766 to_string(activeMode).c_str());
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800767
768 // Default to the lowest refresh rate.
769 return mPrimaryRefreshRates.front()->second;
Ady Abraham2139f732019-11-13 18:56:40 -0800770}
771
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800772const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
773 for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) {
774 const auto& mode = (*it)->second;
775 if (anchorGroup == mode->getGroup()) {
776 return mode;
Marin Shalamanov46084422020-10-13 12:33:42 +0200777 }
778 }
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800779
ramindanid72ba162022-09-09 21:33:40 +0000780 ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup);
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800781
782 // Default to the highest refresh rate.
783 return mPrimaryRefreshRates.back()->second;
Ady Abraham2139f732019-11-13 18:56:40 -0800784}
785
ramindanid72ba162022-09-09 21:33:40 +0000786std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked(
Ady Abraham37d46922022-10-05 13:08:51 -0700787 std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder,
788 std::optional<DisplayModeId> preferredDisplayModeOpt) const {
789 std::deque<RefreshRateRanking> rankings;
ramindanid72ba162022-09-09 21:33:40 +0000790 const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) {
791 const auto& mode = it->second;
Ady Abraham37d46922022-10-05 13:08:51 -0700792 if (anchorGroupOpt && mode->getGroup() != anchorGroupOpt) {
793 return;
ramindanid72ba162022-09-09 21:33:40 +0000794 }
Ady Abraham37d46922022-10-05 13:08:51 -0700795
796 float score = calculateRefreshRateScoreForFps(mode->getFps());
797 const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending);
798 if (inverseScore) {
799 score = 1.0f / score;
800 }
801 if (preferredDisplayModeOpt) {
802 if (*preferredDisplayModeOpt == mode->getId()) {
803 rankings.push_front(RefreshRateRanking{mode, /*score*/ 1.0f});
804 return;
805 }
806 constexpr float kNonPreferredModePenalty = 0.95f;
807 score *= kNonPreferredModePenalty;
808 }
809 rankings.push_back(RefreshRateRanking{mode, score});
ramindanid72ba162022-09-09 21:33:40 +0000810 };
811
812 if (refreshRateOrder == RefreshRateOrder::Ascending) {
813 std::for_each(mPrimaryRefreshRates.begin(), mPrimaryRefreshRates.end(), makeRanking);
814 } else {
815 std::for_each(mPrimaryRefreshRates.rbegin(), mPrimaryRefreshRates.rend(), makeRanking);
816 }
817
818 if (!rankings.empty() || !anchorGroupOpt) {
Ady Abraham37d46922022-10-05 13:08:51 -0700819 return {rankings.begin(), rankings.end()};
ramindanid72ba162022-09-09 21:33:40 +0000820 }
821
822 ALOGW("Can't find %s refresh rate by policy with the same mode group"
823 " as the mode group %d",
824 refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value());
825
Ady Abraham37d46922022-10-05 13:08:51 -0700826 return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder,
827 preferredDisplayModeOpt);
ramindanid72ba162022-09-09 21:33:40 +0000828}
829
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700830DisplayModePtr RefreshRateConfigs::getActiveModePtr() const {
Ady Abraham2139f732019-11-13 18:56:40 -0800831 std::lock_guard lock(mLock);
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700832 return getActiveModeItLocked()->second;
833}
834
835const DisplayMode& RefreshRateConfigs::getActiveMode() const {
836 // Reads from kMainThreadContext do not require mLock.
837 ftl::FakeGuard guard(mLock);
838 return *mActiveModeIt->second;
839}
840
841DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const {
842 // Reads under mLock do not require kMainThreadContext.
843 return FTL_FAKE_GUARD(kMainThreadContext, mActiveModeIt);
Ady Abraham2139f732019-11-13 18:56:40 -0800844}
845
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800846void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) {
Ady Abraham2139f732019-11-13 18:56:40 -0800847 std::lock_guard lock(mLock);
Marin Shalamanov4c7831e2021-06-08 20:44:06 +0200848
ramindanid72ba162022-09-09 21:33:40 +0000849 // Invalidate the cached invocation to getRankedRefreshRates. This forces
850 // the refresh rate to be recomputed on the next call to getRankedRefreshRates.
851 mGetRankedRefreshRatesCache.reset();
Marin Shalamanov4c7831e2021-06-08 20:44:06 +0200852
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800853 mActiveModeIt = mDisplayModes.find(modeId);
854 LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800855}
856
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800857RefreshRateConfigs::RefreshRateConfigs(DisplayModes modes, DisplayModeId activeModeId,
rnlee3bd610662021-06-23 16:27:57 -0700858 Config config)
859 : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
Ady Abraham9a2ea342021-09-03 17:32:34 -0700860 initializeIdleTimer();
Dominik Laskowskif8734e02022-08-26 09:06:59 -0700861 FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId));
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100862}
863
Ady Abraham9a2ea342021-09-03 17:32:34 -0700864void RefreshRateConfigs::initializeIdleTimer() {
ramindani32cf0602022-03-02 02:30:29 +0000865 if (mConfig.idleTimerTimeout > 0ms) {
Ady Abraham9a2ea342021-09-03 17:32:34 -0700866 mIdleTimer.emplace(
ramindani32cf0602022-03-02 02:30:29 +0000867 "IdleTimer", mConfig.idleTimerTimeout,
Dominik Laskowski83bd7712022-01-07 14:30:53 -0800868 [this] {
869 std::scoped_lock lock(mIdleTimerCallbacksMutex);
870 if (const auto callbacks = getIdleTimerCallbacks()) {
871 callbacks->onReset();
872 }
Ady Abraham9a2ea342021-09-03 17:32:34 -0700873 },
Dominik Laskowski83bd7712022-01-07 14:30:53 -0800874 [this] {
875 std::scoped_lock lock(mIdleTimerCallbacksMutex);
876 if (const auto callbacks = getIdleTimerCallbacks()) {
877 callbacks->onExpired();
878 }
Ady Abraham9a2ea342021-09-03 17:32:34 -0700879 });
Ady Abraham9a2ea342021-09-03 17:32:34 -0700880 }
881}
882
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800883void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) {
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100884 std::lock_guard lock(mLock);
Marin Shalamanov4c7831e2021-06-08 20:44:06 +0200885
ramindanid72ba162022-09-09 21:33:40 +0000886 // Invalidate the cached invocation to getRankedRefreshRates. This forces
887 // the refresh rate to be recomputed on the next call to getRankedRefreshRates.
888 mGetRankedRefreshRatesCache.reset();
Marin Shalamanov4c7831e2021-06-08 20:44:06 +0200889
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800890 mDisplayModes = std::move(modes);
891 mActiveModeIt = mDisplayModes.find(activeModeId);
892 LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
Ady Abrahamabc27602020-04-08 17:20:29 -0700893
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800894 const auto sortedModes =
895 sortByRefreshRate(mDisplayModes, [](const DisplayMode&) { return true; });
896 mMinRefreshRateModeIt = sortedModes.front();
897 mMaxRefreshRateModeIt = sortedModes.back();
898
Marin Shalamanov75f37252021-02-10 21:43:57 +0100899 // Reset the policy because the old one may no longer be valid.
900 mDisplayManagerPolicy = {};
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800901 mDisplayManagerPolicy.defaultMode = activeModeId;
Ady Abraham64c2fc02020-12-29 12:07:50 -0800902
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800903 mSupportsFrameRateOverrideByContent =
904 mConfig.enableFrameRateOverride && canModesSupportFrameRateOverride(sortedModes);
Ady Abraham4899ff82021-01-06 13:53:29 -0800905
Ady Abrahamabc27602020-04-08 17:20:29 -0700906 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800907}
908
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100909bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const {
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100910 // defaultMode must be a valid mode, and within the given refresh rate range.
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800911 if (const auto mode = mDisplayModes.get(policy.defaultMode)) {
912 if (!policy.primaryRange.includes(mode->get()->getFps())) {
913 ALOGE("Default mode is not in the primary range.");
914 return false;
915 }
916 } else {
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100917 ALOGE("Default mode is not found.");
Steven Thomasd4071902020-03-24 16:02:53 -0700918 return false;
919 }
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700920
921 using namespace fps_approx_ops;
922 return policy.appRequestRange.min <= policy.primaryRange.min &&
923 policy.appRequestRange.max >= policy.primaryRange.max;
Steven Thomasd4071902020-03-24 16:02:53 -0700924}
925
Dominik Laskowski36dced82022-09-02 09:24:00 -0700926auto RefreshRateConfigs::setPolicy(const PolicyVariant& policy) -> SetPolicyResult {
927 Policy oldPolicy;
928 {
929 std::lock_guard lock(mLock);
930 oldPolicy = *getCurrentPolicyLocked();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100931
Dominik Laskowski36dced82022-09-02 09:24:00 -0700932 const bool valid = ftl::match(
933 policy,
934 [this](const auto& policy) {
935 ftl::FakeGuard guard(mLock);
936 if (!isPolicyValidLocked(policy)) {
937 ALOGE("Invalid policy: %s", policy.toString().c_str());
938 return false;
939 }
940
941 using T = std::decay_t<decltype(policy)>;
942
943 if constexpr (std::is_same_v<T, DisplayManagerPolicy>) {
944 mDisplayManagerPolicy = policy;
945 } else {
946 static_assert(std::is_same_v<T, OverridePolicy>);
947 mOverridePolicy = policy;
948 }
949 return true;
950 },
951 [this](NoOverridePolicy) {
952 ftl::FakeGuard guard(mLock);
953 mOverridePolicy.reset();
954 return true;
955 });
956
957 if (!valid) {
958 return SetPolicyResult::Invalid;
959 }
960
961 mGetRankedRefreshRatesCache.reset();
962
963 if (*getCurrentPolicyLocked() == oldPolicy) {
964 return SetPolicyResult::Unchanged;
965 }
966 constructAvailableRefreshRates();
Steven Thomasd4071902020-03-24 16:02:53 -0700967 }
Dominik Laskowski36dced82022-09-02 09:24:00 -0700968
969 const auto displayId = getActiveMode().getPhysicalDisplayId();
970 const unsigned numModeChanges = std::exchange(mNumModeSwitchesInPolicy, 0u);
971
972 ALOGI("Display %s policy changed\n"
973 "Previous: %s\n"
974 "Current: %s\n"
975 "%u mode changes were performed under the previous policy",
976 to_string(displayId).c_str(), oldPolicy.toString().c_str(), toString(policy).c_str(),
977 numModeChanges);
978
979 return SetPolicyResult::Changed;
Steven Thomasd4071902020-03-24 16:02:53 -0700980}
981
982const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const {
983 return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy;
984}
985
986RefreshRateConfigs::Policy RefreshRateConfigs::getCurrentPolicy() const {
987 std::lock_guard lock(mLock);
988 return *getCurrentPolicyLocked();
989}
990
991RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const {
992 std::lock_guard lock(mLock);
993 return mDisplayManagerPolicy;
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100994}
995
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100996bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100997 std::lock_guard lock(mLock);
Dominik Laskowskib0054a22022-03-03 09:03:06 -0800998 return std::any_of(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
999 [modeId](DisplayModeIterator modeIt) {
1000 return modeIt->second->getId() == modeId;
1001 });
Ady Abraham2139f732019-11-13 18:56:40 -08001002}
1003
1004void RefreshRateConfigs::constructAvailableRefreshRates() {
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001005 // Filter modes based on current policy and sort on refresh rate.
Steven Thomasd4071902020-03-24 16:02:53 -07001006 const Policy* policy = getCurrentPolicyLocked();
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001007 ALOGV("%s: %s ", __func__, policy->toString().c_str());
Ady Abrahamabc27602020-04-08 17:20:29 -07001008
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001009 const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
Ady Abraham8a82ba62020-01-17 12:43:17 -08001010
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001011 const auto filterRefreshRates = [&](FpsRange range, const char* rangeName) REQUIRES(mLock) {
1012 const auto filter = [&](const DisplayMode& mode) {
1013 return mode.getResolution() == defaultMode->getResolution() &&
1014 mode.getDpi() == defaultMode->getDpi() &&
1015 (policy->allowGroupSwitching || mode.getGroup() == defaultMode->getGroup()) &&
1016 range.includes(mode.getFps());
1017 };
Ady Abraham8a82ba62020-01-17 12:43:17 -08001018
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001019 const auto modes = sortByRefreshRate(mDisplayModes, filter);
1020 LOG_ALWAYS_FATAL_IF(modes.empty(), "No matching modes for %s range %s", rangeName,
1021 to_string(range).c_str());
Dominik Laskowski953b7fd2022-01-08 19:34:59 -08001022
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001023 const auto stringifyModes = [&] {
1024 std::string str;
1025 for (const auto modeIt : modes) {
1026 str += to_string(modeIt->second->getFps());
1027 str.push_back(' ');
1028 }
1029 return str;
1030 };
1031 ALOGV("%s refresh rates: %s", rangeName, stringifyModes().c_str());
Steven Thomasf734df42020-04-13 21:09:28 -07001032
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001033 return modes;
1034 };
1035
1036 mPrimaryRefreshRates = filterRefreshRates(policy->primaryRange, "primary");
1037 mAppRequestRefreshRates = filterRefreshRates(policy->appRequestRange, "app request");
Ady Abraham2139f732019-11-13 18:56:40 -08001038}
1039
Marin Shalamanove8a663d2020-11-24 17:48:00 +01001040Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
Dominik Laskowski6eab42d2021-09-13 14:34:13 -07001041 using namespace fps_approx_ops;
1042
1043 if (frameRate <= mKnownFrameRates.front()) {
1044 return mKnownFrameRates.front();
Ady Abrahamb1b9d412020-06-01 19:53:52 -07001045 }
1046
Dominik Laskowski6eab42d2021-09-13 14:34:13 -07001047 if (frameRate >= mKnownFrameRates.back()) {
1048 return mKnownFrameRates.back();
Ady Abrahamb1b9d412020-06-01 19:53:52 -07001049 }
1050
Marin Shalamanove8a663d2020-11-24 17:48:00 +01001051 auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate,
Dominik Laskowski6eab42d2021-09-13 14:34:13 -07001052 isStrictlyLess);
Ady Abrahamb1b9d412020-06-01 19:53:52 -07001053
Dominik Laskowski6eab42d2021-09-13 14:34:13 -07001054 const auto distance1 = std::abs(frameRate.getValue() - lowerBound->getValue());
1055 const auto distance2 = std::abs(frameRate.getValue() - std::prev(lowerBound)->getValue());
Ady Abrahamb1b9d412020-06-01 19:53:52 -07001056 return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
1057}
1058
Ana Krulecb9afd792020-06-11 13:16:15 -07001059RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const {
1060 std::lock_guard lock(mLock);
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001061
1062 const Fps deviceMinFps = mMinRefreshRateModeIt->second->getFps();
1063 const DisplayModePtr& minByPolicy = getMinRefreshRateByPolicyLocked();
Ana Krulecb9afd792020-06-11 13:16:15 -07001064
1065 // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
1066 // the min allowed refresh rate is higher than the device min, we do not want to enable the
1067 // timer.
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001068 if (isStrictlyLess(deviceMinFps, minByPolicy->getFps())) {
1069 return KernelIdleTimerAction::TurnOff;
Ana Krulecb9afd792020-06-11 13:16:15 -07001070 }
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001071
ramindanid72ba162022-09-09 21:33:40 +00001072 const DisplayModePtr& maxByPolicy =
1073 getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup());
Ana Krulecb9afd792020-06-11 13:16:15 -07001074 if (minByPolicy == maxByPolicy) {
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001075 // Turn on the timer when the min of the primary range is below the device min.
1076 if (const Policy* currentPolicy = getCurrentPolicyLocked();
1077 isApproxLess(currentPolicy->primaryRange.min, deviceMinFps)) {
1078 return KernelIdleTimerAction::TurnOn;
Ana Krulecb9afd792020-06-11 13:16:15 -07001079 }
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001080 return KernelIdleTimerAction::TurnOff;
Ana Krulecb9afd792020-06-11 13:16:15 -07001081 }
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001082
Ana Krulecb9afd792020-06-11 13:16:15 -07001083 // Turn on the timer in all other cases.
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001084 return KernelIdleTimerAction::TurnOn;
Ana Krulecb9afd792020-06-11 13:16:15 -07001085}
1086
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001087int RefreshRateConfigs::getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate) {
Ady Abraham62f216c2020-10-13 19:07:23 -07001088 // This calculation needs to be in sync with the java code
1089 // in DisplayManagerService.getDisplayInfoForFrameRateOverride
Marin Shalamanov15a0fc62021-08-16 18:20:21 +02001090
1091 // The threshold must be smaller than 0.001 in order to differentiate
1092 // between the fractional pairs (e.g. 59.94 and 60).
1093 constexpr float kThreshold = 0.0009f;
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001094 const auto numPeriods = displayRefreshRate.getValue() / layerFrameRate.getValue();
Ady Abraham0bb6a472020-10-12 10:22:13 -07001095 const auto numPeriodsRounded = std::round(numPeriods);
1096 if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
Ady Abraham62a0be22020-12-08 16:54:10 -08001097 return 0;
Ady Abraham0bb6a472020-10-12 10:22:13 -07001098 }
1099
Ady Abraham62f216c2020-10-13 19:07:23 -07001100 return static_cast<int>(numPeriodsRounded);
1101}
1102
Marin Shalamanov15a0fc62021-08-16 18:20:21 +02001103bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
Dominik Laskowski6eab42d2021-09-13 14:34:13 -07001104 if (isStrictlyLess(bigger, smaller)) {
Marin Shalamanov15a0fc62021-08-16 18:20:21 +02001105 return isFractionalPairOrMultiple(bigger, smaller);
1106 }
1107
1108 const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
1109 constexpr float kCoef = 1000.f / 1001.f;
Dominik Laskowski6eab42d2021-09-13 14:34:13 -07001110 return isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier / kCoef)) ||
1111 isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef));
Marin Shalamanov15a0fc62021-08-16 18:20:21 +02001112}
1113
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001114void RefreshRateConfigs::dump(utils::Dumper& dumper) const {
1115 using namespace std::string_view_literals;
Dominik Laskowski0acc3842022-04-07 11:23:42 -07001116
Marin Shalamanovba421a82020-11-10 21:49:26 +01001117 std::lock_guard lock(mLock);
Marin Shalamanovba421a82020-11-10 21:49:26 +01001118
Dominik Laskowskif8734e02022-08-26 09:06:59 -07001119 const auto activeModeId = getActiveModeItLocked()->first;
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001120 dumper.dump("activeModeId"sv, std::to_string(activeModeId.value()));
Marin Shalamanovba421a82020-11-10 21:49:26 +01001121
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001122 dumper.dump("displayModes"sv);
1123 {
1124 utils::Dumper::Indent indent(dumper);
1125 for (const auto& [id, mode] : mDisplayModes) {
1126 dumper.dump({}, to_string(*mode));
1127 }
Marin Shalamanovba421a82020-11-10 21:49:26 +01001128 }
1129
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001130 dumper.dump("displayManagerPolicy"sv, mDisplayManagerPolicy.toString());
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001131
Dominik Laskowski0acc3842022-04-07 11:23:42 -07001132 if (const Policy& currentPolicy = *getCurrentPolicyLocked();
1133 mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001134 dumper.dump("overridePolicy"sv, currentPolicy.toString());
ramindani32cf0602022-03-02 02:30:29 +00001135 }
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001136
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001137 dumper.dump("supportsFrameRateOverrideByContent"sv, mSupportsFrameRateOverrideByContent);
Dominik Laskowski0acc3842022-04-07 11:23:42 -07001138
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001139 std::string idleTimer;
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001140 if (mIdleTimer) {
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001141 idleTimer = mIdleTimer->dump();
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001142 } else {
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001143 idleTimer = "off"sv;
Dominik Laskowskib0054a22022-03-03 09:03:06 -08001144 }
1145
Dominik Laskowski0acc3842022-04-07 11:23:42 -07001146 if (const auto controller = mConfig.kernelIdleTimerController) {
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001147 base::StringAppendF(&idleTimer, " (kernel via %s)", ftl::enum_string(*controller).c_str());
Dominik Laskowski0acc3842022-04-07 11:23:42 -07001148 } else {
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001149 idleTimer += " (platform)"sv;
Dominik Laskowski0acc3842022-04-07 11:23:42 -07001150 }
1151
Dominik Laskowskie70461a2022-08-30 14:42:01 -07001152 dumper.dump("idleTimer"sv, idleTimer);
Marin Shalamanovba421a82020-11-10 21:49:26 +01001153}
1154
ramindani32cf0602022-03-02 02:30:29 +00001155std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
1156 return mConfig.idleTimerTimeout;
1157}
1158
Ady Abraham2139f732019-11-13 18:56:40 -08001159} // namespace android::scheduler
Marin Shalamanovbed7fd32020-12-21 20:02:20 +01001160
1161// TODO(b/129481165): remove the #pragma below and fix conversion issues
Ady Abrahamdd5bfa92021-01-07 17:56:08 -08001162#pragma clang diagnostic pop // ignored "-Wextra"