• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
20 
21 #include "RefreshRateCalculator.h"
22 
23 #include "../Utils.h"
24 
25 namespace android::hardware::graphics::composer {
26 
27 class AODRefreshRateCalculator : public RefreshRateCalculator {
28 public:
AODRefreshRateCalculator(EventQueue * eventQueue)29     AODRefreshRateCalculator(EventQueue* eventQueue) : mEventQueue(eventQueue) {
30         mName = "RefreshRateCalculator-AOD";
31         mResetRefreshRateEvent.mEventType = VrrControllerEventType::kAodRefreshRateCalculatorUpdate;
32         mResetRefreshRateEvent.mFunctor = std::move(
33                 std::bind(&AODRefreshRateCalculator::changeRefreshRateDisplayState, this));
34     }
35 
getRefreshRate()36     int getRefreshRate() const override {
37         if (!mIsInDoze) {
38             return kDefaultInvalidRefreshRate;
39         }
40         return mLastRefreshRate;
41     }
42 
onPresentInternal(int64_t presentTimeNs,int flag)43     void onPresentInternal(int64_t presentTimeNs, int flag) override {
44         if (hasPresentFrameFlag(flag, PresentFrameFlag::kPresentingWhenDoze)) {
45             mIsInDoze = true;
46             if (mAodRefreshRateState != kAodActiveToIdleTransitionState) {
47                 setNewRefreshRate(kActiveRefreshRate);
48                 mEventQueue->dropEvent(VrrControllerEventType::kAodRefreshRateCalculatorUpdate);
49                 mResetRefreshRateEvent.mWhenNs =
50                         getSteadyClockTimeNs() + kActiveRefreshRateDurationNs;
51                 mEventQueue->mPriorityQueue.emplace(mResetRefreshRateEvent);
52                 if (mAodRefreshRateState == kAodIdleRefreshRateState) {
53                     changeRefreshRateDisplayState();
54                 }
55             }
56         } else {
57             if (mIsInDoze) {
58                 // We are transitioning from doze mode to normal mode.
59                 reset();
60                 mIsInDoze = false;
61             }
62         }
63     }
64 
reset()65     void reset() override {
66         setNewRefreshRate(kDefaultInvalidRefreshRate);
67         mEventQueue->dropEvent(VrrControllerEventType::kAodRefreshRateCalculatorUpdate);
68         mAodRefreshRateState = kAodIdleRefreshRateState;
69     }
70 
71 private:
72     static constexpr int kDDICFrameInsertionNum = 8;
73     static constexpr int kIdleRefreshRate = 1;
74     static constexpr int kActiveRefreshRate = 30;
75     static constexpr int kActiveFrameIntervalNs = (std::nano::den / 30);
76     static constexpr int64_t kActiveRefreshRateDurationNs =
77             kActiveFrameIntervalNs * kDDICFrameInsertionNum;
78     static constexpr int kNumOfSkipRefreshRateUpdateFrames = 3;
79     static constexpr int64_t kActiveToIdleTransitionDurationNs =
80             kActiveFrameIntervalNs * kNumOfSkipRefreshRateUpdateFrames; // 33.33ms * 3 ~= 100ms
81 
82     enum AodRefreshRateState {
83         kAodIdleRefreshRateState = 0,
84         kAodActiveRefreshRateState,
85         // State |kAodActiveToIdleTransitionState| is a special condition designed to prevent
86         // looping issues. In this state, the refresh rate is initially set to idle (1 Hz).
87         // Subsequently, during the subsequent |kActiveToIdleTransitionDurationNs| period, even if
88         // new frames arrive, the refresh rate will not be changed to active. Finally, when the
89         // timeout occurs, we return to the |kAodIdleRefreshRateState| state, ready to change the
90         // refresh rate back to active (30Hz) again when new frames arrive.
91         kAodActiveToIdleTransitionState,
92     };
93 
setNewRefreshRate(int newRefreshRate)94     void setNewRefreshRate(int newRefreshRate) {
95         if (newRefreshRate != mLastRefreshRate) {
96             mLastRefreshRate = newRefreshRate;
97             ATRACE_INT(mName.c_str(), newRefreshRate);
98             if (mRefreshRateChangeCallback) {
99                 mRefreshRateChangeCallback(mLastRefreshRate);
100             }
101         }
102     }
103 
changeRefreshRateDisplayState()104     int changeRefreshRateDisplayState() {
105         if (mAodRefreshRateState == kAodIdleRefreshRateState) {
106             mAodRefreshRateState = kAodActiveRefreshRateState;
107         } else if (mAodRefreshRateState == kAodActiveRefreshRateState) {
108             setNewRefreshRate(kIdleRefreshRate);
109             mAodRefreshRateState = kAodActiveToIdleTransitionState;
110             mResetRefreshRateEvent.mWhenNs =
111                     getSteadyClockTimeNs() + kActiveToIdleTransitionDurationNs;
112             mEventQueue->mPriorityQueue.emplace(mResetRefreshRateEvent);
113         } else {
114             mAodRefreshRateState = kAodIdleRefreshRateState;
115         }
116         return NO_ERROR;
117     }
118 
119     EventQueue* mEventQueue;
120     VrrControllerEvent mResetRefreshRateEvent;
121 
122     AodRefreshRateState mAodRefreshRateState = kAodIdleRefreshRateState;
123 
124     int mLastRefreshRate = kIdleRefreshRate;
125 
126     bool mIsInDoze = false;
127 };
128 
129 } // namespace android::hardware::graphics::composer
130