| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright 2018 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 <utils/Errors.h> | 
 | 20 |  | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 21 | #include <cinttypes> | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 22 | #include <mutex> | 
 | 23 |  | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 24 | #include "Scheduler.h" | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 25 |  | 
 | 26 | namespace android { | 
 | 27 |  | 
 | 28 | /* | 
 | 29 |  * Modulates the vsync-offsets depending on current SurfaceFlinger state. | 
 | 30 |  */ | 
 | 31 | class VSyncModulator { | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 32 | private: | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 33 |     // Number of frames we'll keep the early phase offsets once they are activated for a | 
 | 34 |     // transaction. This acts as a low-pass filter in case the client isn't quick enough in | 
 | 35 |     // sending new transactions. | 
 | 36 |     const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 37 |  | 
| Alec Mouri | 98fca26 | 2019-05-23 07:14:20 -0700 | [diff] [blame] | 38 |     // Number of frames we'll keep the early gl phase offsets once they are activated. | 
 | 39 |     // This acts as a low-pass filter to avoid scenarios where we rapidly | 
 | 40 |     // switch in and out of gl composition. | 
 | 41 |     const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; | 
 | 42 |  | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 43 | public: | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 44 |     struct Offsets { | 
 | 45 |         nsecs_t sf; | 
 | 46 |         nsecs_t app; | 
 | 47 |     }; | 
 | 48 |  | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 49 |     // Sets the phase offsets | 
 | 50 |     // | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 51 |     // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction | 
 | 52 |     //          as early. May be the same as late, in which case we don't shift offsets. | 
 | 53 |     // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition | 
 | 54 |     //            and the transaction was marked as early, we'll use sfEarly. | 
 | 55 |     // sfLate: The regular SF vsync phase offset. | 
 | 56 |     // appEarly: Like sfEarly, but for the app-vsync | 
 | 57 |     // appEarlyGl: Like sfEarlyGl, but for the app-vsync. | 
 | 58 |     // appLate: The regular app vsync phase offset. | 
 | 59 |     void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) { | 
 | 60 |         mEarlyOffsets = early; | 
 | 61 |         mEarlyGlOffsets = earlyGl; | 
 | 62 |         mLateOffsets = late; | 
| Ady Abraham | f665635 | 2019-02-14 16:29:49 -0800 | [diff] [blame] | 63 |  | 
 | 64 |         if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { | 
 | 65 |             mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); | 
 | 66 |         } | 
 | 67 |  | 
 | 68 |         if (mAppConnectionHandle && late.app != mOffsets.load().app) { | 
 | 69 |             mScheduler->setPhaseOffset(mAppConnectionHandle, late.app); | 
 | 70 |         } | 
 | 71 |  | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 72 |         mOffsets = late; | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 73 |     } | 
 | 74 |  | 
| Ana Krulec | fefcb58 | 2018-08-07 14:22:37 -0700 | [diff] [blame] | 75 |     Offsets getEarlyOffsets() const { return mEarlyOffsets; } | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 76 |  | 
| Ana Krulec | fefcb58 | 2018-08-07 14:22:37 -0700 | [diff] [blame] | 77 |     Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; } | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 78 |  | 
 | 79 |     void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { | 
 | 80 |         mSfEventThread = sfEventThread; | 
 | 81 |         mAppEventThread = appEventThread; | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 82 |     } | 
 | 83 |  | 
| Ana Krulec | 12096d0 | 2018-09-07 14:54:14 -0700 | [diff] [blame] | 84 |     void setSchedulerAndHandles(Scheduler* scheduler, | 
 | 85 |                                 Scheduler::ConnectionHandle* appConnectionHandle, | 
 | 86 |                                 Scheduler::ConnectionHandle* sfConnectionHandle) { | 
 | 87 |         mScheduler = scheduler; | 
 | 88 |         mAppConnectionHandle = appConnectionHandle; | 
 | 89 |         mSfConnectionHandle = sfConnectionHandle; | 
 | 90 |     } | 
 | 91 |  | 
