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