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