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