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 <mutex> 22 23 using namespace android::surfaceflinger; 24 25 namespace android { 26 27 /* 28 * Modulates the vsync-offsets depending on current SurfaceFlinger state. 29 */ 30 class VSyncModulator { 31 private: 32 33 // Number of frames we'll keep the early phase offsets once they are activated. This acts as a 34 // low-pass filter in case the client isn't quick enough in sending new transactions. 35 const int MIN_EARLY_FRAME_COUNT = 2; 36 37 public: 38 39 enum TransactionStart { 40 EARLY, 41 NORMAL 42 }; 43 44 // Sets the phase offsets 45 // 46 // early: the phase offset when waking up early. May be the same as late, in which case we don't 47 // shift offsets. 48 // late: the regular sf phase offset. setPhaseOffsets(nsecs_t early,nsecs_t late)49 void setPhaseOffsets(nsecs_t early, nsecs_t late) { 50 mEarlyPhaseOffset = early; 51 mLatePhaseOffset = late; 52 mPhaseOffset = late; 53 } 54 getEarlyPhaseOffset()55 nsecs_t getEarlyPhaseOffset() const { 56 return mEarlyPhaseOffset; 57 } 58 setEventThread(EventThread * eventThread)59 void setEventThread(EventThread* eventThread) { 60 mEventThread = eventThread; 61 } 62 setTransactionStart(TransactionStart transactionStart)63 void setTransactionStart(TransactionStart transactionStart) { 64 65 if (transactionStart == TransactionStart::EARLY) { 66 mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT; 67 } 68 69 // An early transaction stays an early transaction. 70 if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) { 71 return; 72 } 73 mTransactionStart = transactionStart; 74 updatePhaseOffsets(); 75 } 76 onTransactionHandled()77 void onTransactionHandled() { 78 if (mTransactionStart == TransactionStart::NORMAL) return; 79 mTransactionStart = TransactionStart::NORMAL; 80 updatePhaseOffsets(); 81 } 82 onRefreshed(bool usedRenderEngine)83 void onRefreshed(bool usedRenderEngine) { 84 bool updatePhaseOffsetsNeeded = false; 85 if (mRemainingEarlyFrameCount > 0) { 86 mRemainingEarlyFrameCount--; 87 updatePhaseOffsetsNeeded = true; 88 } 89 if (usedRenderEngine != mLastFrameUsedRenderEngine) { 90 mLastFrameUsedRenderEngine = usedRenderEngine; 91 updatePhaseOffsetsNeeded = true; 92 } 93 if (updatePhaseOffsetsNeeded) { 94 updatePhaseOffsets(); 95 } 96 } 97 98 private: 99 updatePhaseOffsets()100 void updatePhaseOffsets() { 101 102 // Do not change phase offsets if disabled. 103 if (mEarlyPhaseOffset == mLatePhaseOffset) return; 104 105 if (shouldUseEarlyOffset()) { 106 if (mPhaseOffset != mEarlyPhaseOffset) { 107 if (mEventThread) { 108 mEventThread->setPhaseOffset(mEarlyPhaseOffset); 109 } 110 mPhaseOffset = mEarlyPhaseOffset; 111 } 112 } else { 113 if (mPhaseOffset != mLatePhaseOffset) { 114 if (mEventThread) { 115 mEventThread->setPhaseOffset(mLatePhaseOffset); 116 } 117 mPhaseOffset = mLatePhaseOffset; 118 } 119 } 120 } 121 shouldUseEarlyOffset()122 bool shouldUseEarlyOffset() { 123 return mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine 124 || mRemainingEarlyFrameCount > 0; 125 } 126 127 nsecs_t mLatePhaseOffset = 0; 128 nsecs_t mEarlyPhaseOffset = 0; 129 EventThread* mEventThread = nullptr; 130 std::atomic<nsecs_t> mPhaseOffset = 0; 131 std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL; 132 std::atomic<bool> mLastFrameUsedRenderEngine = false; 133 std::atomic<int> mRemainingEarlyFrameCount = 0; 134 }; 135 136 } // namespace android 137