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 #pragma once
18 
19 #include <cinttypes>
20 #include <cstdint>
21 #include <deque>
22 #include <mutex>
23 #include <numeric>
24 #include <string>
25 
26 #include <log/log.h>
27 
28 #include <utils/Mutex.h>
29 #include <utils/Timers.h>
30 
31 #include "SchedulerUtils.h"
32 
33 namespace android {
34 namespace scheduler {
35 
36 /*
37  * This class represents information about individial layers.
38  */
39 class LayerInfo {
40     /**
41      * Struct that keeps the information about the refresh rate for last
42      * HISTORY_SIZE frames. This is used to better determine the refresh rate
43      * for individual layers.
44      */
45     class RefreshRateHistory {
46     public:
RefreshRateHistory(nsecs_t minRefreshDuration)47         explicit RefreshRateHistory(nsecs_t minRefreshDuration)
48               : mMinRefreshDuration(minRefreshDuration) {}
insertRefreshRate(int refreshRate)49         void insertRefreshRate(int refreshRate) {
50             mElements.push_back(refreshRate);
51             if (mElements.size() > HISTORY_SIZE) {
52                 mElements.pop_front();
53             }
54         }
55 
getRefreshRateAvg()56         float getRefreshRateAvg() const {
57             if (mElements.empty()) {
58                 return 1e9f / mMinRefreshDuration;
59             }
60 
61             return scheduler::calculate_mean(mElements);
62         }
63 
clearHistory()64         void clearHistory() { mElements.clear(); }
65 
66     private:
67         std::deque<nsecs_t> mElements;
68         static constexpr size_t HISTORY_SIZE = 30;
69         const nsecs_t mMinRefreshDuration;
70     };
71 
72     /**
73      * Struct that keeps the information about the present time for last
74      * HISTORY_SIZE frames. This is used to better determine whether the given layer
75      * is still relevant and it's refresh rate should be considered.
76      */
77     class PresentTimeHistory {
78     public:
insertPresentTime(nsecs_t presentTime)79         void insertPresentTime(nsecs_t presentTime) {
80             mElements.push_back(presentTime);
81             if (mElements.size() > HISTORY_SIZE) {
82                 mElements.pop_front();
83             }
84         }
85 
86         // Checks whether the present time that was inserted HISTORY_SIZE ago is within a
87         // certain threshold: TIME_EPSILON_NS.
isRelevant()88         bool isRelevant() const {
89             if (mElements.size() < 2) {
90                 return false;
91             }
92 
93             // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
94             if (mElements.size() != HISTORY_SIZE &&
95                 mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) {
96                 return false;
97             }
98 
99             // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds.
100             const int64_t obsoleteEpsilon =
101                     systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
102             if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) {
103                 return false;
104             }
105 
106             return true;
107         }
108 
isLowActivityLayer()109         bool isLowActivityLayer() const {
110             // We want to make sure that we received more than two frames from the layer
111             // in order to check low activity.
112             if (mElements.size() < scheduler::LOW_ACTIVITY_BUFFERS + 1) {
113                 return false;
114             }
115 
116             const int64_t obsoleteEpsilon =
117                     systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count();
118             // Check the frame before last to determine whether there is low activity.
119             // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending
120             // infrequent updates.
121             if (mElements.at(mElements.size() - (scheduler::LOW_ACTIVITY_BUFFERS + 1)) <
122                 obsoleteEpsilon) {
123                 return true;
124             }
125 
126             return false;
127         }
128 
clearHistory()129         void clearHistory() { mElements.clear(); }
130 
131     private:
132         std::deque<nsecs_t> mElements;
133         static constexpr size_t HISTORY_SIZE = 90;
134         static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
135     };
136 
137 public:
138     LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate);
139     ~LayerInfo();
140 
141     LayerInfo(const LayerInfo&) = delete;
142     LayerInfo& operator=(const LayerInfo&) = delete;
143 
144     // Records the last requested oresent time. It also stores information about when
145     // the layer was last updated. If the present time is farther in the future than the
146     // updated time, the updated time is the present time.
147     void setLastPresentTime(nsecs_t lastPresentTime);
148 
setHDRContent(bool isHdr)149     void setHDRContent(bool isHdr) {
150         std::lock_guard lock(mLock);
151         mIsHDR = isHdr;
152     }
153 
setVisibility(bool visible)154     void setVisibility(bool visible) {
155         std::lock_guard lock(mLock);
156         mIsVisible = visible;
157     }
158 
159     // Checks the present time history to see whether the layer is relevant.
isRecentlyActive()160     bool isRecentlyActive() const {
161         std::lock_guard lock(mLock);
162         return mPresentTimeHistory.isRelevant();
163     }
164 
165     // Calculate the average refresh rate.
getDesiredRefreshRate()166     float getDesiredRefreshRate() const {
167         std::lock_guard lock(mLock);
168 
169         if (mPresentTimeHistory.isLowActivityLayer()) {
170             return 1e9f / mLowActivityRefreshDuration;
171         }
172         return mRefreshRateHistory.getRefreshRateAvg();
173     }
174 
getHDRContent()175     bool getHDRContent() {
176         std::lock_guard lock(mLock);
177         return mIsHDR;
178     }
179 
isVisible()180     bool isVisible() {
181         std::lock_guard lock(mLock);
182         return mIsVisible;
183     }
184 
185     // Return the last updated time. If the present time is farther in the future than the
186     // updated time, the updated time is the present time.
getLastUpdatedTime()187     nsecs_t getLastUpdatedTime() {
188         std::lock_guard lock(mLock);
189         return mLastUpdatedTime;
190     }
191 
getName()192     std::string getName() const { return mName; }
193 
clearHistory()194     void clearHistory() {
195         std::lock_guard lock(mLock);
196         mRefreshRateHistory.clearHistory();
197         mPresentTimeHistory.clearHistory();
198     }
199 
200 private:
201     const std::string mName;
202     const nsecs_t mMinRefreshDuration;
203     const nsecs_t mLowActivityRefreshDuration;
204     mutable std::mutex mLock;
205     nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
206     nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
207     RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock);
208     PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock);
209     bool mIsHDR GUARDED_BY(mLock) = false;
210     bool mIsVisible GUARDED_BY(mLock) = false;
211 };
212 
213 } // namespace scheduler
214 } // namespace android