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 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
18
19 #include "PeriodRefreshRateCalculator.h"
20
21 #include "../Utils.h"
22
23 namespace android::hardware::graphics::composer {
24
PeriodRefreshRateCalculator(EventQueue * eventQueue,const PeriodRefreshRateCalculatorParameters & params)25 PeriodRefreshRateCalculator::PeriodRefreshRateCalculator(
26 EventQueue* eventQueue, const PeriodRefreshRateCalculatorParameters& params)
27 : mEventQueue(eventQueue), mParams(params) {
28 mName = "RefreshRateCalculator-Period";
29
30 mMeasureEvent.mEventType = VrrControllerEventType::kPeriodRefreshRateCalculatorUpdate;
31 mLastMeasureTimeNs = getSteadyClockTimeNs() + params.mMeasurePeriodNs;
32 mMeasureEvent.mWhenNs = mLastMeasureTimeNs;
33 mMeasureEvent.mFunctor = std::move(std::bind(&PeriodRefreshRateCalculator::onMeasure, this));
34
35 mConfidenceThresholdTimeNs = mParams.mMeasurePeriodNs * mParams.mConfidencePercentage / 100;
36 }
37
getRefreshRate() const38 int PeriodRefreshRateCalculator::getRefreshRate() const {
39 return mLastRefreshRate;
40 }
41
onPowerStateChange(int from,int to)42 void PeriodRefreshRateCalculator::onPowerStateChange(int from, int to) {
43 if (to != HWC_POWER_MODE_NORMAL) {
44 // We bypass inspection of the previous power state , as it is irrelevant to discard events
45 // when there is no event.
46 setEnabled(false);
47 } else {
48 if (from == HWC_POWER_MODE_NORMAL) {
49 ALOGE("Disregard power state change notification by staying current power state.");
50 return;
51 }
52 setEnabled(true);
53 }
54 }
55
onPresentInternal(int64_t presentTimeNs,int flag)56 void PeriodRefreshRateCalculator::onPresentInternal(int64_t presentTimeNs, int flag) {
57 if (hasPresentFrameFlag(flag, PresentFrameFlag::kPresentingWhenDoze)) {
58 return;
59 }
60 if (mLastPresentTimeNs >= 0) {
61 auto periodNs = presentTimeNs - mLastPresentTimeNs;
62 if (periodNs <= std::nano::den) {
63 int numVsync = std::max(mMinVsyncNum, durationToVsync(periodNs));
64 // current frame rate is |mVsyncRate/numVsync|
65 ++mStatistics[Fraction<int>(mVsyncRate, numVsync)];
66 }
67 }
68 mLastPresentTimeNs = presentTimeNs;
69 }
70
reset()71 void PeriodRefreshRateCalculator::reset() {
72 mStatistics.clear();
73 mLastRefreshRate = kDefaultInvalidRefreshRate;
74 mLastPresentTimeNs = kDefaultInvalidPresentTimeNs;
75 }
76
setEnabled(bool isEnabled)77 void PeriodRefreshRateCalculator::setEnabled(bool isEnabled) {
78 if (!isEnabled) {
79 mEventQueue->dropEvent(VrrControllerEventType::kPeriodRefreshRateCalculatorUpdate);
80 } else {
81 mLastMeasureTimeNs = getSteadyClockTimeNs() + mParams.mMeasurePeriodNs;
82 mMeasureEvent.mWhenNs = mLastMeasureTimeNs;
83 mMeasureEvent.mFunctor =
84 std::move(std::bind(&PeriodRefreshRateCalculator::onMeasure, this));
85 mEventQueue->mPriorityQueue.emplace(mMeasureEvent);
86 }
87 }
88
onMeasure()89 int PeriodRefreshRateCalculator::onMeasure() {
90 int currentRefreshRate = kDefaultInvalidRefreshRate;
91 int totalPresent = 0;
92 int64_t totalDurationNs = 0;
93 int maxOccurrence = 0;
94 Fraction<int> majorRefreshRate;
95
96 for (const auto& [rate, count] : mStatistics) {
97 totalPresent += count;
98 auto durationNs = freqToDurationNs(rate);
99 totalDurationNs += durationNs * count;
100 if (count > maxOccurrence) {
101 maxOccurrence = count;
102 majorRefreshRate = rate;
103 }
104 }
105 if (totalPresent > 0 && (totalDurationNs > mConfidenceThresholdTimeNs)) {
106 if (mParams.mType == PeriodRefreshRateCalculatorType::kAverage) {
107 if (mParams.mMeasurePeriodNs > totalDurationNs * 2) {
108 // avoid sudden high jumping when it's actually idle since last present for more
109 // than half of the measure period.
110 totalDurationNs = mParams.mMeasurePeriodNs;
111 totalPresent++;
112 }
113 auto avgDurationNs = roundDivide(totalDurationNs, static_cast<int64_t>(totalPresent));
114 currentRefreshRate = durationNsToFreq(avgDurationNs);
115 } else {
116 currentRefreshRate = majorRefreshRate.round();
117 }
118 }
119 mStatistics.clear();
120 currentRefreshRate = std::max(currentRefreshRate, 1);
121 currentRefreshRate = std::min(currentRefreshRate, mMaxFrameRate);
122 setNewRefreshRate(currentRefreshRate);
123
124 // Prepare next measurement event.
125 mLastMeasureTimeNs += mParams.mMeasurePeriodNs;
126 mMeasureEvent.mWhenNs = mLastMeasureTimeNs;
127 mEventQueue->mPriorityQueue.emplace(mMeasureEvent);
128 return NO_ERROR;
129 }
130
setNewRefreshRate(int newRefreshRate)131 void PeriodRefreshRateCalculator::setNewRefreshRate(int newRefreshRate) {
132 if ((newRefreshRate != mLastRefreshRate) || mParams.mAlwaysCallback) {
133 mLastRefreshRate = newRefreshRate;
134 ATRACE_INT(mName.c_str(), newRefreshRate);
135 if (mRefreshRateChangeCallback) {
136 mRefreshRateChangeCallback(mLastRefreshRate);
137 }
138 }
139 }
140
141 } // namespace android::hardware::graphics::composer
142