1 /* 2 * Copyright (C) 2024 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 <hardware/hwcomposer2.h> 20 #include <map> 21 #include <sstream> 22 #include <string> 23 #include <utility> 24 25 #include "../Power/PowerStatsProfile.h" 26 #include "../Power/PowerStatsProfileTokenGenerator.h" 27 #include "EventQueue.h" 28 #include "Utils.h" 29 #include "display/common/CommonDisplayContextProvider.h" 30 #include "display/common/Constants.h" 31 #include "interface/DisplayContextProvider.h" 32 #include "interface/VariableRefreshRateInterface.h" 33 34 // #define DEBUG_VRR_STATISTICS 1 35 36 namespace android::hardware::graphics::composer { 37 38 // |DisplayStatus| is the intrinsic property of the key for statistics, representing the display 39 // configuration. 40 typedef struct DisplayStatus { isOffDisplayStatus41 inline bool isOff() const { 42 if ((mPowerMode == HWC_POWER_MODE_OFF) || (mPowerMode == HWC_POWER_MODE_DOZE_SUSPEND)) { 43 return true; 44 } else { 45 return false; 46 } 47 } 48 49 bool operator==(const DisplayStatus& rhs) const { 50 if (isOff() || rhs.isOff()) { 51 return isOff() == rhs.isOff(); 52 } 53 return (mActiveConfigId == rhs.mActiveConfigId) && (mPowerMode == rhs.mPowerMode) && 54 (mBrightnessMode == rhs.mBrightnessMode); 55 } 56 57 bool operator<(const DisplayStatus& rhs) const { 58 if (isOff() && rhs.isOff()) { 59 return false; 60 } 61 62 if (mPowerMode != rhs.mPowerMode) { 63 return (isOff() || (mPowerMode < rhs.mPowerMode)); 64 } else if (mActiveConfigId != rhs.mActiveConfigId) { 65 return mActiveConfigId < rhs.mActiveConfigId; 66 } else { 67 return mBrightnessMode < rhs.mBrightnessMode; 68 } 69 } 70 toStringDisplayStatus71 std::string toString() const { 72 std::ostringstream os; 73 os << "id = " << mActiveConfigId; 74 os << ", power mode = " << mPowerMode; 75 os << ", brightness = " << static_cast<int>(mBrightnessMode); 76 return os.str(); 77 } 78 79 hwc2_config_t mActiveConfigId = -1; 80 int mPowerMode = HWC_POWER_MODE_OFF; 81 BrightnessMode mBrightnessMode = BrightnessMode::kInvalidBrightnessMode; 82 } DisplayStatus; 83 84 // |DisplayRefreshProfile| is the key to the statistics. 85 typedef struct DisplayRefreshProfile { 86 PowerStatsProfile toPowerStatsProfile(bool enableMapping = true) const { 87 PowerStatsProfile powerStatsProfile; 88 if (mNumVsync < 0) { // To address the specific scenario of powering off 89 powerStatsProfile.mFps = -1; 90 return powerStatsProfile; 91 } 92 powerStatsProfile.mWidth = mWidth; 93 powerStatsProfile.mHeight = mHeight; 94 powerStatsProfile.mPowerMode = mCurrentDisplayConfig.mPowerMode; 95 powerStatsProfile.mBrightnessMode = mCurrentDisplayConfig.mBrightnessMode; 96 powerStatsProfile.mRefreshSource = mRefreshSource; 97 Fraction fps(mTeFrequency, mNumVsync); 98 if (enableMapping) { 99 if ((android::hardware::graphics::composer::kFpsMappingTable.count(fps) > 0)) { 100 powerStatsProfile.mFps = fps.round(); 101 } else { 102 powerStatsProfile.mFps = 0; 103 } 104 } else { 105 powerStatsProfile.mFps = fps.round(); 106 } 107 108 return powerStatsProfile; 109 } 110 isOffDisplayRefreshProfile111 inline bool isOff() const { return mCurrentDisplayConfig.isOff(); } 112 113 bool operator<(const DisplayRefreshProfile& rhs) const { 114 if (isOff() || rhs.isOff()) { 115 if (isOff() == rhs.isOff()) { 116 return false; 117 } 118 } 119 120 if (mCurrentDisplayConfig != rhs.mCurrentDisplayConfig) { 121 return (mCurrentDisplayConfig < rhs.mCurrentDisplayConfig); 122 } else if (mNumVsync != rhs.mNumVsync) { 123 return (mNumVsync < rhs.mNumVsync); 124 } else { 125 return (mRefreshSource < rhs.mRefreshSource); 126 } 127 } 128 toStringDisplayRefreshProfile129 std::string toString() const { 130 std::string res = mCurrentDisplayConfig.toString(); 131 res += ", mNumVsync = " + std::to_string(mNumVsync) + ", refresh source = " + 132 (isPresentRefresh(mRefreshSource) ? "present" : "nonpresent"); 133 return res; 134 } 135 136 DisplayStatus mCurrentDisplayConfig; 137 int mTeFrequency; 138 int mWidth = 0; 139 int mHeight = 0; 140 // |mNumVsync| is the timing property of the key for statistics, representing the distribution 141 // of refreshs. It represents the interval between a refresh and the previous refresh in 142 // terms of the number of vsyncs. 143 int mNumVsync = -1; 144 RefreshSource mRefreshSource = kRefreshSourceActivePresent; 145 } DisplayRefreshProfile; 146 147 // |DisplayRefreshRecord| is the value to the statistics. 148 typedef struct DisplayRefreshRecord { 149 DisplayRefreshRecord() = default; 150 DisplayRefreshRecord& operator+=(const DisplayRefreshRecord& other) { 151 this->mCount += other.mCount; 152 this->mAccumulatedTimeNs += other.mAccumulatedTimeNs; 153 this->mLastTimeStampInBootClockNs = 154 std::max(mLastTimeStampInBootClockNs, other.mLastTimeStampInBootClockNs); 155 mUpdated = true; 156 return *this; 157 } toStringDisplayRefreshRecord158 std::string toString() const { 159 std::ostringstream os; 160 os << "Count = " << mCount; 161 os << ", AccumulatedTime Ms = " << mAccumulatedTimeNs / 1000000; 162 os << ", LastTimeStampInBootClockNs = " << mLastTimeStampInBootClockNs; 163 return os.str(); 164 } 165 uint64_t mCount = 0; 166 uint64_t mAccumulatedTimeNs = 0; 167 uint64_t mLastTimeStampInBootClockNs = 0; 168 bool mUpdated = false; 169 } DisplayRefreshRecord; 170 171 // |DisplayRefreshStatistics| is a map consisting of key-value pairs for statistics. 172 // The key consists of two parts: display configuration and refresh frequency (in terms of vsync). 173 typedef std::map<DisplayRefreshProfile, DisplayRefreshRecord> DisplayRefreshStatistics; 174 175 class StatisticsProvider { 176 public: 177 virtual ~StatisticsProvider() = default; 178 179 virtual uint64_t getStartStatisticTimeNs() const = 0; 180 181 virtual DisplayRefreshStatistics getStatistics() = 0; 182 183 virtual DisplayRefreshStatistics getUpdatedStatistics() = 0; 184 }; 185 186 class VariableRefreshRateStatistic : public PowerModeListener, 187 public RefreshListener, 188 public StatisticsProvider { 189 public: 190 VariableRefreshRateStatistic(CommonDisplayContextProvider* displayContextProvider, 191 EventQueue* eventQueue, int maxFrameRate, int maxTeFrequency, 192 int64_t updatePeriodNs); 193 194 uint64_t getPowerOffDurationNs() const; 195 196 uint64_t getStartStatisticTimeNs() const override; 197 198 DisplayRefreshStatistics getStatistics() override; 199 200 DisplayRefreshStatistics getUpdatedStatistics() override; 201 202 void onPowerStateChange(int from, int to) final; 203 204 void onPresent(int64_t presentTimeNs, int flag) override; 205 206 void onNonPresentRefresh(int64_t refreshTimeNs, RefreshSource refreshSource) override; 207 208 void setActiveVrrConfiguration(int activeConfigId, int teFrequency); 209 210 // If |minimumRefreshRate| is not equal to zero, enforce the minimum (fixed) refresh rate; 211 // otherwise, revert to a variable refresh rate. 212 void setFixedRefreshRate(uint32_t minimumRefreshRate); 213 214 VariableRefreshRateStatistic(const VariableRefreshRateStatistic& other) = delete; 215 VariableRefreshRateStatistic& operator=(const VariableRefreshRateStatistic& other) = delete; 216 217 std::string dumpStatistics(bool getUpdatedOnly, RefreshSource refreshSource, 218 const std::string& delimiter = ";"); 219 void dump(String8& result, const std::vector<std::string>& args = {}); 220 221 private: 222 static constexpr int64_t kMaxRefreshIntervalNs = std::nano::den; 223 static constexpr uint32_t kFrameRateWhenPresentAtLpMode = 30; 224 225 bool isPowerModeOffNowLocked() const; 226 227 std::string normalizeString(const std::string& input); 228 229 void onRefreshInternal(int64_t refreshTimeNs, int flag, RefreshSource refreshSource); 230 231 void updateCurrentDisplayStatus(); 232 233 void updateIdleStats(int64_t endTimeStampInBootClockNs = -1); 234 235 #ifdef DEBUG_VRR_STATISTICS 236 int updateStatistic(); 237 #endif 238 239 PowerStatsProfileTokenGenerator mPowerStatsProfileTokenGenerator; 240 241 CommonDisplayContextProvider* mDisplayContextProvider; 242 EventQueue* mEventQueue; 243 244 const int mMaxFrameRate; 245 const int mMaxTeFrequency; 246 const int64_t mMinFrameIntervalNs; 247 248 int mTeFrequency; 249 int64_t mTeIntervalNs; 250 251 const int64_t mUpdatePeriodNs; 252 253 int64_t mLastDumpsysTime = 0; 254 int64_t mLastRefreshTimeInBootClockNs = kDefaultInvalidPresentTimeNs; 255 256 DisplayRefreshStatistics mStatistics; 257 DisplayRefreshStatistics mStatisticsSnapshot; 258 DisplayRefreshProfile mDisplayRefreshProfile; 259 260 uint64_t mPowerOffDurationNs = 0; 261 262 uint32_t mMinimumRefreshRate = 1; 263 uint64_t mMaximumFrameIntervalNs = kMaxRefreshIntervalNs; // 1 second. 264 265 uint64_t mStartStatisticTimeNs; 266 267 #ifdef DEBUG_VRR_STATISTICS 268 VrrControllerEvent mUpdateEvent; 269 #endif 270 271 mutable std::mutex mMutex; 272 }; 273 274 } // namespace android::hardware::graphics::composer 275