|  | /* | 
|  | * Copyright 2019 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <cinttypes> | 
|  | #include <cstdint> | 
|  | #include <deque> | 
|  | #include <mutex> | 
|  | #include <numeric> | 
|  | #include <string> | 
|  |  | 
|  | #include <log/log.h> | 
|  |  | 
|  | #include <utils/Mutex.h> | 
|  | #include <utils/Timers.h> | 
|  |  | 
|  | #include "SchedulerUtils.h" | 
|  |  | 
|  | namespace android { | 
|  | namespace scheduler { | 
|  |  | 
|  | /* | 
|  | * This class represents information about individial layers. | 
|  | */ | 
|  | class LayerInfo { | 
|  | /** | 
|  | * Struct that keeps the information about the refresh rate for last | 
|  | * HISTORY_SIZE frames. This is used to better determine the refresh rate | 
|  | * for individual layers. | 
|  | */ | 
|  | class RefreshRateHistory { | 
|  | public: | 
|  | explicit RefreshRateHistory(nsecs_t minRefreshDuration) | 
|  | : mMinRefreshDuration(minRefreshDuration) {} | 
|  | void insertRefreshRate(int refreshRate) { | 
|  | mElements.push_back(refreshRate); | 
|  | if (mElements.size() > HISTORY_SIZE) { | 
|  | mElements.pop_front(); | 
|  | } | 
|  | } | 
|  |  | 
|  | float getRefreshRateAvg() const { | 
|  | if (mElements.empty()) { | 
|  | return 1e9f / mMinRefreshDuration; | 
|  | } | 
|  |  | 
|  | return scheduler::calculate_mean(mElements); | 
|  | } | 
|  |  | 
|  | void clearHistory() { mElements.clear(); } | 
|  |  | 
|  | private: | 
|  | std::deque<nsecs_t> mElements; | 
|  | static constexpr size_t HISTORY_SIZE = 30; | 
|  | const nsecs_t mMinRefreshDuration; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Struct that keeps the information about the present time for last | 
|  | * HISTORY_SIZE frames. This is used to better determine whether the given layer | 
|  | * is still relevant and it's refresh rate should be considered. | 
|  | */ | 
|  | class PresentTimeHistory { | 
|  | public: | 
|  | void insertPresentTime(nsecs_t presentTime) { | 
|  | mElements.push_back(presentTime); | 
|  | if (mElements.size() > HISTORY_SIZE) { | 
|  | mElements.pop_front(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Checks whether the present time that was inserted HISTORY_SIZE ago is within a | 
|  | // certain threshold: TIME_EPSILON_NS. | 
|  | bool isRelevant() const { | 
|  | if (mElements.size() < 2) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates | 
|  | if (mElements.size() != HISTORY_SIZE && | 
|  | mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds. | 
|  | const int64_t obsoleteEpsilon = | 
|  | systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count(); | 
|  | if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool isLowActivityLayer() const { | 
|  | // We want to make sure that we received more than two frames from the layer | 
|  | // in order to check low activity. | 
|  | if (mElements.size() < 2) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const int64_t obsoleteEpsilon = | 
|  | systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count(); | 
|  | // Check the frame before last to determine whether there is low activity. | 
|  | // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending | 
|  | // infrequent updates. | 
|  | if (mElements.at(mElements.size() - 2) < obsoleteEpsilon) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void clearHistory() { mElements.clear(); } | 
|  |  | 
|  | private: | 
|  | std::deque<nsecs_t> mElements; | 
|  | static constexpr size_t HISTORY_SIZE = 90; | 
|  | static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; | 
|  | }; | 
|  |  | 
|  | public: | 
|  | LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate); | 
|  | ~LayerInfo(); | 
|  |  | 
|  | LayerInfo(const LayerInfo&) = delete; | 
|  | LayerInfo& operator=(const LayerInfo&) = delete; | 
|  |  | 
|  | // Records the last requested oresent time. It also stores information about when | 
|  | // the layer was last updated. If the present time is farther in the future than the | 
|  | // updated time, the updated time is the present time. | 
|  | void setLastPresentTime(nsecs_t lastPresentTime); | 
|  |  | 
|  | void setHDRContent(bool isHdr) { | 
|  | std::lock_guard lock(mLock); | 
|  | mIsHDR = isHdr; | 
|  | } | 
|  |  | 
|  | void setVisibility(bool visible) { | 
|  | std::lock_guard lock(mLock); | 
|  | mIsVisible = visible; | 
|  | } | 
|  |  | 
|  | // Checks the present time history to see whether the layer is relevant. | 
|  | bool isRecentlyActive() const { | 
|  | std::lock_guard lock(mLock); | 
|  | return mPresentTimeHistory.isRelevant(); | 
|  | } | 
|  |  | 
|  | // Calculate the average refresh rate. | 
|  | float getDesiredRefreshRate() const { | 
|  | std::lock_guard lock(mLock); | 
|  |  | 
|  | if (mPresentTimeHistory.isLowActivityLayer()) { | 
|  | return 1e9f / mLowActivityRefreshDuration; | 
|  | } | 
|  | return mRefreshRateHistory.getRefreshRateAvg(); | 
|  | } | 
|  |  | 
|  | bool getHDRContent() { | 
|  | std::lock_guard lock(mLock); | 
|  | return mIsHDR; | 
|  | } | 
|  |  | 
|  | bool isVisible() { | 
|  | std::lock_guard lock(mLock); | 
|  | return mIsVisible; | 
|  | } | 
|  |  | 
|  | // Return the last updated time. If the present time is farther in the future than the | 
|  | // updated time, the updated time is the present time. | 
|  | nsecs_t getLastUpdatedTime() { | 
|  | std::lock_guard lock(mLock); | 
|  | return mLastUpdatedTime; | 
|  | } | 
|  |  | 
|  | std::string getName() const { return mName; } | 
|  |  | 
|  | void clearHistory() { | 
|  | std::lock_guard lock(mLock); | 
|  | mRefreshRateHistory.clearHistory(); | 
|  | mPresentTimeHistory.clearHistory(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | const std::string mName; | 
|  | const nsecs_t mMinRefreshDuration; | 
|  | const nsecs_t mLowActivityRefreshDuration; | 
|  | mutable std::mutex mLock; | 
|  | nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0; | 
|  | nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0; | 
|  | RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock); | 
|  | PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock); | 
|  | bool mIsHDR GUARDED_BY(mLock) = false; | 
|  | bool mIsVisible GUARDED_BY(mLock) = false; | 
|  | }; | 
|  |  | 
|  | } // namespace scheduler | 
|  | } // namespace android |