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