| Ana Krulec | 7ecce8c | 2018-10-12 13:44:41 -0700 | [diff] [blame] | 92 |     void setTransactionStart(Scheduler::TransactionStart transactionStart) { | 
 | 93 |         if (transactionStart == Scheduler::TransactionStart::EARLY) { | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 94 |             mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 95 |         } | 
 | 96 |  | 
| Jorim Jaggi | f15c3be | 2018-04-12 12:56:58 +0100 | [diff] [blame] | 97 |         // An early transaction stays an early transaction. | 
| Ana Krulec | 7ecce8c | 2018-10-12 13:44:41 -0700 | [diff] [blame] | 98 |         if (transactionStart == mTransactionStart || | 
 | 99 |             mTransactionStart == Scheduler::TransactionStart::EARLY) { | 
| Jorim Jaggi | f15c3be | 2018-04-12 12:56:58 +0100 | [diff] [blame] | 100 |             return; | 
 | 101 |         } | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 102 |         mTransactionStart = transactionStart; | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 103 |         updateOffsets(); | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 104 |     } | 
 | 105 |  | 
| Jorim Jaggi | f15c3be | 2018-04-12 12:56:58 +0100 | [diff] [blame] | 106 |     void onTransactionHandled() { | 
| Ana Krulec | 7ecce8c | 2018-10-12 13:44:41 -0700 | [diff] [blame] | 107 |         if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; | 
 | 108 |         mTransactionStart = Scheduler::TransactionStart::NORMAL; | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 109 |         updateOffsets(); | 
| Jorim Jaggi | f15c3be | 2018-04-12 12:56:58 +0100 | [diff] [blame] | 110 |     } | 
 | 111 |  | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 112 |     // Called when we send a refresh rate change to hardware composer, so that | 
 | 113 |     // we can move into early offsets. | 
 | 114 |     void onRefreshRateChangeInitiated() { | 
 | 115 |         if (mRefreshRateChangePending) { | 
 | 116 |             return; | 
 | 117 |         } | 
 | 118 |         mRefreshRateChangePending = true; | 
 | 119 |         updateOffsets(); | 
 | 120 |     } | 
 | 121 |  | 
 | 122 |     // Called when we detect from vsync signals that the refresh rate changed. | 
 | 123 |     // This way we can move out of early offsets if no longer necessary. | 
 | 124 |     void onRefreshRateChangeDetected() { | 
 | 125 |         if (!mRefreshRateChangePending) { | 
 | 126 |             return; | 
 | 127 |         } | 
 | 128 |         mRefreshRateChangePending = false; | 
 | 129 |         updateOffsets(); | 
 | 130 |     } | 
 | 131 |  | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 132 |     void onRefreshed(bool usedRenderEngine) { | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 133 |         bool updateOffsetsNeeded = false; | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 134 |         if (mRemainingEarlyFrameCount > 0) { | 
 | 135 |             mRemainingEarlyFrameCount--; | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 136 |             updateOffsetsNeeded = true; | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 137 |         } | 
| Alec Mouri | 98fca26 | 2019-05-23 07:14:20 -0700 | [diff] [blame] | 138 |         if (usedRenderEngine) { | 
 | 139 |             mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION; | 
 | 140 |             updateOffsetsNeeded = true; | 
 | 141 |         } else if (mRemainingRenderEngineUsageCount > 0) { | 
 | 142 |             mRemainingRenderEngineUsageCount--; | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 143 |             updateOffsetsNeeded = true; | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 144 |         } | 
| Alec Mouri | 98fca26 | 2019-05-23 07:14:20 -0700 | [diff] [blame] | 145 |  | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 146 |         if (updateOffsetsNeeded) { | 
 | 147 |             updateOffsets(); | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 148 |         } | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 149 |     } | 
 | 150 |  | 
