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 21 #include <cinttypes> 22 #include <mutex> 23 24 #include "Scheduler.h" 25 26 namespace android { 27 28 /* 29 * Modulates the vsync-offsets depending on current SurfaceFlinger state. 30 */ 31 class VSyncModulator { 32 private: 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; 37 38 public: 39 struct Offsets { 40 nsecs_t sf; 41 nsecs_t app; 42 }; 43 44 // Sets the phase offsets 45 // 46 // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction 47 // as early. May be the same as late, in which case we don't shift offsets. 48 // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition 49 // and the transaction was marked as early, we'll use sfEarly. 50 // sfLate: The regular SF vsync phase offset. 51 // appEarly: Like sfEarly, but for the app-vsync 52 // appEarlyGl: Like sfEarlyGl, but for the app-vsync. 53 // appLate: The regular app vsync phase offset. setPhaseOffsets(Offsets early,Offsets earlyGl,Offsets late)54 void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) { 55 mEarlyOffsets = early; 56 mEarlyGlOffsets = earlyGl; 57 mLateOffsets = late; 58 59 if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { 60 mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); 61 } 62 63 if (mAppConnectionHandle && late.app != mOffsets.load().app) { 64 mScheduler->setPhaseOffset(mAppConnectionHandle, late.app); 65 } 66 67 mOffsets = late; 68 } 69 getEarlyOffsets()70 Offsets getEarlyOffsets() const { return mEarlyOffsets; } 71 getEarlyGlOffsets()72 Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; } 73 setEventThreads(EventThread * sfEventThread,EventThread * appEventThread)74 void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { 75 mSfEventThread = sfEventThread; 76 mAppEventThread = appEventThread; 77 } 78 setSchedulerAndHandles(Scheduler * scheduler,Scheduler::ConnectionHandle * appConnectionHandle,Scheduler::ConnectionHandle * sfConnectionHandle)79 void setSchedulerAndHandles(Scheduler* scheduler, 80 Scheduler::ConnectionHandle* appConnectionHandle, 81 Scheduler::ConnectionHandle* sfConnectionHandle) { 82 mScheduler = scheduler; 83 mAppConnectionHandle = appConnectionHandle; 84 mSfConnectionHandle = sfConnectionHandle; 85 } 86 setTransactionStart(Scheduler::TransactionStart transactionStart)87 void setTransactionStart(Scheduler::TransactionStart transactionStart) { 88 if (transactionStart == Scheduler::TransactionStart::EARLY) { 89 mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; 90 } 91 92 // An early transaction stays an early transaction. 93 if (transactionStart == mTransactionStart || 94 mTransactionStart == Scheduler::TransactionStart::EARLY) { 95 return; 96 } 97 mTransactionStart = transactionStart; 98 updateOffsets(); 99 } 100 onTransactionHandled()101 void onTransactionHandled() { 102 if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; 103 mTransactionStart = Scheduler::TransactionStart::NORMAL; 104 updateOffsets(); 105 } 106 107 // Called when we send a refresh rate change to hardware composer, so that 108 // we can move into early offsets. onRefreshRateChangeInitiated()109 void onRefreshRateChangeInitiated() { 110 if (mRefreshRateChangePending) { 111 return; 112 } 113 mRefreshRateChangePending = true; 114 updateOffsets(); 115 } 116 117 // Called when we detect from vsync signals that the refresh rate changed. 118 // This way we can move out of early offsets if no longer necessary. onRefreshRateChangeDetected()119 void onRefreshRateChangeDetected() { 120 if (!mRefreshRateChangePending) { 121 return; 122 } 123 mRefreshRateChangePending = false; 124 updateOffsets(); 125 } 126 onRefreshed(bool usedRenderEngine)127 void onRefreshed(bool usedRenderEngine) { 128 bool updateOffsetsNeeded = false; 129 if (mRemainingEarlyFrameCount > 0) { 130 mRemainingEarlyFrameCount--; 131 updateOffsetsNeeded = true; 132 } 133 if (usedRenderEngine != mLastFrameUsedRenderEngine) { 134 mLastFrameUsedRenderEngine = usedRenderEngine; 135 updateOffsetsNeeded = true; 136 } 137 if (updateOffsetsNeeded) { 138 updateOffsets(); 139 } 140 } 141 getOffsets()142 Offsets getOffsets() { 143 // Early offsets are used if we're in the middle of a refresh rate 144 // change, or if we recently begin a transaction. 145 if (mTransactionStart == Scheduler::TransactionStart::EARLY || 146 mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { 147 return mEarlyOffsets; 148 } else if (mLastFrameUsedRenderEngine) { 149 return mEarlyGlOffsets; 150 } else { 151 return mLateOffsets; 152 } 153 } 154 155 private: updateOffsets()156 void updateOffsets() { 157 const Offsets desired = getOffsets(); 158 const Offsets current = mOffsets; 159 160 bool changed = false; 161 if (desired.sf != current.sf) { 162 if (mSfConnectionHandle != nullptr) { 163 mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); 164 } else { 165 mSfEventThread->setPhaseOffset(desired.sf); 166 } 167 changed = true; 168 } 169 if (desired.app != current.app) { 170 if (mAppConnectionHandle != nullptr) { 171 mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); 172 } else { 173 mAppEventThread->setPhaseOffset(desired.app); 174 } 175 changed = true; 176 } 177 178 if (changed) { 179 mOffsets = desired; 180 } 181 } 182 183 Offsets mLateOffsets; 184 Offsets mEarlyOffsets; 185 Offsets mEarlyGlOffsets; 186 187 EventThread* mSfEventThread = nullptr; 188 EventThread* mAppEventThread = nullptr; 189 190 Scheduler* mScheduler = nullptr; 191 Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; 192 Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; 193 194 std::atomic<Offsets> mOffsets; 195 196 std::atomic<Scheduler::TransactionStart> mTransactionStart = 197 Scheduler::TransactionStart::NORMAL; 198 std::atomic<bool> mLastFrameUsedRenderEngine = false; 199 std::atomic<bool> mRefreshRateChangePending = false; 200 std::atomic<int> mRemainingEarlyFrameCount = 0; 201 }; 202 203 } // namespace android 204