1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // #define LOG_NDEBUG 0
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 
20 // TODO(b/129481165): remove the #pragma below and fix conversion issues
21 #pragma clang diagnostic push
22 #pragma clang diagnostic ignored "-Wextra"
23 
24 #include <chrono>
25 #include <cmath>
26 #include <deque>
27 #include <map>
28 
29 #include <android-base/properties.h>
30 #include <android-base/stringprintf.h>
31 #include <ftl/enum.h>
32 #include <ftl/fake_guard.h>
33 #include <ftl/match.h>
34 #include <ftl/unit.h>
35 #include <gui/TraceUtils.h>
36 #include <scheduler/FrameRateMode.h>
37 #include <utils/Trace.h>
38 
39 #include "RefreshRateSelector.h"
40 
41 #include <com_android_graphics_surfaceflinger_flags.h>
42 
43 #undef LOG_TAG
44 #define LOG_TAG "RefreshRateSelector"
45 
46 namespace android::scheduler {
47 namespace {
48 
49 using namespace com::android::graphics::surfaceflinger;
50 
51 struct RefreshRateScore {
52     FrameRateMode frameRateMode;
53     float overallScore;
54     struct {
55         float modeBelowThreshold;
56         float modeAboveThreshold;
57     } fixedRateBelowThresholdLayersScore;
58 };
59 
60 constexpr RefreshRateSelector::GlobalSignals kNoSignals;
61 
formatLayerInfo(const RefreshRateSelector::LayerRequirement & layer,float weight)62 std::string formatLayerInfo(const RefreshRateSelector::LayerRequirement& layer, float weight) {
63     return base::StringPrintf("%s (type=%s, weight=%.2f, seamlessness=%s) %s", layer.name.c_str(),
64                               ftl::enum_string(layer.vote).c_str(), weight,
65                               ftl::enum_string(layer.seamlessness).c_str(),
66                               to_string(layer.desiredRefreshRate).c_str());
67 }
68 
constructKnownFrameRates(const DisplayModes & modes)69 std::vector<Fps> constructKnownFrameRates(const DisplayModes& modes) {
70     std::vector<Fps> knownFrameRates = {24_Hz, 30_Hz, 45_Hz, 60_Hz, 72_Hz};
71     knownFrameRates.reserve(knownFrameRates.size() + modes.size());
72 
73     // Add all supported refresh rates.
74     for (const auto& [id, mode] : modes) {
75         knownFrameRates.push_back(mode->getPeakFps());
76     }
77 
78     // Sort and remove duplicates.
79     std::sort(knownFrameRates.begin(), knownFrameRates.end(), isStrictlyLess);
80     knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
81                                       isApproxEqual),
82                           knownFrameRates.end());
83     return knownFrameRates;
84 }
85 
sortByRefreshRate(const DisplayModes & modes)86 std::vector<DisplayModeIterator> sortByRefreshRate(const DisplayModes& modes) {
87     std::vector<DisplayModeIterator> sortedModes;
88     sortedModes.reserve(modes.size());
89     for (auto it = modes.begin(); it != modes.end(); ++it) {
90         sortedModes.push_back(it);
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->getVsyncRate().getPeriodNsecs() == mode2->getVsyncRate().getPeriodNsecs()) {
98             return mode1->getGroup() > mode2->getGroup();
99         }
100 
101         return mode1->getVsyncRate().getPeriodNsecs() > mode2->getVsyncRate().getPeriodNsecs();
102     });
103 
104     return sortedModes;
105 }
106 
divisorRange(Fps vsyncRate,Fps peakFps,FpsRange range,RefreshRateSelector::Config::FrameRateOverride config)107 std::pair<unsigned, unsigned> divisorRange(Fps vsyncRate, Fps peakFps, FpsRange range,
108                                            RefreshRateSelector::Config::FrameRateOverride config) {
109     if (config != RefreshRateSelector::Config::FrameRateOverride::Enabled) {
110         return {1, 1};
111     }
112 
113     using fps_approx_ops::operator/;
114     // use signed type as `fps / range.max` might be 0
115     auto start = std::max(1, static_cast<int>(peakFps / range.max) - 1);
116     if (FlagManager::getInstance().vrr_config()) {
117         start = std::max(1,
118                          static_cast<int>(vsyncRate /
119                                           std::min(range.max, peakFps, fps_approx_ops::operator<)) -
120                                  1);
121     }
122     const auto end = vsyncRate /
123             std::max(range.min, RefreshRateSelector::kMinSupportedFrameRate,
124                      fps_approx_ops::operator<);
125 
126     return {start, end};
127 }
128 
shouldEnableFrameRateOverride(const std::vector<DisplayModeIterator> & sortedModes)129 bool shouldEnableFrameRateOverride(const std::vector<DisplayModeIterator>& sortedModes) {
130     for (const auto it1 : sortedModes) {
131         const auto& mode1 = it1->second;
132         for (const auto it2 : sortedModes) {
133             const auto& mode2 = it2->second;
134 
135             if (RefreshRateSelector::getFrameRateDivisor(mode1->getPeakFps(),
136                                                          mode2->getPeakFps()) >= 2) {
137                 return true;
138             }
139         }
140     }
141     return false;
142 }
143 
toString(const RefreshRateSelector::PolicyVariant & policy)144 std::string toString(const RefreshRateSelector::PolicyVariant& policy) {
145     using namespace std::string_literals;
146 
147     return ftl::match(
148             policy,
149             [](const RefreshRateSelector::DisplayManagerPolicy& policy) {
150                 return "DisplayManagerPolicy"s + policy.toString();
151             },
152             [](const RefreshRateSelector::OverridePolicy& policy) {
153                 return "OverridePolicy"s + policy.toString();
154             },
155             [](RefreshRateSelector::NoOverridePolicy) { return "NoOverridePolicy"s; });
156 }
157 
158 } // namespace
159 
createFrameRateModes(const Policy & policy,std::function<bool (const DisplayMode &)> && filterModes,const FpsRange & renderRange) const160 auto RefreshRateSelector::createFrameRateModes(
161         const Policy& policy, std::function<bool(const DisplayMode&)>&& filterModes,
162         const FpsRange& renderRange) const -> std::vector<FrameRateMode> {
163     struct Key {
164         Fps fps;
165         int32_t group;
166     };
167 
168     struct KeyLess {
169         bool operator()(const Key& a, const Key& b) const {
170             using namespace fps_approx_ops;
171             if (a.fps != b.fps) {
172                 return a.fps < b.fps;
173             }
174 
175             // For the same fps the order doesn't really matter, but we still
176             // want the behaviour of a strictly less operator.
177             // We use the group id as the secondary ordering for that.
178             return a.group < b.group;
179         }
180     };
181 
182     std::map<Key, DisplayModeIterator, KeyLess> ratesMap;
183     for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) {
184         const auto& [id, mode] = *it;
185 
186         if (!filterModes(*mode)) {
187             continue;
188         }
189         const auto vsyncRate = mode->getVsyncRate();
190         const auto peakFps = mode->getPeakFps();
191         const auto [start, end] =
192                 divisorRange(vsyncRate, peakFps, renderRange, mConfig.enableFrameRateOverride);
193         for (auto divisor = start; divisor <= end; divisor++) {
194             const auto fps = vsyncRate / divisor;
195             using fps_approx_ops::operator<;
196             if (divisor > 1 && fps < kMinSupportedFrameRate) {
197                 break;
198             }
199 
200             if (mConfig.enableFrameRateOverride == Config::FrameRateOverride::Enabled &&
201                 !renderRange.includes(fps)) {
202                 continue;
203             }
204 
205             if (mConfig.enableFrameRateOverride ==
206                         Config::FrameRateOverride::AppOverrideNativeRefreshRates &&
207                 !isNativeRefreshRate(fps)) {
208                 continue;
209             }
210 
211             const auto [existingIter, emplaceHappened] =
212                     ratesMap.try_emplace(Key{fps, mode->getGroup()}, it);
213             if (emplaceHappened) {
214                 ALOGV("%s: including %s (%s(%s))", __func__, to_string(fps).c_str(),
215                       to_string(peakFps).c_str(), to_string(vsyncRate).c_str());
216             } else {
217                 // If the primary physical range is a single rate, prefer to stay in that rate
218                 // even if there is a lower physical refresh rate available. This would cause more
219                 // cases to stay within the primary physical range
220                 const Fps existingModeFps = existingIter->second->second->getPeakFps();
221                 const bool existingModeIsPrimaryRange = policy.primaryRangeIsSingleRate() &&
222                         policy.primaryRanges.physical.includes(existingModeFps);
223                 const bool newModeIsPrimaryRange = policy.primaryRangeIsSingleRate() &&
224                         policy.primaryRanges.physical.includes(mode->getPeakFps());
225                 if (newModeIsPrimaryRange == existingModeIsPrimaryRange) {
226                     // We might need to update the map as we found a lower refresh rate
227                     if (isStrictlyLess(mode->getPeakFps(), existingModeFps)) {
228                         existingIter->second = it;
229                         ALOGV("%s: changing %s (%s(%s)) as we found a lower physical rate",
230                               __func__, to_string(fps).c_str(), to_string(peakFps).c_str(),
231                               to_string(vsyncRate).c_str());
232                     }
233                 } else if (newModeIsPrimaryRange) {
234                     existingIter->second = it;
235                     ALOGV("%s: changing %s (%s(%s)) to stay in the primary range", __func__,
236                           to_string(fps).c_str(), to_string(peakFps).c_str(),
237                           to_string(vsyncRate).c_str());
238                 }
239             }
240         }
241     }
242 
243     std::vector<FrameRateMode> frameRateModes;
244     frameRateModes.reserve(ratesMap.size());
245     for (const auto& [key, mode] : ratesMap) {
246         frameRateModes.emplace_back(FrameRateMode{key.fps, ftl::as_non_null(mode->second)});
247     }
248 
249     // We always want that the lowest frame rate will be corresponding to the
250     // lowest mode for power saving.
251     const auto lowestRefreshRateIt =
252             std::min_element(frameRateModes.begin(), frameRateModes.end(),
253                              [](const FrameRateMode& lhs, const FrameRateMode& rhs) {
254                                  return isStrictlyLess(lhs.modePtr->getVsyncRate(),
255                                                        rhs.modePtr->getVsyncRate());
256                              });
257     frameRateModes.erase(frameRateModes.begin(), lowestRefreshRateIt);
258 
259     return frameRateModes;
260 }
261 
262 struct RefreshRateSelector::RefreshRateScoreComparator {
operator ()android::scheduler::RefreshRateSelector::RefreshRateScoreComparator263     bool operator()(const RefreshRateScore& lhs, const RefreshRateScore& rhs) const {
264         const auto& [frameRateMode, overallScore, _] = lhs;
265 
266         std::string name = to_string(frameRateMode);
267 
268         ALOGV("%s sorting scores %.2f", name.c_str(), overallScore);
269 
270         if (!ScoredFrameRate::scoresEqual(overallScore, rhs.overallScore)) {
271             return overallScore > rhs.overallScore;
272         }
273 
274         if (refreshRateOrder == RefreshRateOrder::Descending) {
275             using fps_approx_ops::operator>;
276             return frameRateMode.fps > rhs.frameRateMode.fps;
277         } else {
278             using fps_approx_ops::operator<;
279             return frameRateMode.fps < rhs.frameRateMode.fps;
280         }
281     }
282 
283     const RefreshRateOrder refreshRateOrder;
284 };
285 
toString() const286 std::string RefreshRateSelector::Policy::toString() const {
287     return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
288                               ", primaryRanges=%s, appRequestRanges=%s idleScreenConfig=%s}",
289                               ftl::to_underlying(defaultMode),
290                               allowGroupSwitching ? "true" : "false",
291                               to_string(primaryRanges).c_str(), to_string(appRequestRanges).c_str(),
292                               idleScreenConfigOpt ? idleScreenConfigOpt->toString().c_str()
293                                                   : "nullptr");
294 }
295 
getDisplayFrames(nsecs_t layerPeriod,nsecs_t displayPeriod) const296 std::pair<nsecs_t, nsecs_t> RefreshRateSelector::getDisplayFrames(nsecs_t layerPeriod,
297                                                                   nsecs_t displayPeriod) const {
298     auto [quotient, remainder] = std::div(layerPeriod, displayPeriod);
299     if (remainder <= MARGIN_FOR_PERIOD_CALCULATION ||
300         std::abs(remainder - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) {
301         quotient++;
302         remainder = 0;
303     }
304 
305     return {quotient, remainder};
306 }
307 
calculateNonExactMatchingDefaultLayerScoreLocked(nsecs_t displayPeriod,nsecs_t layerPeriod) const308 float RefreshRateSelector::calculateNonExactMatchingDefaultLayerScoreLocked(
309         nsecs_t displayPeriod, nsecs_t layerPeriod) const {
310     // Find the actual rate the layer will render, assuming
311     // that layerPeriod is the minimal period to render a frame.
312     // For example if layerPeriod is 20ms and displayPeriod is 16ms,
313     // then the actualLayerPeriod will be 32ms, because it is the
314     // smallest multiple of the display period which is >= layerPeriod.
315     auto actualLayerPeriod = displayPeriod;
316     int multiplier = 1;
317     while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
318         multiplier++;
319         actualLayerPeriod = displayPeriod * multiplier;
320     }
321 
322     // Because of the threshold we used above it's possible that score is slightly
323     // above 1.
324     return std::min(1.0f, static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
325 }
326 
calculateNonExactMatchingLayerScoreLocked(const LayerRequirement & layer,Fps refreshRate) const327 float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer,
328                                                                      Fps refreshRate) const {
329     constexpr float kScoreForFractionalPairs = .8f;
330 
331     const auto displayPeriod = refreshRate.getPeriodNsecs();
332     const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
333     if (layer.vote == LayerVoteType::ExplicitDefault) {
334         return calculateNonExactMatchingDefaultLayerScoreLocked(displayPeriod, layerPeriod);
335     }
336 
337     if (layer.vote == LayerVoteType::ExplicitGte) {
338         using fps_approx_ops::operator>=;
339         if (refreshRate >= layer.desiredRefreshRate) {
340             return 1.0f;
341         } else {
342             return calculateDistanceScoreLocked(layer.desiredRefreshRate, refreshRate);
343         }
344     }
345 
346     if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
347         layer.vote == LayerVoteType::Heuristic) {
348         using fps_approx_ops::operator<;
349         if (refreshRate < 60_Hz) {
350             const bool favorsAtLeast60 =
351                     std::find_if(mFrameRatesThatFavorsAtLeast60.begin(),
352                                  mFrameRatesThatFavorsAtLeast60.end(), [&](Fps fps) {
353                                      using fps_approx_ops::operator==;
354                                      return fps == layer.desiredRefreshRate;
355                                  }) != mFrameRatesThatFavorsAtLeast60.end();
356             if (favorsAtLeast60) {
357                 return 0;
358             }
359         }
360 
361         const float multiplier = refreshRate.getValue() / layer.desiredRefreshRate.getValue();
362 
363         // We only want to score this layer as a fractional pair if the content is not
364         // significantly faster than the display rate, at it would cause a significant frame drop.
365         // It is more appropriate to choose a higher display rate even if
366         // a pull-down will be required.
367         constexpr float kMinMultiplier = 0.75f;
368         if (multiplier >= kMinMultiplier &&
369             isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) {
370             return kScoreForFractionalPairs;
371         }
372 
373         // Calculate how many display vsyncs we need to present a single frame for this
374         // layer
375         const auto [displayFramesQuotient, displayFramesRemainder] =
376                 getDisplayFrames(layerPeriod, displayPeriod);
377         static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
378         if (displayFramesRemainder == 0) {
379             // Layer desired refresh rate matches the display rate.
380             return 1.0f;
381         }
382 
383         if (displayFramesQuotient == 0) {
384             // Layer desired refresh rate is higher than the display rate.
385             return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
386                     (1.0f / (MAX_FRAMES_TO_FIT + 1));
387         }
388 
389         // Layer desired refresh rate is lower than the display rate. Check how well it fits
390         // the cadence.
391         auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder));
392         int iter = 2;
393         while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
394             diff = diff - (displayPeriod - diff);
395             iter++;
396         }
397 
398         return (1.0f / iter);
399     }
400 
401     return 0;
402 }
403 
calculateDistanceScoreLocked(Fps referenceRate,Fps refreshRate) const404 float RefreshRateSelector::calculateDistanceScoreLocked(Fps referenceRate, Fps refreshRate) const {
405     using fps_approx_ops::operator>=;
406     const float ratio = referenceRate >= refreshRate
407             ? refreshRate.getValue() / referenceRate.getValue()
408             : referenceRate.getValue() / refreshRate.getValue();
409     // Use ratio^2 to get a lower score the more we get further from the reference rate.
410     return ratio * ratio;
411 }
412 
calculateDistanceScoreFromMaxLocked(Fps refreshRate) const413 float RefreshRateSelector::calculateDistanceScoreFromMaxLocked(Fps refreshRate) const {
414     const auto& maxFps = mAppRequestFrameRates.back().fps;
415     return calculateDistanceScoreLocked(maxFps, refreshRate);
416 }
417 
calculateLayerScoreLocked(const LayerRequirement & layer,Fps refreshRate,bool isSeamlessSwitch) const418 float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
419                                                      bool isSeamlessSwitch) const {
420     // Slightly prefer seamless switches.
421     constexpr float kSeamedSwitchPenalty = 0.95f;
422     const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
423 
424     if (layer.vote == LayerVoteType::ExplicitCategory) {
425         // HighHint is considered later for touch boost.
426         if (layer.frameRateCategory == FrameRateCategory::HighHint) {
427             return 0.f;
428         }
429 
430         if (getFrameRateCategoryRange(layer.frameRateCategory).includes(refreshRate)) {
431             return 1.f;
432         }
433 
434         FpsRange categoryRange = getFrameRateCategoryRange(layer.frameRateCategory);
435         using fps_approx_ops::operator<;
436         if (refreshRate < categoryRange.min) {
437             return calculateNonExactMatchingDefaultLayerScoreLocked(refreshRate.getPeriodNsecs(),
438                                                                     categoryRange.min
439                                                                             .getPeriodNsecs());
440         }
441         return calculateNonExactMatchingDefaultLayerScoreLocked(refreshRate.getPeriodNsecs(),
442                                                                 categoryRange.max.getPeriodNsecs());
443     }
444 
445     // If the layer wants Max, give higher score to the higher refresh rate
446     if (layer.vote == LayerVoteType::Max) {
447         return calculateDistanceScoreFromMaxLocked(refreshRate);
448     }
449 
450     if (layer.vote == LayerVoteType::ExplicitExact) {
451         const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate);
452         if (supportsAppFrameRateOverrideByContent()) {
453             // Since we support frame rate override, allow refresh rates which are
454             // multiples of the layer's request, as those apps would be throttled
455             // down to run at the desired refresh rate.
456             return divisor > 0;
457         }
458 
459         return divisor == 1;
460     }
461 
462     // If the layer frame rate is a divisor of the refresh rate it should score
463     // the highest score.
464     if (layer.desiredRefreshRate.isValid() &&
465         getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) {
466         return 1.0f * seamlessness;
467     }
468 
469     // The layer frame rate is not a divisor of the refresh rate,
470     // there is a small penalty attached to the score to favor the frame rates
471     // the exactly matches the display refresh rate or a multiple.
472     constexpr float kNonExactMatchingPenalty = 0.95f;
473     return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness *
474             kNonExactMatchingPenalty;
475 }
476 
getRankedFrameRates(const std::vector<LayerRequirement> & layers,GlobalSignals signals,Fps pacesetterFps) const477 auto RefreshRateSelector::getRankedFrameRates(const std::vector<LayerRequirement>& layers,
478                                               GlobalSignals signals, Fps pacesetterFps) const
479         -> RankedFrameRates {
480     GetRankedFrameRatesCache cache{layers, signals, pacesetterFps};
481 
482     std::lock_guard lock(mLock);
483 
484     if (mGetRankedFrameRatesCache && mGetRankedFrameRatesCache->matches(cache)) {
485         return mGetRankedFrameRatesCache->result;
486     }
487 
488     cache.result = getRankedFrameRatesLocked(layers, signals, pacesetterFps);
489     mGetRankedFrameRatesCache = std::move(cache);
490     return mGetRankedFrameRatesCache->result;
491 }
492 
getRankedFrameRatesLocked(const std::vector<LayerRequirement> & layers,GlobalSignals signals,Fps pacesetterFps) const493 auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers,
494                                                     GlobalSignals signals, Fps pacesetterFps) const
495         -> RankedFrameRates {
496     using namespace fps_approx_ops;
497     ATRACE_CALL();
498     ALOGV("%s: %zu layers", __func__, layers.size());
499 
500     const auto& activeMode = *getActiveModeLocked().modePtr;
501 
502     if (pacesetterFps.isValid()) {
503         ALOGV("Follower display");
504 
505         const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Descending,
506                                             std::nullopt, [&](FrameRateMode mode) {
507                                                 return mode.modePtr->getPeakFps() == pacesetterFps;
508                                             });
509 
510         if (!ranking.empty()) {
511             ATRACE_FORMAT_INSTANT("%s (Follower display)",
512                                   to_string(ranking.front().frameRateMode.fps).c_str());
513 
514             return {ranking, kNoSignals, pacesetterFps};
515         }
516 
517         ALOGW("Follower display cannot follow the pacesetter");
518     }
519 
520     // Keep the display at max frame rate for the duration of powering on the display.
521     if (signals.powerOnImminent) {
522         ALOGV("Power On Imminent");
523         const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Descending);
524         ATRACE_FORMAT_INSTANT("%s (Power On Imminent)",
525                               to_string(ranking.front().frameRateMode.fps).c_str());
526         return {ranking, GlobalSignals{.powerOnImminent = true}};
527     }
528 
529     int noVoteLayers = 0;
530     // Layers that prefer the same mode ("no-op").
531     int noPreferenceLayers = 0;
532     int minVoteLayers = 0;
533     int maxVoteLayers = 0;
534     int explicitDefaultVoteLayers = 0;
535     int explicitExactOrMultipleVoteLayers = 0;
536     int explicitExact = 0;
537     int explicitGteLayers = 0;
538     int explicitCategoryVoteLayers = 0;
539     int interactiveLayers = 0;
540     int seamedFocusedLayers = 0;
541     int categorySmoothSwitchOnlyLayers = 0;
542 
543     for (const auto& layer : layers) {
544         switch (layer.vote) {
545             case LayerVoteType::NoVote:
546                 noVoteLayers++;
547                 break;
548             case LayerVoteType::Min:
549                 minVoteLayers++;
550                 break;
551             case LayerVoteType::Max:
552                 maxVoteLayers++;
553                 break;
554             case LayerVoteType::ExplicitDefault:
555                 explicitDefaultVoteLayers++;
556                 break;
557             case LayerVoteType::ExplicitExactOrMultiple:
558                 explicitExactOrMultipleVoteLayers++;
559                 break;
560             case LayerVoteType::ExplicitExact:
561                 explicitExact++;
562                 break;
563             case LayerVoteType::ExplicitGte:
564                 explicitGteLayers++;
565                 break;
566             case LayerVoteType::ExplicitCategory:
567                 if (layer.frameRateCategory == FrameRateCategory::HighHint) {
568                     // HighHint does not count as an explicit signal from an app. It may be
569                     // be a touch signal.
570                     interactiveLayers++;
571                 } else {
572                     explicitCategoryVoteLayers++;
573                 }
574                 if (layer.frameRateCategory == FrameRateCategory::NoPreference) {
575                     noPreferenceLayers++;
576                 }
577                 break;
578             case LayerVoteType::Heuristic:
579                 break;
580         }
581 
582         if (layer.seamlessness == Seamlessness::SeamedAndSeamless && layer.focused) {
583             seamedFocusedLayers++;
584         }
585         if (layer.frameRateCategorySmoothSwitchOnly) {
586             categorySmoothSwitchOnlyLayers++;
587         }
588     }
589 
590     const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 ||
591             explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0 || explicitGteLayers > 0 ||
592             explicitCategoryVoteLayers > 0;
593 
594     const Policy* policy = getCurrentPolicyLocked();
595     const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
596 
597     // If the default mode group is different from the group of current mode,
598     // this means a layer requesting a seamed mode switch just disappeared and
599     // we should switch back to the default group.
600     // However if a seamed layer is still present we anchor around the group
601     // of the current mode, in order to prevent unnecessary seamed mode switches
602     // (e.g. when pausing a video playback).
603     const auto anchorGroup =
604             seamedFocusedLayers > 0 ? activeMode.getGroup() : defaultMode->getGroup();
605 
606     // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
607     // selected a refresh rate to see if we should apply touch boost.
608     if (signals.touch && !hasExplicitVoteLayers) {
609         ALOGV("Touch Boost");
610         const auto ranking = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
611         ATRACE_FORMAT_INSTANT("%s (Touch Boost)",
612                               to_string(ranking.front().frameRateMode.fps).c_str());
613         return {ranking, GlobalSignals{.touch = true}};
614     }
615 
616     // If the primary range consists of a single refresh rate then we can only
617     // move out the of range if layers explicitly request a different refresh
618     // rate.
619     if (!signals.touch && signals.idle &&
620         !(policy->primaryRangeIsSingleRate() && hasExplicitVoteLayers)) {
621         ALOGV("Idle");
622         const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending);
623         ATRACE_FORMAT_INSTANT("%s (Idle)", to_string(ranking.front().frameRateMode.fps).c_str());
624         return {ranking, GlobalSignals{.idle = true}};
625     }
626 
627     if (layers.empty() || noVoteLayers == layers.size()) {
628         ALOGV("No layers with votes");
629         const auto ranking = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
630         ATRACE_FORMAT_INSTANT("%s (No layers with votes)",
631                               to_string(ranking.front().frameRateMode.fps).c_str());
632         return {ranking, kNoSignals};
633     }
634 
635     // If all layers are category NoPreference, use the current config.
636     if (noPreferenceLayers + noVoteLayers == layers.size()) {
637         ALOGV("All layers NoPreference");
638         const auto ascendingWithPreferred =
639                 rankFrameRates(anchorGroup, RefreshRateOrder::Ascending, activeMode.getId());
640         ATRACE_FORMAT_INSTANT("%s (All layers NoPreference)",
641                               to_string(ascendingWithPreferred.front().frameRateMode.fps).c_str());
642         return {ascendingWithPreferred, kNoSignals};
643     }
644 
645     const bool smoothSwitchOnly = categorySmoothSwitchOnlyLayers > 0;
646     const DisplayModeId activeModeId = activeMode.getId();
647 
648     // Only if all layers want Min we should return Min
649     if (noVoteLayers + minVoteLayers == layers.size()) {
650         ALOGV("All layers Min");
651         const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending,
652                                             std::nullopt, [&](FrameRateMode mode) {
653                                                 return !smoothSwitchOnly ||
654                                                         mode.modePtr->getId() == activeModeId;
655                                             });
656         ATRACE_FORMAT_INSTANT("%s (All layers Min)",
657                               to_string(ranking.front().frameRateMode.fps).c_str());
658         return {ranking, kNoSignals};
659     }
660 
661     // Find the best refresh rate based on score
662     std::vector<RefreshRateScore> scores;
663     scores.reserve(mAppRequestFrameRates.size());
664 
665     for (const FrameRateMode& it : mAppRequestFrameRates) {
666         scores.emplace_back(RefreshRateScore{it, 0.0f});
667     }
668 
669     for (const auto& layer : layers) {
670         ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f, category %s) ",
671               layer.name.c_str(), ftl::enum_string(layer.vote).c_str(), layer.weight,
672               layer.desiredRefreshRate.getValue(),
673               ftl::enum_string(layer.frameRateCategory).c_str());
674         if (layer.isNoVote() || layer.frameRateCategory == FrameRateCategory::NoPreference ||
675             layer.vote == LayerVoteType::Min) {
676             ALOGV("%s scoring skipped due to vote", formatLayerInfo(layer, layer.weight).c_str());
677             continue;
678         }
679 
680         const auto weight = layer.weight;
681 
682         for (auto& [mode, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
683             const auto& [fps, modePtr] = mode;
684             const bool isSeamlessSwitch = modePtr->getGroup() == activeMode.getGroup();
685 
686             if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
687                 ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s",
688                       formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(),
689                       to_string(activeMode).c_str());
690                 continue;
691             }
692 
693             if (layer.seamlessness == Seamlessness::SeamedAndSeamless && !isSeamlessSwitch &&
694                 !layer.focused) {
695                 ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
696                       " Current mode = %s",
697                       formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(),
698                       to_string(activeMode).c_str());
699                 continue;
700             }
701 
702             if (smoothSwitchOnly && modePtr->getId() != activeModeId) {
703                 ALOGV("%s ignores %s because it's non-VRR and smooth switch only."
704                       " Current mode = %s",
705                       formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(),
706                       to_string(activeMode).c_str());
707                 continue;
708             }
709 
710             // Layers with default seamlessness vote for the current mode group if
711             // there are layers with seamlessness=SeamedAndSeamless and for the default
712             // mode group otherwise. In second case, if the current mode group is different
713             // from the default, this means a layer with seamlessness=SeamedAndSeamless has just
714             // disappeared.
715             const bool isInPolicyForDefault = modePtr->getGroup() == anchorGroup;
716             if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) {
717                 ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(),
718                       to_string(*modePtr).c_str(), to_string(activeMode).c_str());
719                 continue;
720             }
721 
722             const bool inPrimaryPhysicalRange =
723                     policy->primaryRanges.physical.includes(modePtr->getPeakFps());
724             const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps);
725             if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) ||
726                  !inPrimaryRenderRange) &&
727                 !(layer.focused &&
728                   (layer.vote == LayerVoteType::ExplicitDefault ||
729                    layer.vote == LayerVoteType::ExplicitExact))) {
730                 // Only focused layers with ExplicitDefault frame rate settings are allowed to score
731                 // refresh rates outside the primary range.
732                 continue;
733             }
734 
735             const float layerScore = calculateLayerScoreLocked(layer, fps, isSeamlessSwitch);
736             const float weightedLayerScore = weight * layerScore;
737 
738             // Layer with fixed source has a special consideration which depends on the
739             // mConfig.frameRateMultipleThreshold. We don't want these layers to score
740             // refresh rates above the threshold, but we also don't want to favor the lower
741             // ones by having a greater number of layers scoring them. Instead, we calculate
742             // the score independently for these layers and later decide which
743             // refresh rates to add it. For example, desired 24 fps with 120 Hz threshold should not
744             // score 120 Hz, but desired 60 fps should contribute to the score.
745             const bool fixedSourceLayer = [](LayerVoteType vote) {
746                 switch (vote) {
747                     case LayerVoteType::ExplicitExactOrMultiple:
748                     case LayerVoteType::Heuristic:
749                         return true;
750                     case LayerVoteType::NoVote:
751                     case LayerVoteType::Min:
752                     case LayerVoteType::Max:
753                     case LayerVoteType::ExplicitDefault:
754                     case LayerVoteType::ExplicitExact:
755                     case LayerVoteType::ExplicitGte:
756                     case LayerVoteType::ExplicitCategory:
757                         return false;
758                 }
759             }(layer.vote);
760             const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 &&
761                     layer.desiredRefreshRate <
762                             Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
763             if (fixedSourceLayer && layerBelowThreshold) {
764                 const bool modeAboveThreshold =
765                         modePtr->getPeakFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
766                 if (modeAboveThreshold) {
767                     ALOGV("%s gives %s (%s(%s)) fixed source (above threshold) score of %.4f",
768                           formatLayerInfo(layer, weight).c_str(), to_string(fps).c_str(),
769                           to_string(modePtr->getPeakFps()).c_str(),
770                           to_string(modePtr->getVsyncRate()).c_str(), layerScore);
771                     fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
772                 } else {
773                     ALOGV("%s gives %s (%s(%s)) fixed source (below threshold) score of %.4f",
774                           formatLayerInfo(layer, weight).c_str(), to_string(fps).c_str(),
775                           to_string(modePtr->getPeakFps()).c_str(),
776                           to_string(modePtr->getVsyncRate()).c_str(), layerScore);
777                     fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
778                 }
779             } else {
780                 ALOGV("%s gives %s (%s(%s)) score of %.4f", formatLayerInfo(layer, weight).c_str(),
781                       to_string(fps).c_str(), to_string(modePtr->getPeakFps()).c_str(),
782                       to_string(modePtr->getVsyncRate()).c_str(), layerScore);
783                 overallScore += weightedLayerScore;
784             }
785         }
786     }
787 
788     // We want to find the best refresh rate without the fixed source layers,
789     // so we could know whether we should add the modeAboveThreshold scores or not.
790     // If the best refresh rate is already above the threshold, it means that
791     // some non-fixed source layers already scored it, so we can just add the score
792     // for all fixed source layers, even the ones that are above the threshold.
793     const bool maxScoreAboveThreshold = [&] {
794         if (mConfig.frameRateMultipleThreshold == 0 || scores.empty()) {
795             return false;
796         }
797 
798         const auto maxScoreIt =
799                 std::max_element(scores.begin(), scores.end(),
800                                  [](RefreshRateScore max, RefreshRateScore current) {
801                                      return current.overallScore > max.overallScore;
802                                  });
803         ALOGV("%s (%s(%s)) is the best refresh rate without fixed source layers. It is %s the "
804               "threshold for "
805               "refresh rate multiples",
806               to_string(maxScoreIt->frameRateMode.fps).c_str(),
807               to_string(maxScoreIt->frameRateMode.modePtr->getPeakFps()).c_str(),
808               to_string(maxScoreIt->frameRateMode.modePtr->getVsyncRate()).c_str(),
809               maxScoreAboveThreshold ? "above" : "below");
810         return maxScoreIt->frameRateMode.modePtr->getPeakFps() >=
811                 Fps::fromValue(mConfig.frameRateMultipleThreshold);
812     }();
813 
814     // Now we can add the fixed rate layers score
815     for (auto& [frameRateMode, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
816         overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold;
817         if (maxScoreAboveThreshold) {
818             overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
819         }
820         ALOGV("%s (%s(%s)) adjusted overallScore is %.4f", to_string(frameRateMode.fps).c_str(),
821               to_string(frameRateMode.modePtr->getPeakFps()).c_str(),
822               to_string(frameRateMode.modePtr->getVsyncRate()).c_str(), overallScore);
823     }
824 
825     // Now that we scored all the refresh rates we need to pick the one that got the highest
826     // overallScore. Sort the scores based on their overallScore in descending order of priority.
827     const RefreshRateOrder refreshRateOrder =
828             maxVoteLayers > 0 ? RefreshRateOrder::Descending : RefreshRateOrder::Ascending;
829     std::sort(scores.begin(), scores.end(),
830               RefreshRateScoreComparator{.refreshRateOrder = refreshRateOrder});
831 
832     FrameRateRanking ranking;
833     ranking.reserve(scores.size());
834 
835     std::transform(scores.begin(), scores.end(), back_inserter(ranking),
836                    [](const RefreshRateScore& score) {
837                        return ScoredFrameRate{score.frameRateMode, score.overallScore};
838                    });
839 
840     const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) {
841         return score.overallScore == 0;
842     });
843 
844     if (policy->primaryRangeIsSingleRate()) {
845         // If we never scored any layers, then choose the rate from the primary
846         // range instead of picking a random score from the app range.
847         if (noLayerScore) {
848             ALOGV("Layers not scored");
849             const auto descending = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
850             ATRACE_FORMAT_INSTANT("%s (Layers not scored)",
851                                   to_string(descending.front().frameRateMode.fps).c_str());
852             return {descending, kNoSignals};
853         } else {
854             ALOGV("primaryRangeIsSingleRate");
855             ATRACE_FORMAT_INSTANT("%s (primaryRangeIsSingleRate)",
856                                   to_string(ranking.front().frameRateMode.fps).c_str());
857             return {ranking, kNoSignals};
858         }
859     }
860 
861     // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
862     // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
863     // vote we should not change it if we get a touch event. Only apply touch boost if it will
864     // actually increase the refresh rate over the normal selection.
865     const auto isTouchBoostForExplicitExact = [&]() -> bool {
866         if (supportsAppFrameRateOverrideByContent()) {
867             // Enable touch boost if there are other layers besides exact
868             return explicitExact + noVoteLayers + explicitGteLayers != layers.size();
869         } else {
870             // Enable touch boost if there are no exact layers
871             return explicitExact == 0;
872         }
873     };
874 
875     const auto isTouchBoostForCategory = [&]() -> bool {
876         return explicitCategoryVoteLayers + noVoteLayers + explicitGteLayers != layers.size();
877     };
878 
879     // A method for UI Toolkit to send the touch signal via "HighHint" category vote,
880     // which will touch boost when there are no ExplicitDefault layer votes. This is an
881     // incomplete solution but accounts for cases such as games that use `setFrameRate` with default
882     // compatibility to limit the frame rate, which should not have touch boost.
883     const bool hasInteraction = signals.touch || interactiveLayers > 0;
884 
885     if (hasInteraction && explicitDefaultVoteLayers == 0 && isTouchBoostForExplicitExact() &&
886         isTouchBoostForCategory()) {
887         const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
888         using fps_approx_ops::operator<;
889 
890         if (scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) {
891             ALOGV("Touch Boost");
892             ATRACE_FORMAT_INSTANT("%s (Touch Boost [late])",
893                                   to_string(touchRefreshRates.front().frameRateMode.fps).c_str());
894             return {touchRefreshRates, GlobalSignals{.touch = true}};
895         }
896     }
897 
898     // If we never scored any layers, and we don't favor high refresh rates, prefer to stay with the
899     // current config
900     if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) {
901         ALOGV("preferredDisplayMode");
902         const auto ascendingWithPreferred =
903                 rankFrameRates(anchorGroup, RefreshRateOrder::Ascending, activeMode.getId());
904         ATRACE_FORMAT_INSTANT("%s (preferredDisplayMode)",
905                               to_string(ascendingWithPreferred.front().frameRateMode.fps).c_str());
906         return {ascendingWithPreferred, kNoSignals};
907     }
908 
909     ALOGV("%s (scored)", to_string(ranking.front().frameRateMode.fps).c_str());
910     ATRACE_FORMAT_INSTANT("%s (scored)", to_string(ranking.front().frameRateMode.fps).c_str());
911     return {ranking, kNoSignals};
912 }
913 
914 using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>;
915 using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>;
916 
groupLayersByUid(const std::vector<RefreshRateSelector::LayerRequirement> & layers)917 PerUidLayerRequirements groupLayersByUid(
918         const std::vector<RefreshRateSelector::LayerRequirement>& layers) {
919     PerUidLayerRequirements layersByUid;
920     for (const auto& layer : layers) {
921         const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first;
922         auto& layersWithSameUid = it->second;
923         layersWithSameUid.push_back(&layer);
924     }
925 
926     // Remove uids that can't have a frame rate override
927     for (auto it = layersByUid.begin(); it != layersByUid.end();) {
928         const auto& layersWithSameUid = it->second;
929         bool skipUid = false;
930         for (const auto& layer : layersWithSameUid) {
931             using LayerVoteType = RefreshRateSelector::LayerVoteType;
932 
933             if (layer->vote == LayerVoteType::Max || layer->vote == LayerVoteType::Heuristic) {
934                 skipUid = true;
935                 break;
936             }
937         }
938         if (skipUid) {
939             it = layersByUid.erase(it);
940         } else {
941             ++it;
942         }
943     }
944 
945     return layersByUid;
946 }
947 
getFrameRateOverrides(const std::vector<LayerRequirement> & layers,Fps displayRefreshRate,GlobalSignals globalSignals) const948 auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequirement>& layers,
949                                                 Fps displayRefreshRate,
950                                                 GlobalSignals globalSignals) const
951         -> UidToFrameRateOverride {
952     ATRACE_CALL();
953     if (mConfig.enableFrameRateOverride == Config::FrameRateOverride::Disabled) {
954         return {};
955     }
956 
957     ALOGV("%s: %zu layers", __func__, layers.size());
958     std::lock_guard lock(mLock);
959 
960     const auto* policyPtr = getCurrentPolicyLocked();
961     // We don't want to run lower than 30fps
962     // TODO(b/297600226): revise this for dVRR
963     const Fps minFrameRate = std::max(policyPtr->appRequestRanges.render.min, 30_Hz, isApproxLess);
964 
965     using fps_approx_ops::operator/;
966     const unsigned numMultiples = displayRefreshRate / minFrameRate;
967 
968     std::vector<std::pair<Fps, float>> scoredFrameRates;
969     scoredFrameRates.reserve(numMultiples);
970 
971     for (unsigned n = numMultiples; n > 0; n--) {
972         const Fps divisor = displayRefreshRate / n;
973         if (mConfig.enableFrameRateOverride ==
974                     Config::FrameRateOverride::AppOverrideNativeRefreshRates &&
975             !isNativeRefreshRate(divisor)) {
976             continue;
977         }
978 
979         if (policyPtr->appRequestRanges.render.includes(divisor)) {
980             ALOGV("%s: adding %s as a potential frame rate", __func__, to_string(divisor).c_str());
981             scoredFrameRates.emplace_back(divisor, 0);
982         }
983     }
984 
985     const auto layersByUid = groupLayersByUid(layers);
986     UidToFrameRateOverride frameRateOverrides;
987     for (const auto& [uid, layersWithSameUid] : layersByUid) {
988         // Look for cases that should not have frame rate overrides.
989         bool hasExplicitExactOrMultiple = false;
990         bool hasExplicitDefault = false;
991         bool hasHighHint = false;
992         for (const auto& layer : layersWithSameUid) {
993             switch (layer->vote) {
994                 case LayerVoteType::ExplicitExactOrMultiple:
995                     hasExplicitExactOrMultiple = true;
996                     break;
997                 case LayerVoteType::ExplicitDefault:
998                     hasExplicitDefault = true;
999                     break;
1000                 case LayerVoteType::ExplicitCategory:
1001                     if (layer->frameRateCategory == FrameRateCategory::HighHint) {
1002                         hasHighHint = true;
1003                     }
1004                     break;
1005                 default:
1006                     // No action
1007                     break;
1008             }
1009             if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint) {
1010                 break;
1011             }
1012         }
1013 
1014         // Layers with ExplicitExactOrMultiple expect touch boost
1015         if (globalSignals.touch && hasExplicitExactOrMultiple) {
1016             continue;
1017         }
1018 
1019         // Mirrors getRankedFrameRates. If there is no ExplicitDefault, expect touch boost and
1020         // skip frame rate override.
1021         if (hasHighHint && !hasExplicitDefault) {
1022             continue;
1023         }
1024 
1025         for (auto& [_, score] : scoredFrameRates) {
1026             score = 0;
1027         }
1028 
1029         for (const auto& layer : layersWithSameUid) {
1030             if (layer->isNoVote() || layer->frameRateCategory == FrameRateCategory::NoPreference ||
1031                 layer->vote == LayerVoteType::Min) {
1032                 continue;
1033             }
1034 
1035             LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
1036                                         layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
1037                                         layer->vote != LayerVoteType::ExplicitExact &&
1038                                         layer->vote != LayerVoteType::ExplicitGte &&
1039                                         layer->vote != LayerVoteType::ExplicitCategory,
1040                                 "Invalid layer vote type for frame rate overrides");
1041             for (auto& [fps, score] : scoredFrameRates) {
1042                 constexpr bool isSeamlessSwitch = true;
1043                 const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch);
1044                 score += layer->weight * layerScore;
1045             }
1046         }
1047 
1048         // If we never scored any layers, we don't have a preferred frame rate
1049         if (std::all_of(scoredFrameRates.begin(), scoredFrameRates.end(),
1050                         [](const auto& scoredFrameRate) {
1051                             const auto [_, score] = scoredFrameRate;
1052                             return score == 0;
1053                         })) {
1054             continue;
1055         }
1056 
1057         // Now that we scored all the refresh rates we need to pick the lowest refresh rate
1058         // that got the highest score.
1059         const auto [overrideFps, _] =
1060                 *std::max_element(scoredFrameRates.begin(), scoredFrameRates.end(),
1061                                   [](const auto& lhsPair, const auto& rhsPair) {
1062                                       const float lhs = lhsPair.second;
1063                                       const float rhs = rhsPair.second;
1064                                       return lhs < rhs && !ScoredFrameRate::scoresEqual(lhs, rhs);
1065                                   });
1066         ALOGV("%s: overriding to %s for uid=%d", __func__, to_string(overrideFps).c_str(), uid);
1067         ATRACE_FORMAT_INSTANT("%s: overriding to %s for uid=%d", __func__,
1068                               to_string(overrideFps).c_str(), uid);
1069         if (ATRACE_ENABLED() && FlagManager::getInstance().trace_frame_rate_override()) {
1070             std::stringstream ss;
1071             ss << "FrameRateOverride " << uid;
1072             ATRACE_INT(ss.str().c_str(), overrideFps.getIntValue());
1073         }
1074         frameRateOverrides.emplace(uid, overrideFps);
1075     }
1076 
1077     return frameRateOverrides;
1078 }
1079 
onKernelTimerChanged(ftl::Optional<DisplayModeId> desiredModeIdOpt,bool timerExpired) const1080 ftl::Optional<FrameRateMode> RefreshRateSelector::onKernelTimerChanged(
1081         ftl::Optional<DisplayModeId> desiredModeIdOpt, bool timerExpired) const {
1082     std::lock_guard lock(mLock);
1083 
1084     const auto current =
1085             desiredModeIdOpt
1086                     .and_then([this](DisplayModeId modeId)
1087                                       REQUIRES(mLock) { return mDisplayModes.get(modeId); })
1088                     .transform([](const DisplayModePtr& modePtr) {
1089                         return FrameRateMode{modePtr->getPeakFps(), ftl::as_non_null(modePtr)};
1090                     })
1091                     .or_else([this] {
1092                         ftl::FakeGuard guard(mLock);
1093                         return std::make_optional(getActiveModeLocked());
1094                     })
1095                     .value();
1096 
1097     const DisplayModePtr& min = mMinRefreshRateModeIt->second;
1098     if (current.modePtr->getId() == min->getId()) {
1099         return {};
1100     }
1101 
1102     return timerExpired ? FrameRateMode{min->getPeakFps(), ftl::as_non_null(min)} : current;
1103 }
1104 
getMinRefreshRateByPolicyLocked() const1105 const DisplayModePtr& RefreshRateSelector::getMinRefreshRateByPolicyLocked() const {
1106     const auto& activeMode = *getActiveModeLocked().modePtr;
1107 
1108     for (const FrameRateMode& mode : mPrimaryFrameRates) {
1109         if (activeMode.getGroup() == mode.modePtr->getGroup()) {
1110             return mode.modePtr.get();
1111         }
1112     }
1113 
1114     ALOGE("Can't find min refresh rate by policy with the same mode group as the current mode %s",
1115           to_string(activeMode).c_str());
1116 
1117     // Default to the lowest refresh rate.
1118     return mPrimaryFrameRates.front().modePtr.get();
1119 }
1120 
getMaxRefreshRateByPolicyLocked(int anchorGroup) const1121 const DisplayModePtr& RefreshRateSelector::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
1122     const ftl::NonNull<DisplayModePtr>* maxByAnchor = &mPrimaryFrameRates.back().modePtr;
1123     const ftl::NonNull<DisplayModePtr>* max = &mPrimaryFrameRates.back().modePtr;
1124 
1125     bool maxByAnchorFound = false;
1126     for (auto it = mPrimaryFrameRates.rbegin(); it != mPrimaryFrameRates.rend(); ++it) {
1127         using namespace fps_approx_ops;
1128         if (it->modePtr->getPeakFps() > (*max)->getPeakFps()) {
1129             max = &it->modePtr;
1130         }
1131 
1132         if (anchorGroup == it->modePtr->getGroup() &&
1133             it->modePtr->getPeakFps() >= (*maxByAnchor)->getPeakFps()) {
1134             maxByAnchorFound = true;
1135             maxByAnchor = &it->modePtr;
1136         }
1137     }
1138 
1139     if (maxByAnchorFound) {
1140         return maxByAnchor->get();
1141     }
1142 
1143     ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup);
1144 
1145     // Default to the highest refresh rate.
1146     return max->get();
1147 }
1148 
rankFrameRates(std::optional<int> anchorGroupOpt,RefreshRateOrder refreshRateOrder,std::optional<DisplayModeId> preferredDisplayModeOpt,const RankFrameRatesPredicate & predicate) const1149 auto RefreshRateSelector::rankFrameRates(std::optional<int> anchorGroupOpt,
1150                                          RefreshRateOrder refreshRateOrder,
1151                                          std::optional<DisplayModeId> preferredDisplayModeOpt,
1152                                          const RankFrameRatesPredicate& predicate) const
1153         -> FrameRateRanking {
1154     using fps_approx_ops::operator<;
1155     const char* const whence = __func__;
1156 
1157     // find the highest frame rate for each display mode
1158     ftl::SmallMap<DisplayModeId, Fps, 8> maxRenderRateForMode;
1159     const bool ascending = (refreshRateOrder == RefreshRateOrder::Ascending);
1160     if (ascending) {
1161         // TODO(b/266481656): Once this bug is fixed, we can remove this workaround and actually
1162         //  use a lower frame rate when we want Ascending frame rates.
1163         for (const auto& frameRateMode : mPrimaryFrameRates) {
1164             if (anchorGroupOpt && frameRateMode.modePtr->getGroup() != anchorGroupOpt) {
1165                 continue;
1166             }
1167 
1168             const auto [iter, _] = maxRenderRateForMode.try_emplace(frameRateMode.modePtr->getId(),
1169                                                                     frameRateMode.fps);
1170             if (iter->second < frameRateMode.fps) {
1171                 iter->second = frameRateMode.fps;
1172             }
1173         }
1174     }
1175 
1176     std::deque<ScoredFrameRate> ranking;
1177     const auto rankFrameRate = [&](const FrameRateMode& frameRateMode) REQUIRES(mLock) {
1178         const auto& modePtr = frameRateMode.modePtr;
1179         if ((anchorGroupOpt && modePtr->getGroup() != anchorGroupOpt) ||
1180             !predicate(frameRateMode)) {
1181             return;
1182         }
1183 
1184         const bool ascending = (refreshRateOrder == RefreshRateOrder::Ascending);
1185         const auto id = modePtr->getId();
1186         if (ascending && frameRateMode.fps < *maxRenderRateForMode.get(id)) {
1187             // TODO(b/266481656): Once this bug is fixed, we can remove this workaround and actually
1188             //  use a lower frame rate when we want Ascending frame rates.
1189             return;
1190         }
1191 
1192         float score = calculateDistanceScoreFromMaxLocked(frameRateMode.fps);
1193 
1194         if (ascending) {
1195             score = 1.0f / score;
1196         }
1197 
1198         constexpr float kScore = std::numeric_limits<float>::max();
1199         if (preferredDisplayModeOpt) {
1200             if (*preferredDisplayModeOpt == modePtr->getId()) {
1201                 ranking.emplace_front(ScoredFrameRate{frameRateMode, kScore});
1202                 return;
1203             }
1204             constexpr float kNonPreferredModePenalty = 0.95f;
1205             score *= kNonPreferredModePenalty;
1206         } else if (ascending && id == getMinRefreshRateByPolicyLocked()->getId()) {
1207             // TODO(b/266481656): Once this bug is fixed, we can remove this workaround
1208             //  and actually use a lower frame rate when we want Ascending frame rates.
1209             ranking.emplace_front(ScoredFrameRate{frameRateMode, kScore});
1210             return;
1211         }
1212 
1213         ALOGV("%s(%s) %s (%s(%s)) scored %.2f", whence, ftl::enum_string(refreshRateOrder).c_str(),
1214               to_string(frameRateMode.fps).c_str(), to_string(modePtr->getPeakFps()).c_str(),
1215               to_string(modePtr->getVsyncRate()).c_str(), score);
1216         ranking.emplace_back(ScoredFrameRate{frameRateMode, score});
1217     };
1218 
1219     if (refreshRateOrder == RefreshRateOrder::Ascending) {
1220         std::for_each(mPrimaryFrameRates.begin(), mPrimaryFrameRates.end(), rankFrameRate);
1221     } else {
1222         std::for_each(mPrimaryFrameRates.rbegin(), mPrimaryFrameRates.rend(), rankFrameRate);
1223     }
1224 
1225     if (!ranking.empty() || !anchorGroupOpt) {
1226         return {ranking.begin(), ranking.end()};
1227     }
1228 
1229     ALOGW("Can't find %s refresh rate by policy with the same mode group"
1230           " as the mode group %d",
1231           refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value());
1232 
1233     constexpr std::optional<int> kNoAnchorGroup = std::nullopt;
1234     return rankFrameRates(kNoAnchorGroup, refreshRateOrder, preferredDisplayModeOpt);
1235 }
1236 
getActiveMode() const1237 FrameRateMode RefreshRateSelector::getActiveMode() const {
1238     std::lock_guard lock(mLock);
1239     return getActiveModeLocked();
1240 }
1241 
getActiveModeLocked() const1242 const FrameRateMode& RefreshRateSelector::getActiveModeLocked() const {
1243     return *mActiveModeOpt;
1244 }
1245 
setActiveMode(DisplayModeId modeId,Fps renderFrameRate)1246 void RefreshRateSelector::setActiveMode(DisplayModeId modeId, Fps renderFrameRate) {
1247     std::lock_guard lock(mLock);
1248 
1249     // Invalidate the cached invocation to getRankedFrameRates. This forces
1250     // the refresh rate to be recomputed on the next call to getRankedFrameRates.
1251     mGetRankedFrameRatesCache.reset();
1252 
1253     const auto activeModeOpt = mDisplayModes.get(modeId);
1254     LOG_ALWAYS_FATAL_IF(!activeModeOpt);
1255 
1256     mActiveModeOpt.emplace(FrameRateMode{renderFrameRate, ftl::as_non_null(activeModeOpt->get())});
1257     mIsVrrDevice = FlagManager::getInstance().vrr_config() &&
1258             activeModeOpt->get()->getVrrConfig().has_value();
1259 }
1260 
RefreshRateSelector(DisplayModes modes,DisplayModeId activeModeId,Config config)1261 RefreshRateSelector::RefreshRateSelector(DisplayModes modes, DisplayModeId activeModeId,
1262                                          Config config)
1263       : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
1264     initializeIdleTimer(mConfig.legacyIdleTimerTimeout);
1265     FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId));
1266 }
1267 
initializeIdleTimer(std::chrono::milliseconds timeout)1268 void RefreshRateSelector::initializeIdleTimer(std::chrono::milliseconds timeout) {
1269     if (timeout > 0ms) {
1270         mIdleTimer.emplace(
1271                 "IdleTimer", timeout,
1272                 [this] {
1273                     std::scoped_lock lock(mIdleTimerCallbacksMutex);
1274                     if (const auto callbacks = getIdleTimerCallbacks()) {
1275                         callbacks->onReset();
1276                     }
1277                 },
1278                 [this] {
1279                     std::scoped_lock lock(mIdleTimerCallbacksMutex);
1280                     if (const auto callbacks = getIdleTimerCallbacks()) {
1281                         callbacks->onExpired();
1282                     }
1283                 });
1284     }
1285 }
1286 
updateDisplayModes(DisplayModes modes,DisplayModeId activeModeId)1287 void RefreshRateSelector::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) {
1288     std::lock_guard lock(mLock);
1289 
1290     // Invalidate the cached invocation to getRankedFrameRates. This forces
1291     // the refresh rate to be recomputed on the next call to getRankedFrameRates.
1292     mGetRankedFrameRatesCache.reset();
1293 
1294     mDisplayModes = std::move(modes);
1295     const auto activeModeOpt = mDisplayModes.get(activeModeId);
1296     LOG_ALWAYS_FATAL_IF(!activeModeOpt);
1297     mActiveModeOpt = FrameRateMode{activeModeOpt->get()->getPeakFps(),
1298                                    ftl::as_non_null(activeModeOpt->get())};
1299 
1300     const auto sortedModes = sortByRefreshRate(mDisplayModes);
1301     mMinRefreshRateModeIt = sortedModes.front();
1302     mMaxRefreshRateModeIt = sortedModes.back();
1303 
1304     // Reset the policy because the old one may no longer be valid.
1305     mDisplayManagerPolicy = {};
1306     mDisplayManagerPolicy.defaultMode = activeModeId;
1307 
1308     mFrameRateOverrideConfig = [&] {
1309         switch (mConfig.enableFrameRateOverride) {
1310             case Config::FrameRateOverride::Disabled:
1311             case Config::FrameRateOverride::AppOverride:
1312             case Config::FrameRateOverride::Enabled:
1313                 return mConfig.enableFrameRateOverride;
1314             case Config::FrameRateOverride::AppOverrideNativeRefreshRates:
1315                 return shouldEnableFrameRateOverride(sortedModes)
1316                         ? Config::FrameRateOverride::AppOverrideNativeRefreshRates
1317                         : Config::FrameRateOverride::Disabled;
1318         }
1319     }();
1320 
1321     if (mConfig.enableFrameRateOverride ==
1322         Config::FrameRateOverride::AppOverrideNativeRefreshRates) {
1323         for (const auto& [_, mode] : mDisplayModes) {
1324             mAppOverrideNativeRefreshRates.try_emplace(mode->getPeakFps(), ftl::unit);
1325         }
1326     }
1327 
1328     constructAvailableRefreshRates();
1329 }
1330 
isPolicyValidLocked(const Policy & policy) const1331 bool RefreshRateSelector::isPolicyValidLocked(const Policy& policy) const {
1332     // defaultMode must be a valid mode, and within the given refresh rate range.
1333     if (const auto mode = mDisplayModes.get(policy.defaultMode)) {
1334         if (!policy.primaryRanges.physical.includes(mode->get()->getPeakFps())) {
1335             ALOGE("Default mode is not in the primary range.");
1336             return false;
1337         }
1338     } else {
1339         ALOGE("Default mode is not found.");
1340         return false;
1341     }
1342 
1343     const auto& primaryRanges = policy.primaryRanges;
1344     const auto& appRequestRanges = policy.appRequestRanges;
1345     ALOGE_IF(!appRequestRanges.physical.includes(primaryRanges.physical),
1346              "Physical range is invalid: primary: %s appRequest: %s",
1347              to_string(primaryRanges.physical).c_str(),
1348              to_string(appRequestRanges.physical).c_str());
1349     ALOGE_IF(!appRequestRanges.render.includes(primaryRanges.render),
1350              "Render range is invalid: primary: %s appRequest: %s",
1351              to_string(primaryRanges.render).c_str(), to_string(appRequestRanges.render).c_str());
1352 
1353     return primaryRanges.valid() && appRequestRanges.valid();
1354 }
1355 
setPolicy(const PolicyVariant & policy)1356 auto RefreshRateSelector::setPolicy(const PolicyVariant& policy) -> SetPolicyResult {
1357     Policy oldPolicy;
1358     PhysicalDisplayId displayId;
1359     {
1360         std::lock_guard lock(mLock);
1361         oldPolicy = *getCurrentPolicyLocked();
1362 
1363         const bool valid = ftl::match(
1364                 policy,
1365                 [this](const auto& policy) {
1366                     ftl::FakeGuard guard(mLock);
1367                     if (!isPolicyValidLocked(policy)) {
1368                         ALOGE("Invalid policy: %s", policy.toString().c_str());
1369                         return false;
1370                     }
1371 
1372                     using T = std::decay_t<decltype(policy)>;
1373 
1374                     if constexpr (std::is_same_v<T, DisplayManagerPolicy>) {
1375                         mDisplayManagerPolicy = policy;
1376                     } else {
1377                         static_assert(std::is_same_v<T, OverridePolicy>);
1378                         mOverridePolicy = policy;
1379                     }
1380                     return true;
1381                 },
1382                 [this](NoOverridePolicy) {
1383                     ftl::FakeGuard guard(mLock);
1384                     mOverridePolicy.reset();
1385                     return true;
1386                 });
1387 
1388         if (!valid) {
1389             return SetPolicyResult::Invalid;
1390         }
1391 
1392         mGetRankedFrameRatesCache.reset();
1393 
1394         const auto& idleScreenConfigOpt = getCurrentPolicyLocked()->idleScreenConfigOpt;
1395         if (idleScreenConfigOpt != oldPolicy.idleScreenConfigOpt) {
1396             if (!idleScreenConfigOpt.has_value()) {
1397                 // fallback to legacy timer if existed, otherwise pause the old timer
1398                 LOG_ALWAYS_FATAL_IF(!mIdleTimer);
1399                 if (mConfig.legacyIdleTimerTimeout > 0ms) {
1400                     mIdleTimer->setInterval(mConfig.legacyIdleTimerTimeout);
1401                     mIdleTimer->resume();
1402                 } else {
1403                     mIdleTimer->pause();
1404                 }
1405             } else if (idleScreenConfigOpt->timeoutMillis > 0) {
1406                 // create a new timer or reconfigure
1407                 const auto timeout = std::chrono::milliseconds{idleScreenConfigOpt->timeoutMillis};
1408                 if (!mIdleTimer) {
1409                     initializeIdleTimer(timeout);
1410                     if (mIdleTimerStarted) {
1411                         mIdleTimer->start();
1412                     }
1413                 } else {
1414                     mIdleTimer->setInterval(timeout);
1415                     mIdleTimer->resume();
1416                 }
1417             } else {
1418                 if (mIdleTimer) {
1419                     mIdleTimer->pause();
1420                 }
1421             }
1422         }
1423 
1424         if (getCurrentPolicyLocked()->similarExceptIdleConfig(oldPolicy)) {
1425             return SetPolicyResult::Unchanged;
1426         }
1427 
1428         constructAvailableRefreshRates();
1429 
1430         displayId = getActiveModeLocked().modePtr->getPhysicalDisplayId();
1431     }
1432 
1433     const unsigned numModeChanges = std::exchange(mNumModeSwitchesInPolicy, 0u);
1434 
1435     ALOGI("Display %s policy changed\n"
1436           "Previous: %s\n"
1437           "Current:  %s\n"
1438           "%u mode changes were performed under the previous policy",
1439           to_string(displayId).c_str(), oldPolicy.toString().c_str(), toString(policy).c_str(),
1440           numModeChanges);
1441 
1442     return SetPolicyResult::Changed;
1443 }
1444 
getCurrentPolicyLocked() const1445 auto RefreshRateSelector::getCurrentPolicyLocked() const -> const Policy* {
1446     return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy;
1447 }
1448 
getCurrentPolicy() const1449 auto RefreshRateSelector::getCurrentPolicy() const -> Policy {
1450     std::lock_guard lock(mLock);
1451     return *getCurrentPolicyLocked();
1452 }
1453 
getDisplayManagerPolicy() const1454 auto RefreshRateSelector::getDisplayManagerPolicy() const -> Policy {
1455     std::lock_guard lock(mLock);
1456     return mDisplayManagerPolicy;
1457 }
1458 
isModeAllowed(const FrameRateMode & mode) const1459 bool RefreshRateSelector::isModeAllowed(const FrameRateMode& mode) const {
1460     std::lock_guard lock(mLock);
1461     return std::find(mAppRequestFrameRates.begin(), mAppRequestFrameRates.end(), mode) !=
1462             mAppRequestFrameRates.end();
1463 }
1464 
constructAvailableRefreshRates()1465 void RefreshRateSelector::constructAvailableRefreshRates() {
1466     // Filter modes based on current policy and sort on refresh rate.
1467     const Policy* policy = getCurrentPolicyLocked();
1468     ALOGV("%s: %s ", __func__, policy->toString().c_str());
1469 
1470     const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
1471 
1472     const auto filterRefreshRates = [&](const FpsRanges& ranges,
1473                                         const char* rangeName) REQUIRES(mLock) {
1474         const auto filterModes = [&](const DisplayMode& mode) {
1475             return mode.getResolution() == defaultMode->getResolution() &&
1476                     mode.getDpi() == defaultMode->getDpi() &&
1477                     (policy->allowGroupSwitching || mode.getGroup() == defaultMode->getGroup()) &&
1478                     ranges.physical.includes(mode.getPeakFps()) &&
1479                     (supportsFrameRateOverride() || ranges.render.includes(mode.getPeakFps()));
1480         };
1481 
1482         auto frameRateModes = createFrameRateModes(*policy, filterModes, ranges.render);
1483         if (frameRateModes.empty()) {
1484             ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName,
1485                   policy->toString().c_str());
1486             // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than
1487             // the min supported. See b/292047939.
1488             //  For not we just ignore the render ranges.
1489             frameRateModes = createFrameRateModes(*policy, filterModes, {});
1490         }
1491         LOG_ALWAYS_FATAL_IF(frameRateModes.empty(),
1492                             "No matching frame rate modes for %s range even after ignoring the "
1493                             "render range. policy: %s",
1494                             rangeName, policy->toString().c_str());
1495 
1496         const auto stringifyModes = [&] {
1497             std::string str;
1498             for (const auto& frameRateMode : frameRateModes) {
1499                 str += to_string(frameRateMode) + " ";
1500             }
1501             return str;
1502         };
1503         ALOGV("%s render rates: %s, isVrrDevice? %d", rangeName, stringifyModes().c_str(),
1504               mIsVrrDevice.load());
1505 
1506         return frameRateModes;
1507     };
1508 
1509     mPrimaryFrameRates = filterRefreshRates(policy->primaryRanges, "primary");
1510     mAppRequestFrameRates = filterRefreshRates(policy->appRequestRanges, "app request");
1511 }
1512 
isVrrDevice() const1513 bool RefreshRateSelector::isVrrDevice() const {
1514     return mIsVrrDevice;
1515 }
1516 
findClosestKnownFrameRate(Fps frameRate) const1517 Fps RefreshRateSelector::findClosestKnownFrameRate(Fps frameRate) const {
1518     using namespace fps_approx_ops;
1519 
1520     if (frameRate <= mKnownFrameRates.front()) {
1521         return mKnownFrameRates.front();
1522     }
1523 
1524     if (frameRate >= mKnownFrameRates.back()) {
1525         return mKnownFrameRates.back();
1526     }
1527 
1528     auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate,
1529                                        isStrictlyLess);
1530 
1531     const auto distance1 = std::abs(frameRate.getValue() - lowerBound->getValue());
1532     const auto distance2 = std::abs(frameRate.getValue() - std::prev(lowerBound)->getValue());
1533     return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
1534 }
1535 
getIdleTimerAction() const1536 auto RefreshRateSelector::getIdleTimerAction() const -> KernelIdleTimerAction {
1537     std::lock_guard lock(mLock);
1538 
1539     const Fps deviceMinFps = mMinRefreshRateModeIt->second->getPeakFps();
1540     const DisplayModePtr& minByPolicy = getMinRefreshRateByPolicyLocked();
1541 
1542     // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
1543     // the min allowed refresh rate is higher than the device min, we do not want to enable the
1544     // timer.
1545     if (isStrictlyLess(deviceMinFps, minByPolicy->getPeakFps())) {
1546         return KernelIdleTimerAction::TurnOff;
1547     }
1548 
1549     const DisplayModePtr& maxByPolicy =
1550             getMaxRefreshRateByPolicyLocked(getActiveModeLocked().modePtr->getGroup());
1551     if (minByPolicy == maxByPolicy) {
1552         // Turn on the timer when the min of the primary range is below the device min.
1553         if (const Policy* currentPolicy = getCurrentPolicyLocked();
1554             isApproxLess(currentPolicy->primaryRanges.physical.min, deviceMinFps)) {
1555             return KernelIdleTimerAction::TurnOn;
1556         }
1557         return KernelIdleTimerAction::TurnOff;
1558     }
1559 
1560     // Turn on the timer in all other cases.
1561     return KernelIdleTimerAction::TurnOn;
1562 }
1563 
getFrameRateDivisor(Fps displayRefreshRate,Fps layerFrameRate)1564 int RefreshRateSelector::getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate) {
1565     // This calculation needs to be in sync with the java code
1566     // in DisplayManagerService.getDisplayInfoForFrameRateOverride
1567 
1568     // The threshold must be smaller than 0.001 in order to differentiate
1569     // between the fractional pairs (e.g. 59.94 and 60).
1570     constexpr float kThreshold = 0.0009f;
1571     const auto numPeriods = displayRefreshRate.getValue() / layerFrameRate.getValue();
1572     const auto numPeriodsRounded = std::round(numPeriods);
1573     if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
1574         return 0;
1575     }
1576 
1577     return static_cast<int>(numPeriodsRounded);
1578 }
1579 
isFractionalPairOrMultiple(Fps smaller,Fps bigger)1580 bool RefreshRateSelector::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
1581     if (isStrictlyLess(bigger, smaller)) {
1582         return isFractionalPairOrMultiple(bigger, smaller);
1583     }
1584 
1585     const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
1586     constexpr float kCoef = 1000.f / 1001.f;
1587     return isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier / kCoef)) ||
1588             isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef));
1589 }
1590 
dump(utils::Dumper & dumper) const1591 void RefreshRateSelector::dump(utils::Dumper& dumper) const {
1592     using namespace std::string_view_literals;
1593 
1594     std::lock_guard lock(mLock);
1595 
1596     const auto activeMode = getActiveModeLocked();
1597     dumper.dump("renderRate"sv, to_string(activeMode.fps));
1598     dumper.dump("activeMode"sv, to_string(*activeMode.modePtr));
1599 
1600     dumper.dump("displayModes"sv);
1601     {
1602         utils::Dumper::Indent indent(dumper);
1603         for (const auto& [id, mode] : mDisplayModes) {
1604             dumper.dump({}, to_string(*mode));
1605         }
1606     }
1607 
1608     dumper.dump("displayManagerPolicy"sv, mDisplayManagerPolicy.toString());
1609 
1610     if (const Policy& currentPolicy = *getCurrentPolicyLocked();
1611         mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
1612         dumper.dump("overridePolicy"sv, currentPolicy.toString());
1613     }
1614 
1615     dumper.dump("frameRateOverrideConfig"sv, *ftl::enum_name(mFrameRateOverrideConfig));
1616 
1617     dumper.dump("idleTimer"sv);
1618     {
1619         utils::Dumper::Indent indent(dumper);
1620         dumper.dump("interval"sv, mIdleTimer.transform(&OneShotTimer::interval));
1621         dumper.dump("controller"sv,
1622                     mConfig.kernelIdleTimerController
1623                             .and_then(&ftl::enum_name<KernelIdleTimerController>)
1624                             .value_or("Platform"sv));
1625     }
1626 }
1627 
getIdleTimerTimeout()1628 std::chrono::milliseconds RefreshRateSelector::getIdleTimerTimeout() {
1629     if (FlagManager::getInstance().idle_screen_refresh_rate_timeout() && mIdleTimer) {
1630         return std::chrono::duration_cast<std::chrono::milliseconds>(mIdleTimer->interval());
1631     }
1632     return mConfig.legacyIdleTimerTimeout;
1633 }
1634 
1635 // TODO(b/293651105): Extract category FpsRange mapping to OEM-configurable config.
getFrameRateCategoryRange(FrameRateCategory category)1636 FpsRange RefreshRateSelector::getFrameRateCategoryRange(FrameRateCategory category) {
1637     switch (category) {
1638         case FrameRateCategory::High:
1639             return FpsRange{90_Hz, 120_Hz};
1640         case FrameRateCategory::Normal:
1641             return FpsRange{60_Hz, 120_Hz};
1642         case FrameRateCategory::Low:
1643             return FpsRange{30_Hz, 120_Hz};
1644         case FrameRateCategory::HighHint:
1645         case FrameRateCategory::NoPreference:
1646         case FrameRateCategory::Default:
1647             LOG_ALWAYS_FATAL("Should not get fps range for frame rate category: %s",
1648                              ftl::enum_string(category).c_str());
1649         default:
1650             LOG_ALWAYS_FATAL("Invalid frame rate category for range: %s",
1651                              ftl::enum_string(category).c_str());
1652     }
1653 }
1654 
1655 } // namespace android::scheduler
1656 
1657 // TODO(b/129481165): remove the #pragma below and fix conversion issues
1658 #pragma clang diagnostic pop // ignored "-Wextra"
1659