• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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