1 /*
2  * Copyright 2020 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 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wextra"
20 
21 // #define LOG_NDEBUG 0
22 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
23 
24 #include "LayerInfo.h"
25 
26 #include <algorithm>
27 #include <utility>
28 
29 #include <android/native_window.h>
30 #include <cutils/compiler.h>
31 #include <cutils/trace.h>
32 #include <ftl/enum.h>
33 #include <gui/TraceUtils.h>
34 #include <system/window.h>
35 
36 #undef LOG_TAG
37 #define LOG_TAG "LayerInfo"
38 
39 namespace android::scheduler {
40 
41 bool LayerInfo::sTraceEnabled = false;
42 
LayerInfo(const std::string & name,uid_t ownerUid,LayerHistory::LayerVoteType defaultVote)43 LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid,
44                      LayerHistory::LayerVoteType defaultVote)
45       : mName(name),
46         mOwnerUid(ownerUid),
47         mDefaultVote(defaultVote),
48         mLayerVote({defaultVote, Fps()}),
49         mLayerProps(std::make_unique<LayerProps>()),
50         mRefreshRateHistory(name) {
51     ;
52 }
53 
setLastPresentTime(nsecs_t lastPresentTime,nsecs_t now,LayerUpdateType updateType,bool pendingModeChange,const LayerProps & props)54 void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
55                                    bool pendingModeChange, const LayerProps& props) {
56     lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
57 
58     *mLayerProps = props;
59     switch (updateType) {
60         case LayerUpdateType::AnimationTX:
61             mLastUpdatedTime = std::max(lastPresentTime, now);
62             mLastAnimationTime = std::max(lastPresentTime, now);
63             break;
64         case LayerUpdateType::SetFrameRate:
65             if (FlagManager::getInstance().vrr_config()) {
66                 break;
67             }
68             FALLTHROUGH_INTENDED;
69         case LayerUpdateType::Buffer:
70             mLastUpdatedTime = std::max(lastPresentTime, now);
71             FrameTimeData frameTime = {.presentTime = lastPresentTime,
72                                        .queueTime = mLastUpdatedTime,
73                                        .pendingModeChange = pendingModeChange,
74                                        .isSmallDirty = props.isSmallDirty};
75             mFrameTimes.push_back(frameTime);
76             if (mFrameTimes.size() > HISTORY_SIZE) {
77                 mFrameTimes.pop_front();
78             }
79             break;
80     }
81 }
82 
setProperties(const android::scheduler::LayerProps & properties)83 void LayerInfo::setProperties(const android::scheduler::LayerProps& properties) {
84     *mLayerProps = properties;
85 }
86 
isFrameTimeValid(const FrameTimeData & frameTime) const87 bool LayerInfo::isFrameTimeValid(const FrameTimeData& frameTime) const {
88     return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>(
89                                           mFrameTimeValidSince.time_since_epoch())
90                                           .count();
91 }
92 
isFrequent(nsecs_t now) const93 LayerInfo::Frequent LayerInfo::isFrequent(nsecs_t now) const {
94     // If we know nothing about this layer (e.g. after touch event),
95     // we consider it as frequent as it might be the start of an animation.
96     if (mFrameTimes.size() < kFrequentLayerWindowSize) {
97         return {/* isFrequent */ true, /* clearHistory */ false, /* isConclusive */ true};
98     }
99 
100     // Non-active layers are also infrequent
101     if (mLastUpdatedTime < getActiveLayerThreshold(now)) {
102         return {/* isFrequent */ false, /* clearHistory */ false, /* isConclusive */ true};
103     }
104 
105     // We check whether we can classify this layer as frequent or infrequent:
106     //  - frequent: a layer posted kFrequentLayerWindowSize within
107     //              kMaxPeriodForFrequentLayerNs of each other.
108     // -  infrequent: a layer posted kFrequentLayerWindowSize with longer
109     //                gaps than kFrequentLayerWindowSize.
110     // If we can't determine the layer classification yet, we return the last
111     // classification.
112     bool isFrequent = true;
113     bool isInfrequent = true;
114     int32_t smallDirtyCount = 0;
115     const auto n = mFrameTimes.size() - 1;
116     for (size_t i = 0; i < kFrequentLayerWindowSize - 1; i++) {
117         if (mFrameTimes[n - i].queueTime - mFrameTimes[n - i - 1].queueTime <
118             kMaxPeriodForFrequentLayerNs.count()) {
119             isInfrequent = false;
120             if (mFrameTimes[n - i].presentTime == 0 && mFrameTimes[n - i].isSmallDirty) {
121                 smallDirtyCount++;
122             }
123         } else {
124             isFrequent = false;
125         }
126     }
127 
128     // Vote the small dirty when a layer contains at least HISTORY_SIZE of small dirty updates.
129     bool isSmallDirty = false;
130     if (smallDirtyCount >= kNumSmallDirtyThreshold) {
131         if (mLastSmallDirtyCount >= HISTORY_SIZE) {
132             isSmallDirty = true;
133         } else {
134             mLastSmallDirtyCount++;
135         }
136     } else {
137         mLastSmallDirtyCount = 0;
138     }
139 
140     if (isFrequent || isInfrequent) {
141         // If the layer was previously inconclusive, we clear
142         // the history as indeterminate layers changed to frequent,
143         // and we should not look at the stale data.
144         return {isFrequent, isFrequent && !mIsFrequencyConclusive, /* isConclusive */ true,
145                 isSmallDirty};
146     }
147 
148     // If we can't determine whether the layer is frequent or not, we return
149     // the last known classification and mark the layer frequency as inconclusive.
150     isFrequent = !mLastRefreshRate.infrequent;
151 
152     // If the layer was previously tagged as animating, we clear
153     // the history as it is likely the layer just changed its behavior,
154     // and we should not look at stale data.
155     return {isFrequent, isFrequent && mLastRefreshRate.animating, /* isConclusive */ false};
156 }
157 
getFps(nsecs_t now) const158 Fps LayerInfo::getFps(nsecs_t now) const {
159     // Find the first active frame
160     auto it = mFrameTimes.begin();
161     for (; it != mFrameTimes.end(); ++it) {
162         if (it->queueTime >= getActiveLayerThreshold(now)) {
163             break;
164         }
165     }
166 
167     const auto numFrames = std::distance(it, mFrameTimes.end());
168     if (numFrames < kFrequentLayerWindowSize) {
169         return Fps();
170     }
171 
172     // Layer is considered frequent if the average frame rate is higher than the threshold
173     const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
174     return Fps::fromPeriodNsecs(totalTime / (numFrames - 1));
175 }
176 
isAnimating(nsecs_t now) const177 bool LayerInfo::isAnimating(nsecs_t now) const {
178     return mLastAnimationTime >= getActiveLayerThreshold(now);
179 }
180 
hasEnoughDataForHeuristic() const181 bool LayerInfo::hasEnoughDataForHeuristic() const {
182     // The layer had to publish at least HISTORY_SIZE or HISTORY_DURATION of updates
183     if (mFrameTimes.size() < 2) {
184         ALOGV("%s fewer than 2 frames recorded: %zu", mName.c_str(), mFrameTimes.size());
185         return false;
186     }
187 
188     if (!isFrameTimeValid(mFrameTimes.front())) {
189         ALOGV("%s stale frames still captured", mName.c_str());
190         return false;
191     }
192 
193     const auto totalDuration = mFrameTimes.back().queueTime - mFrameTimes.front().queueTime;
194     if (mFrameTimes.size() < HISTORY_SIZE && totalDuration < HISTORY_DURATION.count()) {
195         ALOGV("%s not enough frames captured: %zu | %.2f seconds", mName.c_str(),
196               mFrameTimes.size(), totalDuration / 1e9f);
197         return false;
198     }
199 
200     return true;
201 }
202 
calculateAverageFrameTime() const203 std::optional<nsecs_t> LayerInfo::calculateAverageFrameTime() const {
204     // Ignore frames captured during a mode change
205     const bool isDuringModeChange =
206             std::any_of(mFrameTimes.begin(), mFrameTimes.end(),
207                         [](const auto& frame) { return frame.pendingModeChange; });
208     if (isDuringModeChange) {
209         return std::nullopt;
210     }
211 
212     const bool isMissingPresentTime =
213             std::any_of(mFrameTimes.begin(), mFrameTimes.end(),
214                         [](auto frame) { return frame.presentTime == 0; });
215     if (isMissingPresentTime && !mLastRefreshRate.reported.isValid()) {
216         // If there are no presentation timestamps and we haven't calculated
217         // one in the past then we can't calculate the refresh rate
218         return std::nullopt;
219     }
220 
221     // Calculate the average frame time based on presentation timestamps. If those
222     // doesn't exist, we look at the time the buffer was queued only. We can do that only if
223     // we calculated a refresh rate based on presentation timestamps in the past. The reason
224     // we look at the queue time is to handle cases where hwui attaches presentation timestamps
225     // when implementing render ahead for specific refresh rates. When hwui no longer provides
226     // presentation timestamps we look at the queue time to see if the current refresh rate still
227     // matches the content.
228 
229     auto getFrameTime = isMissingPresentTime ? [](FrameTimeData data) { return data.queueTime; }
230                                              : [](FrameTimeData data) { return data.presentTime; };
231 
232     nsecs_t totalDeltas = 0;
233     int numDeltas = 0;
234     int32_t smallDirtyCount = 0;
235     auto prevFrame = mFrameTimes.begin();
236     for (auto it = mFrameTimes.begin() + 1; it != mFrameTimes.end(); ++it) {
237         const auto currDelta = getFrameTime(*it) - getFrameTime(*prevFrame);
238         if (currDelta < kMinPeriodBetweenFrames) {
239             // Skip this frame, but count the delta into the next frame
240             continue;
241         }
242 
243         // If this is a small area update, we don't want to consider it for calculating the average
244         // frame time. Instead, we let the bigger frame updates to drive the calculation.
245         if (it->isSmallDirty && currDelta < kMinPeriodBetweenSmallDirtyFrames) {
246             smallDirtyCount++;
247             continue;
248         }
249 
250         prevFrame = it;
251 
252         if (currDelta > kMaxPeriodBetweenFrames) {
253             // Skip this frame and the current delta.
254             continue;
255         }
256 
257         totalDeltas += currDelta;
258         numDeltas++;
259     }
260 
261     if (smallDirtyCount > 0) {
262         ATRACE_FORMAT_INSTANT("small dirty = %" PRIu32, smallDirtyCount);
263     }
264 
265     if (numDeltas == 0) {
266         return std::nullopt;
267     }
268 
269     const auto averageFrameTime = static_cast<double>(totalDeltas) / static_cast<double>(numDeltas);
270     return static_cast<nsecs_t>(averageFrameTime);
271 }
272 
calculateRefreshRateIfPossible(const RefreshRateSelector & selector,nsecs_t now)273 std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(const RefreshRateSelector& selector,
274                                                              nsecs_t now) {
275     ATRACE_CALL();
276     static constexpr float MARGIN = 1.0f; // 1Hz
277     if (!hasEnoughDataForHeuristic()) {
278         ALOGV("Not enough data");
279         return std::nullopt;
280     }
281 
282     if (const auto averageFrameTime = calculateAverageFrameTime()) {
283         const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime);
284         const auto closestKnownRefreshRate = mRefreshRateHistory.add(refreshRate, now, selector);
285         if (closestKnownRefreshRate.isValid()) {
286             using fps_approx_ops::operator!=;
287 
288             // To avoid oscillation, use the last calculated refresh rate if it is close enough.
289             if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) >
290                         MARGIN &&
291                 mLastRefreshRate.reported != closestKnownRefreshRate) {
292                 mLastRefreshRate.calculated = refreshRate;
293                 mLastRefreshRate.reported = closestKnownRefreshRate;
294             }
295 
296             ALOGV("%s %s rounded to nearest known frame rate %s", mName.c_str(),
297                   to_string(refreshRate).c_str(), to_string(mLastRefreshRate.reported).c_str());
298         } else {
299             ALOGV("%s Not stable (%s) returning last known frame rate %s", mName.c_str(),
300                   to_string(refreshRate).c_str(), to_string(mLastRefreshRate.reported).c_str());
301         }
302     }
303 
304     return mLastRefreshRate.reported.isValid() ? std::make_optional(mLastRefreshRate.reported)
305                                                : std::nullopt;
306 }
307 
getRefreshRateVote(const RefreshRateSelector & selector,nsecs_t now)308 LayerInfo::RefreshRateVotes LayerInfo::getRefreshRateVote(const RefreshRateSelector& selector,
309                                                           nsecs_t now) {
310     ATRACE_CALL();
311     LayerInfo::RefreshRateVotes votes;
312 
313     if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
314         if (mLayerVote.category != FrameRateCategory::Default) {
315             const auto voteType = mLayerVote.type == LayerHistory::LayerVoteType::NoVote
316                     ? LayerHistory::LayerVoteType::NoVote
317                     : LayerHistory::LayerVoteType::ExplicitCategory;
318             ATRACE_FORMAT_INSTANT("Vote %s (category=%s)", ftl::enum_string(voteType).c_str(),
319                                   ftl::enum_string(mLayerVote.category).c_str());
320             ALOGV("%s voted %s with category: %s", mName.c_str(),
321                   ftl::enum_string(voteType).c_str(),
322                   ftl::enum_string(mLayerVote.category).c_str());
323             votes.push_back({voteType, Fps(), Seamlessness::Default, mLayerVote.category,
324                              mLayerVote.categorySmoothSwitchOnly});
325         }
326 
327         if (mLayerVote.fps.isValid() ||
328             mLayerVote.type != LayerHistory::LayerVoteType::ExplicitDefault) {
329             ATRACE_FORMAT_INSTANT("Vote %s", ftl::enum_string(mLayerVote.type).c_str());
330             ALOGV("%s voted %d", mName.c_str(), static_cast<int>(mLayerVote.type));
331             votes.push_back({mLayerVote.type, mLayerVote.fps, mLayerVote.seamlessness,
332                              FrameRateCategory::Default, mLayerVote.categorySmoothSwitchOnly});
333         }
334 
335         return votes;
336     }
337 
338     if (isAnimating(now)) {
339         ATRACE_FORMAT_INSTANT("animating");
340         ALOGV("%s is animating", mName.c_str());
341         mLastRefreshRate.animating = true;
342         votes.push_back({LayerHistory::LayerVoteType::Max, Fps()});
343         return votes;
344     }
345 
346     // Vote for max refresh rate whenever we're front-buffered.
347     if (FlagManager::getInstance().vrr_config() && isFrontBuffered()) {
348         ATRACE_FORMAT_INSTANT("front buffered");
349         ALOGV("%s is front-buffered", mName.c_str());
350         votes.push_back({LayerHistory::LayerVoteType::Max, Fps()});
351         return votes;
352     }
353 
354     const LayerInfo::Frequent frequent = isFrequent(now);
355     mIsFrequencyConclusive = frequent.isConclusive;
356     if (!frequent.isFrequent) {
357         ATRACE_FORMAT_INSTANT("infrequent");
358         ALOGV("%s is infrequent", mName.c_str());
359         mLastRefreshRate.infrequent = true;
360         mLastSmallDirtyCount = 0;
361         // Infrequent layers vote for minimal refresh rate for
362         // battery saving purposes and also to prevent b/135718869.
363         votes.push_back({LayerHistory::LayerVoteType::Min, Fps()});
364         return votes;
365     }
366 
367     if (frequent.clearHistory) {
368         ATRACE_FORMAT_INSTANT("frequent.clearHistory");
369         ALOGV("%s frequent.clearHistory", mName.c_str());
370         clearHistory(now);
371     }
372 
373     // Return no vote if the recent frames are small dirty.
374     if (frequent.isSmallDirty && !mLastRefreshRate.reported.isValid()) {
375         ATRACE_FORMAT_INSTANT("NoVote (small dirty)");
376         ALOGV("%s is small dirty", mName.c_str());
377         votes.push_back({LayerHistory::LayerVoteType::NoVote, Fps()});
378         return votes;
379     }
380 
381     auto refreshRate = calculateRefreshRateIfPossible(selector, now);
382     if (refreshRate.has_value()) {
383         ATRACE_FORMAT_INSTANT("calculated (%s)", to_string(*refreshRate).c_str());
384         ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str());
385         votes.push_back({LayerHistory::LayerVoteType::Heuristic, refreshRate.value()});
386         return votes;
387     }
388 
389     ATRACE_FORMAT_INSTANT("Max (can't resolve refresh rate)");
390     ALOGV("%s Max (can't resolve refresh rate)", mName.c_str());
391     votes.push_back({LayerHistory::LayerVoteType::Max, Fps()});
392     return votes;
393 }
394 
getTraceTag(LayerHistory::LayerVoteType type) const395 const char* LayerInfo::getTraceTag(LayerHistory::LayerVoteType type) const {
396     if (mTraceTags.count(type) == 0) {
397         auto tag = "LFPS " + mName + " " + ftl::enum_string(type);
398         mTraceTags.emplace(type, std::move(tag));
399     }
400 
401     return mTraceTags.at(type).c_str();
402 }
403 
getSetFrameRateVote() const404 LayerInfo::FrameRate LayerInfo::getSetFrameRateVote() const {
405     return mLayerProps->setFrameRateVote;
406 }
407 
isVisible() const408 bool LayerInfo::isVisible() const {
409     return mLayerProps->visible;
410 }
411 
getFrameRateSelectionPriority() const412 int32_t LayerInfo::getFrameRateSelectionPriority() const {
413     return mLayerProps->frameRateSelectionPriority;
414 }
415 
isFrontBuffered() const416 bool LayerInfo::isFrontBuffered() const {
417     return mLayerProps->isFrontBuffered;
418 }
419 
getBounds() const420 FloatRect LayerInfo::getBounds() const {
421     return mLayerProps->bounds;
422 }
423 
getTransform() const424 ui::Transform LayerInfo::getTransform() const {
425     return mLayerProps->transform;
426 }
427 
428 LayerInfo::RefreshRateHistory::HeuristicTraceTagData
makeHeuristicTraceTagData() const429 LayerInfo::RefreshRateHistory::makeHeuristicTraceTagData() const {
430     const std::string prefix = "LFPS ";
431     const std::string suffix = "Heuristic ";
432     return {.min = prefix + mName + suffix + "min",
433             .max = prefix + mName + suffix + "max",
434             .consistent = prefix + mName + suffix + "consistent",
435             .average = prefix + mName + suffix + "average"};
436 }
437 
clear()438 void LayerInfo::RefreshRateHistory::clear() {
439     mRefreshRates.clear();
440 }
441 
add(Fps refreshRate,nsecs_t now,const RefreshRateSelector & selector)442 Fps LayerInfo::RefreshRateHistory::add(Fps refreshRate, nsecs_t now,
443                                        const RefreshRateSelector& selector) {
444     mRefreshRates.push_back({refreshRate, now});
445     while (mRefreshRates.size() >= HISTORY_SIZE ||
446            now - mRefreshRates.front().timestamp > HISTORY_DURATION.count()) {
447         mRefreshRates.pop_front();
448     }
449 
450     if (CC_UNLIKELY(sTraceEnabled)) {
451         if (!mHeuristicTraceTagData.has_value()) {
452             mHeuristicTraceTagData = makeHeuristicTraceTagData();
453         }
454 
455         ATRACE_INT(mHeuristicTraceTagData->average.c_str(), refreshRate.getIntValue());
456     }
457 
458     return selectRefreshRate(selector);
459 }
460 
selectRefreshRate(const RefreshRateSelector & selector) const461 Fps LayerInfo::RefreshRateHistory::selectRefreshRate(const RefreshRateSelector& selector) const {
462     if (mRefreshRates.empty()) return Fps();
463 
464     const auto [min, max] =
465             std::minmax_element(mRefreshRates.begin(), mRefreshRates.end(),
466                                 [](const auto& lhs, const auto& rhs) {
467                                     return isStrictlyLess(lhs.refreshRate, rhs.refreshRate);
468                                 });
469 
470     const auto maxClosestRate = selector.findClosestKnownFrameRate(max->refreshRate);
471     const bool consistent = [&](Fps maxFps, Fps minFps) {
472         if (FlagManager::getInstance().use_known_refresh_rate_for_fps_consistency()) {
473             if (maxFps.getValue() - minFps.getValue() <
474                 MARGIN_CONSISTENT_FPS_FOR_CLOSEST_REFRESH_RATE) {
475                 const auto minClosestRate = selector.findClosestKnownFrameRate(minFps);
476                 using fps_approx_ops::operator==;
477                 return maxClosestRate == minClosestRate;
478             }
479             return false;
480         }
481         return maxFps.getValue() - minFps.getValue() < MARGIN_CONSISTENT_FPS;
482     }(max->refreshRate, min->refreshRate);
483 
484     if (CC_UNLIKELY(sTraceEnabled)) {
485         if (!mHeuristicTraceTagData.has_value()) {
486             mHeuristicTraceTagData = makeHeuristicTraceTagData();
487         }
488 
489         ATRACE_INT(mHeuristicTraceTagData->max.c_str(), max->refreshRate.getIntValue());
490         ATRACE_INT(mHeuristicTraceTagData->min.c_str(), min->refreshRate.getIntValue());
491         ATRACE_INT(mHeuristicTraceTagData->consistent.c_str(), consistent);
492     }
493 
494     return consistent ? maxClosestRate : Fps();
495 }
496 
convertCompatibility(int8_t compatibility)497 FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compatibility) {
498     switch (compatibility) {
499         case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT:
500             return FrameRateCompatibility::Default;
501         case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE:
502             return FrameRateCompatibility::ExactOrMultiple;
503         case ANATIVEWINDOW_FRAME_RATE_EXACT:
504             return FrameRateCompatibility::Exact;
505         case ANATIVEWINDOW_FRAME_RATE_MIN:
506             return FrameRateCompatibility::Min;
507         case ANATIVEWINDOW_FRAME_RATE_GTE:
508             return FrameRateCompatibility::Gte;
509         case ANATIVEWINDOW_FRAME_RATE_NO_VOTE:
510             return FrameRateCompatibility::NoVote;
511         default:
512             LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
513             return FrameRateCompatibility::Default;
514     }
515 }
516 
convertChangeFrameRateStrategy(int8_t strategy)517 Seamlessness LayerInfo::FrameRate::convertChangeFrameRateStrategy(int8_t strategy) {
518     switch (strategy) {
519         case ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS:
520             return Seamlessness::OnlySeamless;
521         case ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS:
522             return Seamlessness::SeamedAndSeamless;
523         default:
524             LOG_ALWAYS_FATAL("Invalid change frame sate strategy value %d", strategy);
525             return Seamlessness::Default;
526     }
527 }
528 
convertCategory(int8_t category)529 FrameRateCategory LayerInfo::FrameRate::convertCategory(int8_t category) {
530     switch (category) {
531         case ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT:
532             return FrameRateCategory::Default;
533         case ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE:
534             return FrameRateCategory::NoPreference;
535         case ANATIVEWINDOW_FRAME_RATE_CATEGORY_LOW:
536             return FrameRateCategory::Low;
537         case ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL:
538             return FrameRateCategory::Normal;
539         case ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH_HINT:
540             return FrameRateCategory::HighHint;
541         case ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH:
542             return FrameRateCategory::High;
543         default:
544             LOG_ALWAYS_FATAL("Invalid frame rate category value %d", category);
545             return FrameRateCategory::Default;
546     }
547 }
548 
convertFrameRateSelectionStrategy(int8_t strategy)549 LayerInfo::FrameRateSelectionStrategy LayerInfo::convertFrameRateSelectionStrategy(
550         int8_t strategy) {
551     switch (strategy) {
552         case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_PROPAGATE:
553             return FrameRateSelectionStrategy::Propagate;
554         case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN:
555             return FrameRateSelectionStrategy::OverrideChildren;
556         case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF:
557             return FrameRateSelectionStrategy::Self;
558         default:
559             LOG_ALWAYS_FATAL("Invalid frame rate selection strategy value %d", strategy);
560             return FrameRateSelectionStrategy::Self;
561     }
562 }
563 
isNoVote() const564 bool LayerInfo::FrameRate::isNoVote() const {
565     return vote.type == FrameRateCompatibility::NoVote;
566 }
567 
isValuelessType() const568 bool LayerInfo::FrameRate::isValuelessType() const {
569     // For a valueless frame rate compatibility (type), the frame rate should be unspecified (0 Hz).
570     if (!isApproxEqual(vote.rate, 0_Hz)) {
571         return false;
572     }
573     switch (vote.type) {
574         case FrameRateCompatibility::Min:
575         case FrameRateCompatibility::NoVote:
576             return true;
577         case FrameRateCompatibility::Default:
578         case FrameRateCompatibility::ExactOrMultiple:
579         case FrameRateCompatibility::Exact:
580         case FrameRateCompatibility::Gte:
581             return false;
582     }
583 }
584 
isValid() const585 bool LayerInfo::FrameRate::isValid() const {
586     return isValuelessType() || vote.rate.isValid() || category != FrameRateCategory::Default;
587 }
588 
isVoteValidForMrr(bool isVrrDevice) const589 bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const {
590     if (isVrrDevice || FlagManager::getInstance().frame_rate_category_mrr()) {
591         return true;
592     }
593 
594     if (category == FrameRateCategory::Default) {
595         return true;
596     }
597 
598     return false;
599 }
600 
operator <<(std::ostream & stream,const LayerInfo::FrameRate & rate)601 std::ostream& operator<<(std::ostream& stream, const LayerInfo::FrameRate& rate) {
602     return stream << "{rate=" << rate.vote.rate << " type=" << ftl::enum_string(rate.vote.type)
603                   << " seamlessness=" << ftl::enum_string(rate.vote.seamlessness) << '}';
604 }
605 
606 } // namespace android::scheduler
607 
608 // TODO(b/129481165): remove the #pragma below and fix conversion issues
609 #pragma clang diagnostic pop // ignored "-Wextra"
610