blob: f309d4d889c43a31012361818120cdac5945dc16 [file] [log] [blame]
Ady Abraham8a82ba62020-01-17 12:43:17 -08001/*
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// #define LOG_NDEBUG 0
18
19#include "LayerInfoV2.h"
20
21#include <algorithm>
22#include <utility>
23
24#undef LOG_TAG
25#define LOG_TAG "LayerInfoV2"
26#define ATRACE_TAG ATRACE_TAG_GRAPHICS
27
28namespace android::scheduler {
29
30LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote)
31 : mHighRefreshRatePeriod(highRefreshRatePeriod),
32 mDefaultVote(defaultVote),
33 mLayerVote({defaultVote, 0.0f}) {}
34
35void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
36 lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
37
38 mLastUpdatedTime = std::max(lastPresentTime, now);
39
40 FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime};
41
42 mFrameTimes.push_back(frameTime);
43 if (mFrameTimes.size() > HISTORY_SIZE) {
44 mFrameTimes.pop_front();
45 }
46}
47
48// Returns whether the earliest present time is within the active threshold.
49bool LayerInfoV2::isRecentlyActive(nsecs_t now) const {
50 if (mFrameTimes.empty()) {
51 return false;
52 }
53
54 return mFrameTimes.back().queueTime >= getActiveLayerThreshold(now);
55}
56
57bool LayerInfoV2::isFrequent(nsecs_t now) const {
58 // Assume layer is infrequent if too few present times have been recorded.
59 if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
Ady Abrahamf6b77072020-01-30 14:22:54 -080060 return false;
Ady Abraham8a82ba62020-01-17 12:43:17 -080061 }
62
63 // Layer is frequent if the earliest value in the window of most recent present times is
64 // within threshold.
65 const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE;
66 const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
67 return it->queueTime >= threshold;
68}
69
70bool LayerInfoV2::hasEnoughDataForHeuristic() const {
71 // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
72 if (mFrameTimes.size() < HISTORY_SIZE &&
73 mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
74 return false;
75 }
76
77 return true;
78}
79
80std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
81 static constexpr float MARGIN = 1.0f; // 1Hz
82
83 if (!hasEnoughDataForHeuristic()) {
84 ALOGV("Not enough data");
85 return std::nullopt;
86 }
87
88 // Calculate the refresh rate by finding the average delta between frames
89 nsecs_t totalPresentTimeDeltas = 0;
90 for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
91 // If there are no presentation timestamp provided we can't calculate the refresh rate
92 if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
93 return std::nullopt;
94 }
95
96 totalPresentTimeDeltas +=
97 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
98 }
99 const float averageFrameTime =
100 static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
101
102 // Now once we calculated the refresh rate we need to make sure that all the frames we captured
Ady Abrahamf6b77072020-01-30 14:22:54 -0800103 // are evenly distributed and we don't calculate the average across some burst of frames.
Ady Abraham8a82ba62020-01-17 12:43:17 -0800104 for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
105 const nsecs_t presentTimeDeltas =
106 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
107 if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
108 return std::nullopt;
109 }
110 }
111
112 const auto refreshRate = 1e9f / averageFrameTime;
113 if (std::abs(refreshRate - mLastReportedRefreshRate) > MARGIN) {
114 mLastReportedRefreshRate = refreshRate;
115 }
116
117 ALOGV("Refresh rate: %.2f", mLastReportedRefreshRate);
118 return mLastReportedRefreshRate;
119}
120
121std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
122 if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
123 return {mLayerVote.type, mLayerVote.fps};
124 }
125
126 if (!isFrequent(now)) {
127 return {LayerHistory::LayerVoteType::Min, 0};
128 }
129
130 auto refreshRate = calculateRefreshRateIfPossible();
131 if (refreshRate.has_value()) {
132 return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
133 }
134
135 return {LayerHistory::LayerVoteType::Max, 0};
136}
137
138} // namespace android::scheduler