blob: 345b8f93fd1e422af545f84684b2a124d35c61ce [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
Ady Abrahama61edcb2020-01-30 18:32:03 -080057bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const {
58 return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>(
59 mFrameTimeValidSince.time_since_epoch())
60 .count();
61}
62
Ady Abraham8a82ba62020-01-17 12:43:17 -080063bool LayerInfoV2::isFrequent(nsecs_t now) const {
Ady Abrahama61edcb2020-01-30 18:32:03 -080064 // If we know nothing about this layer we consider it as frequent as it might be the start
65 // of an animation.
Ady Abraham8a82ba62020-01-17 12:43:17 -080066 if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
Ady Abrahama61edcb2020-01-30 18:32:03 -080067 return true;
Ady Abraham8a82ba62020-01-17 12:43:17 -080068 }
69
70 // Layer is frequent if the earliest value in the window of most recent present times is
71 // within threshold.
72 const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE;
Ady Abrahama61edcb2020-01-30 18:32:03 -080073 if (!isFrameTimeValid(*it)) {
74 return true;
75 }
76
Ady Abraham8a82ba62020-01-17 12:43:17 -080077 const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
78 return it->queueTime >= threshold;
79}
80
81bool LayerInfoV2::hasEnoughDataForHeuristic() const {
82 // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
Ady Abrahama61edcb2020-01-30 18:32:03 -080083 if (mFrameTimes.size() < 2) {
84 return false;
85 }
86
87 if (!isFrameTimeValid(mFrameTimes.front())) {
88 return false;
89 }
90
Ady Abraham8a82ba62020-01-17 12:43:17 -080091 if (mFrameTimes.size() < HISTORY_SIZE &&
92 mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
93 return false;
94 }
95
96 return true;
97}
98
99std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
100 static constexpr float MARGIN = 1.0f; // 1Hz
101
102 if (!hasEnoughDataForHeuristic()) {
103 ALOGV("Not enough data");
104 return std::nullopt;
105 }
106
107 // Calculate the refresh rate by finding the average delta between frames
108 nsecs_t totalPresentTimeDeltas = 0;
109 for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
110 // If there are no presentation timestamp provided we can't calculate the refresh rate
111 if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
112 return std::nullopt;
113 }
114
115 totalPresentTimeDeltas +=
116 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
117 }
118 const float averageFrameTime =
119 static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
120
121 // 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 -0800122 // are evenly distributed and we don't calculate the average across some burst of frames.
Ady Abraham8a82ba62020-01-17 12:43:17 -0800123 for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
124 const nsecs_t presentTimeDeltas =
125 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
126 if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
127 return std::nullopt;
128 }
129 }
130
131 const auto refreshRate = 1e9f / averageFrameTime;
132 if (std::abs(refreshRate - mLastReportedRefreshRate) > MARGIN) {
133 mLastReportedRefreshRate = refreshRate;
134 }
135
136 ALOGV("Refresh rate: %.2f", mLastReportedRefreshRate);
137 return mLastReportedRefreshRate;
138}
139
140std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
141 if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
142 return {mLayerVote.type, mLayerVote.fps};
143 }
144
145 if (!isFrequent(now)) {
146 return {LayerHistory::LayerVoteType::Min, 0};
147 }
148
149 auto refreshRate = calculateRefreshRateIfPossible();
150 if (refreshRate.has_value()) {
151 return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
152 }
153
154 return {LayerHistory::LayerVoteType::Max, 0};
155}
156
157} // namespace android::scheduler