blob: d94d758ec550f742106ee570fc34536855b7f0e4 [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) {
60 return true;
61 }
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
103 // are evenly distrubuted and we don't calculate the average across some burst of frames.
104
105 for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
106 const nsecs_t presentTimeDeltas =
107 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
108 if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
109 return std::nullopt;
110 }
111 }
112
113 const auto refreshRate = 1e9f / averageFrameTime;
114 if (std::abs(refreshRate - mLastReportedRefreshRate) > MARGIN) {
115 mLastReportedRefreshRate = refreshRate;
116 }
117
118 ALOGV("Refresh rate: %.2f", mLastReportedRefreshRate);
119 return mLastReportedRefreshRate;
120}
121
122std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
123 if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
124 return {mLayerVote.type, mLayerVote.fps};
125 }
126
127 if (!isFrequent(now)) {
128 return {LayerHistory::LayerVoteType::Min, 0};
129 }
130
131 auto refreshRate = calculateRefreshRateIfPossible();
132 if (refreshRate.has_value()) {
133 return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
134 }
135
136 return {LayerHistory::LayerVoteType::Max, 0};
137}
138
139} // namespace android::scheduler