| Ady Abraham | be0f948 | 2019-04-24 15:41:53 -0700 | [diff] [blame] | 151 |     Offsets getOffsets() { | 
 | 152 |         // Early offsets are used if we're in the middle of a refresh rate | 
 | 153 |         // change, or if we recently begin a transaction. | 
 | 154 |         if (mTransactionStart == Scheduler::TransactionStart::EARLY || | 
 | 155 |             mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { | 
 | 156 |             return mEarlyOffsets; | 
| Alec Mouri | 98fca26 | 2019-05-23 07:14:20 -0700 | [diff] [blame] | 157 |         } else if (mRemainingRenderEngineUsageCount > 0) { | 
| Ady Abraham | be0f948 | 2019-04-24 15:41:53 -0700 | [diff] [blame] | 158 |             return mEarlyGlOffsets; | 
 | 159 |         } else { | 
 | 160 |             return mLateOffsets; | 
 | 161 |         } | 
 | 162 |     } | 
 | 163 |  | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 164 | private: | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 165 |     void updateOffsets() { | 
 | 166 |         const Offsets desired = getOffsets(); | 
 | 167 |         const Offsets current = mOffsets; | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 168 |  | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 169 |         bool changed = false; | 
 | 170 |         if (desired.sf != current.sf) { | 
| Ana Krulec | 12096d0 | 2018-09-07 14:54:14 -0700 | [diff] [blame] | 171 |             if (mSfConnectionHandle != nullptr) { | 
 | 172 |                 mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); | 
 | 173 |             } else { | 
 | 174 |                 mSfEventThread->setPhaseOffset(desired.sf); | 
 | 175 |             } | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 176 |             changed = true; | 
 | 177 |         } | 
 | 178 |         if (desired.app != current.app) { | 
| Ady Abraham | 3aff917 | 2019-02-07 19:10:26 -0800 | [diff] [blame] | 179 |             if (mAppConnectionHandle != nullptr) { | 
| Ana Krulec | 12096d0 | 2018-09-07 14:54:14 -0700 | [diff] [blame] | 180 |                 mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); | 
 | 181 |             } else { | 
 | 182 |                 mAppEventThread->setPhaseOffset(desired.app); | 
 | 183 |             } | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 184 |             changed = true; | 
 | 185 |         } | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 186 |  | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 187 |         if (changed) { | 
 | 188 |             mOffsets = desired; | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 189 |         } | 
 | 190 |     } | 
 | 191 |  | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 192 |     Offsets mLateOffsets; | 
 | 193 |     Offsets mEarlyOffsets; | 
 | 194 |     Offsets mEarlyGlOffsets; | 
 | 195 |  | 
 | 196 |     EventThread* mSfEventThread = nullptr; | 
 | 197 |     EventThread* mAppEventThread = nullptr; | 
 | 198 |  | 
| Ana Krulec | 12096d0 | 2018-09-07 14:54:14 -0700 | [diff] [blame] | 199 |     Scheduler* mScheduler = nullptr; | 
 | 200 |     Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; | 
 | 201 |     Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; | 
 | 202 |  | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 203 |     std::atomic<Offsets> mOffsets; | 
 | 204 |  | 
| Ana Krulec | 7ecce8c | 2018-10-12 13:44:41 -0700 | [diff] [blame] | 205 |     std::atomic<Scheduler::TransactionStart> mTransactionStart = | 
 | 206 |             Scheduler::TransactionStart::NORMAL; | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 207 |     std::atomic<bool> mRefreshRateChangePending = false; | 
| Jorim Jaggi | 9053521 | 2018-05-23 23:44:06 +0200 | [diff] [blame] | 208 |     std::atomic<int> mRemainingEarlyFrameCount = 0; | 
| Alec Mouri | 98fca26 | 2019-05-23 07:14:20 -0700 | [diff] [blame] | 209 |     std::atomic<int> mRemainingRenderEngineUsageCount = 0; | 
| Dan Stoza | 2713c30 | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 210 | }; | 
 | 211 |  | 
 | 212 | } // namespace android |