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