xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <vector>
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <common/trace.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <ftl/concat.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <log/log_main.h>
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker #include <scheduler/TimeKeeper.h>
27*38e8c45fSAndroid Build Coastguard Worker 
28*38e8c45fSAndroid Build Coastguard Worker #include <common/FlagManager.h>
29*38e8c45fSAndroid Build Coastguard Worker #include "VSyncDispatchTimerQueue.h"
30*38e8c45fSAndroid Build Coastguard Worker #include "VSyncTracker.h"
31*38e8c45fSAndroid Build Coastguard Worker 
32*38e8c45fSAndroid Build Coastguard Worker #undef LOG_TAG
33*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "VSyncDispatch"
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker namespace android::scheduler {
36*38e8c45fSAndroid Build Coastguard Worker 
37*38e8c45fSAndroid Build Coastguard Worker using base::StringAppendF;
38*38e8c45fSAndroid Build Coastguard Worker 
39*38e8c45fSAndroid Build Coastguard Worker namespace {
40*38e8c45fSAndroid Build Coastguard Worker 
getExpectedCallbackTime(nsecs_t nextVsyncTime,const VSyncDispatch::ScheduleTiming & timing)41*38e8c45fSAndroid Build Coastguard Worker ScheduleResult getExpectedCallbackTime(nsecs_t nextVsyncTime,
42*38e8c45fSAndroid Build Coastguard Worker                                        const VSyncDispatch::ScheduleTiming& timing) {
43*38e8c45fSAndroid Build Coastguard Worker     return {TimePoint::fromNs(nextVsyncTime - timing.readyDuration - timing.workDuration),
44*38e8c45fSAndroid Build Coastguard Worker             TimePoint::fromNs(nextVsyncTime)};
45*38e8c45fSAndroid Build Coastguard Worker }
46*38e8c45fSAndroid Build Coastguard Worker 
traceEntry(const VSyncDispatchTimerQueueEntry & entry,nsecs_t now)47*38e8c45fSAndroid Build Coastguard Worker void traceEntry(const VSyncDispatchTimerQueueEntry& entry, nsecs_t now) {
48*38e8c45fSAndroid Build Coastguard Worker     if (!SFTRACE_ENABLED() || !entry.wakeupTime().has_value() || !entry.targetVsync().has_value()) {
49*38e8c45fSAndroid Build Coastguard Worker         return;
50*38e8c45fSAndroid Build Coastguard Worker     }
51*38e8c45fSAndroid Build Coastguard Worker 
52*38e8c45fSAndroid Build Coastguard Worker     ftl::Concat trace(ftl::truncated<5>(entry.name()), " alarm in ",
53*38e8c45fSAndroid Build Coastguard Worker                       ns2us(*entry.wakeupTime() - now), "us; VSYNC in ",
54*38e8c45fSAndroid Build Coastguard Worker                       ns2us(*entry.targetVsync() - now), "us");
55*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_FORMAT_INSTANT(trace.c_str());
56*38e8c45fSAndroid Build Coastguard Worker }
57*38e8c45fSAndroid Build Coastguard Worker 
58*38e8c45fSAndroid Build Coastguard Worker } // namespace
59*38e8c45fSAndroid Build Coastguard Worker 
60*38e8c45fSAndroid Build Coastguard Worker VSyncDispatch::~VSyncDispatch() = default;
61*38e8c45fSAndroid Build Coastguard Worker VSyncTracker::~VSyncTracker() = default;
62*38e8c45fSAndroid Build Coastguard Worker 
VSyncDispatchTimerQueueEntry(std::string name,VSyncDispatch::Callback callback,nsecs_t minVsyncDistance)63*38e8c45fSAndroid Build Coastguard Worker VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
64*38e8c45fSAndroid Build Coastguard Worker                                                            VSyncDispatch::Callback callback,
65*38e8c45fSAndroid Build Coastguard Worker                                                            nsecs_t minVsyncDistance)
66*38e8c45fSAndroid Build Coastguard Worker       : mName(std::move(name)),
67*38e8c45fSAndroid Build Coastguard Worker         mCallback(std::move(callback)),
68*38e8c45fSAndroid Build Coastguard Worker         mMinVsyncDistance(minVsyncDistance) {}
69*38e8c45fSAndroid Build Coastguard Worker 
lastExecutedVsyncTarget() const70*38e8c45fSAndroid Build Coastguard Worker std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
71*38e8c45fSAndroid Build Coastguard Worker     return mLastDispatchTime;
72*38e8c45fSAndroid Build Coastguard Worker }
73*38e8c45fSAndroid Build Coastguard Worker 
name() const74*38e8c45fSAndroid Build Coastguard Worker std::string_view VSyncDispatchTimerQueueEntry::name() const {
75*38e8c45fSAndroid Build Coastguard Worker     return mName;
76*38e8c45fSAndroid Build Coastguard Worker }
77*38e8c45fSAndroid Build Coastguard Worker 
wakeupTime() const78*38e8c45fSAndroid Build Coastguard Worker std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
79*38e8c45fSAndroid Build Coastguard Worker     if (!mArmedInfo) {
80*38e8c45fSAndroid Build Coastguard Worker         return {};
81*38e8c45fSAndroid Build Coastguard Worker     }
82*38e8c45fSAndroid Build Coastguard Worker     return {mArmedInfo->mActualWakeupTime};
83*38e8c45fSAndroid Build Coastguard Worker }
84*38e8c45fSAndroid Build Coastguard Worker 
readyTime() const85*38e8c45fSAndroid Build Coastguard Worker std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
86*38e8c45fSAndroid Build Coastguard Worker     if (!mArmedInfo) {
87*38e8c45fSAndroid Build Coastguard Worker         return {};
88*38e8c45fSAndroid Build Coastguard Worker     }
89*38e8c45fSAndroid Build Coastguard Worker     return {mArmedInfo->mActualReadyTime};
90*38e8c45fSAndroid Build Coastguard Worker }
91*38e8c45fSAndroid Build Coastguard Worker 
targetVsync() const92*38e8c45fSAndroid Build Coastguard Worker std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
93*38e8c45fSAndroid Build Coastguard Worker     if (!mArmedInfo) {
94*38e8c45fSAndroid Build Coastguard Worker         return {};
95*38e8c45fSAndroid Build Coastguard Worker     }
96*38e8c45fSAndroid Build Coastguard Worker     return {mArmedInfo->mActualVsyncTime};
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker 
schedule(VSyncDispatch::ScheduleTiming timing,VSyncTracker & tracker,nsecs_t now)99*38e8c45fSAndroid Build Coastguard Worker ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
100*38e8c45fSAndroid Build Coastguard Worker                                                       VSyncTracker& tracker, nsecs_t now) {
101*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_NAME("VSyncDispatchTimerQueueEntry::schedule");
102*38e8c45fSAndroid Build Coastguard Worker     auto nextVsyncTime =
103*38e8c45fSAndroid Build Coastguard Worker             tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
104*38e8c45fSAndroid Build Coastguard Worker                                                           now + timing.workDuration +
105*38e8c45fSAndroid Build Coastguard Worker                                                                   timing.readyDuration),
106*38e8c45fSAndroid Build Coastguard Worker                                                  timing.committedVsyncOpt.value_or(
107*38e8c45fSAndroid Build Coastguard Worker                                                          timing.lastVsync));
108*38e8c45fSAndroid Build Coastguard Worker     auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
109*38e8c45fSAndroid Build Coastguard Worker 
110*38e8c45fSAndroid Build Coastguard Worker     bool const wouldSkipAVsyncTarget =
111*38e8c45fSAndroid Build Coastguard Worker             mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
112*38e8c45fSAndroid Build Coastguard Worker     bool const wouldSkipAWakeup =
113*38e8c45fSAndroid Build Coastguard Worker             mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
114*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_FORMAT_INSTANT("%s: wouldSkipAVsyncTarget=%d wouldSkipAWakeup=%d", mName.c_str(),
115*38e8c45fSAndroid Build Coastguard Worker                            wouldSkipAVsyncTarget, wouldSkipAWakeup);
116*38e8c45fSAndroid Build Coastguard Worker     if (FlagManager::getInstance().dont_skip_on_early_ro()) {
117*38e8c45fSAndroid Build Coastguard Worker         if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
118*38e8c45fSAndroid Build Coastguard Worker             nextVsyncTime = mArmedInfo->mActualVsyncTime;
119*38e8c45fSAndroid Build Coastguard Worker         } else {
120*38e8c45fSAndroid Build Coastguard Worker             nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
121*38e8c45fSAndroid Build Coastguard Worker         }
122*38e8c45fSAndroid Build Coastguard Worker         nextWakeupTime = std::max(now, nextVsyncTime - timing.workDuration - timing.readyDuration);
123*38e8c45fSAndroid Build Coastguard Worker     } else {
124*38e8c45fSAndroid Build Coastguard Worker         if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
125*38e8c45fSAndroid Build Coastguard Worker             return getExpectedCallbackTime(nextVsyncTime, timing);
126*38e8c45fSAndroid Build Coastguard Worker         }
127*38e8c45fSAndroid Build Coastguard Worker         nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
128*38e8c45fSAndroid Build Coastguard Worker         nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
129*38e8c45fSAndroid Build Coastguard Worker     }
130*38e8c45fSAndroid Build Coastguard Worker 
131*38e8c45fSAndroid Build Coastguard Worker     auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
132*38e8c45fSAndroid Build Coastguard Worker     mScheduleTiming = timing;
133*38e8c45fSAndroid Build Coastguard Worker     mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
134*38e8c45fSAndroid Build Coastguard Worker     return ScheduleResult{TimePoint::fromNs(nextWakeupTime), TimePoint::fromNs(nextVsyncTime)};
135*38e8c45fSAndroid Build Coastguard Worker }
136*38e8c45fSAndroid Build Coastguard Worker 
addPendingWorkloadUpdate(VSyncTracker & tracker,nsecs_t now,VSyncDispatch::ScheduleTiming timing)137*38e8c45fSAndroid Build Coastguard Worker ScheduleResult VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
138*38e8c45fSAndroid Build Coastguard Worker         VSyncTracker& tracker, nsecs_t now, VSyncDispatch::ScheduleTiming timing) {
139*38e8c45fSAndroid Build Coastguard Worker     mWorkloadUpdateInfo = timing;
140*38e8c45fSAndroid Build Coastguard Worker     const auto armedInfo = getArmedInfo(tracker, now, timing, mArmedInfo);
141*38e8c45fSAndroid Build Coastguard Worker     return {TimePoint::fromNs(armedInfo.mActualWakeupTime),
142*38e8c45fSAndroid Build Coastguard Worker             TimePoint::fromNs(armedInfo.mActualVsyncTime)};
143*38e8c45fSAndroid Build Coastguard Worker }
144*38e8c45fSAndroid Build Coastguard Worker 
hasPendingWorkloadUpdate() const145*38e8c45fSAndroid Build Coastguard Worker bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
146*38e8c45fSAndroid Build Coastguard Worker     return mWorkloadUpdateInfo.has_value();
147*38e8c45fSAndroid Build Coastguard Worker }
148*38e8c45fSAndroid Build Coastguard Worker 
adjustVsyncIfNeeded(VSyncTracker & tracker,nsecs_t nextVsyncTime) const149*38e8c45fSAndroid Build Coastguard Worker nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
150*38e8c45fSAndroid Build Coastguard Worker                                                           nsecs_t nextVsyncTime) const {
151*38e8c45fSAndroid Build Coastguard Worker     bool const alreadyDispatchedForVsync = mLastDispatchTime &&
152*38e8c45fSAndroid Build Coastguard Worker             ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
153*38e8c45fSAndroid Build Coastguard Worker              (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
154*38e8c45fSAndroid Build Coastguard Worker     const nsecs_t currentPeriod = tracker.currentPeriod();
155*38e8c45fSAndroid Build Coastguard Worker     bool const nextVsyncTooClose = mLastDispatchTime &&
156*38e8c45fSAndroid Build Coastguard Worker             (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
157*38e8c45fSAndroid Build Coastguard Worker     if (alreadyDispatchedForVsync) {
158*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_FORMAT_INSTANT("alreadyDispatchedForVsync");
159*38e8c45fSAndroid Build Coastguard Worker         return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance,
160*38e8c45fSAndroid Build Coastguard Worker                                                     *mLastDispatchTime);
161*38e8c45fSAndroid Build Coastguard Worker     }
162*38e8c45fSAndroid Build Coastguard Worker 
163*38e8c45fSAndroid Build Coastguard Worker     if (nextVsyncTooClose) {
164*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_FORMAT_INSTANT("nextVsyncTooClose");
165*38e8c45fSAndroid Build Coastguard Worker         return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod,
166*38e8c45fSAndroid Build Coastguard Worker                                                     *mLastDispatchTime + currentPeriod);
167*38e8c45fSAndroid Build Coastguard Worker     }
168*38e8c45fSAndroid Build Coastguard Worker 
169*38e8c45fSAndroid Build Coastguard Worker     return nextVsyncTime;
170*38e8c45fSAndroid Build Coastguard Worker }
171*38e8c45fSAndroid Build Coastguard Worker 
getArmedInfo(VSyncTracker & tracker,nsecs_t now,VSyncDispatch::ScheduleTiming timing,std::optional<ArmingInfo> armedInfo) const172*38e8c45fSAndroid Build Coastguard Worker auto VSyncDispatchTimerQueueEntry::getArmedInfo(VSyncTracker& tracker, nsecs_t now,
173*38e8c45fSAndroid Build Coastguard Worker                                                 VSyncDispatch::ScheduleTiming timing,
174*38e8c45fSAndroid Build Coastguard Worker                                                 std::optional<ArmingInfo> armedInfo) const
175*38e8c45fSAndroid Build Coastguard Worker         -> ArmingInfo {
176*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_NAME("VSyncDispatchTimerQueueEntry::getArmedInfo");
177*38e8c45fSAndroid Build Coastguard Worker     const auto earliestReadyBy = now + timing.workDuration + timing.readyDuration;
178*38e8c45fSAndroid Build Coastguard Worker     const auto earliestVsync = std::max(earliestReadyBy, timing.lastVsync);
179*38e8c45fSAndroid Build Coastguard Worker 
180*38e8c45fSAndroid Build Coastguard Worker     const auto nextVsyncTime =
181*38e8c45fSAndroid Build Coastguard Worker             adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
182*38e8c45fSAndroid Build Coastguard Worker                                 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync,
183*38e8c45fSAndroid Build Coastguard Worker                                                                      timing.lastVsync));
184*38e8c45fSAndroid Build Coastguard Worker     const auto nextReadyTime = nextVsyncTime - timing.readyDuration;
185*38e8c45fSAndroid Build Coastguard Worker     const auto nextWakeupTime = nextReadyTime - timing.workDuration;
186*38e8c45fSAndroid Build Coastguard Worker 
187*38e8c45fSAndroid Build Coastguard Worker     if (FlagManager::getInstance().dont_skip_on_early_ro()) {
188*38e8c45fSAndroid Build Coastguard Worker         bool const wouldSkipAVsyncTarget =
189*38e8c45fSAndroid Build Coastguard Worker                 armedInfo && (nextVsyncTime > (armedInfo->mActualVsyncTime + mMinVsyncDistance));
190*38e8c45fSAndroid Build Coastguard Worker         bool const wouldSkipAWakeup =
191*38e8c45fSAndroid Build Coastguard Worker                 armedInfo && (nextWakeupTime > (armedInfo->mActualWakeupTime + mMinVsyncDistance));
192*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_FORMAT_INSTANT("%s: wouldSkipAVsyncTarget=%d wouldSkipAWakeup=%d", mName.c_str(),
193*38e8c45fSAndroid Build Coastguard Worker                                wouldSkipAVsyncTarget, wouldSkipAWakeup);
194*38e8c45fSAndroid Build Coastguard Worker         if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
195*38e8c45fSAndroid Build Coastguard Worker             return *armedInfo;
196*38e8c45fSAndroid Build Coastguard Worker         }
197*38e8c45fSAndroid Build Coastguard Worker     }
198*38e8c45fSAndroid Build Coastguard Worker 
199*38e8c45fSAndroid Build Coastguard Worker     return ArmingInfo{nextWakeupTime, nextVsyncTime, nextReadyTime};
200*38e8c45fSAndroid Build Coastguard Worker }
201*38e8c45fSAndroid Build Coastguard Worker 
update(VSyncTracker & tracker,nsecs_t now)202*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
203*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_NAME("VSyncDispatchTimerQueueEntry::update");
204*38e8c45fSAndroid Build Coastguard Worker     if (!mArmedInfo && !mWorkloadUpdateInfo) {
205*38e8c45fSAndroid Build Coastguard Worker         return;
206*38e8c45fSAndroid Build Coastguard Worker     }
207*38e8c45fSAndroid Build Coastguard Worker 
208*38e8c45fSAndroid Build Coastguard Worker     if (mWorkloadUpdateInfo) {
209*38e8c45fSAndroid Build Coastguard Worker         const auto workDelta = mWorkloadUpdateInfo->workDuration - mScheduleTiming.workDuration;
210*38e8c45fSAndroid Build Coastguard Worker         const auto readyDelta = mWorkloadUpdateInfo->readyDuration - mScheduleTiming.readyDuration;
211*38e8c45fSAndroid Build Coastguard Worker         const auto lastVsyncDelta = mWorkloadUpdateInfo->lastVsync - mScheduleTiming.lastVsync;
212*38e8c45fSAndroid Build Coastguard Worker         const auto lastCommittedVsyncDelta =
213*38e8c45fSAndroid Build Coastguard Worker                 mWorkloadUpdateInfo->committedVsyncOpt.value_or(mWorkloadUpdateInfo->lastVsync) -
214*38e8c45fSAndroid Build Coastguard Worker                 mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync);
215*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_FORMAT_INSTANT("Workload updated workDelta=%" PRId64 " readyDelta=%" PRId64
216*38e8c45fSAndroid Build Coastguard Worker                                " lastVsyncDelta=%" PRId64 " committedVsyncDelta=%" PRId64,
217*38e8c45fSAndroid Build Coastguard Worker                                workDelta, readyDelta, lastVsyncDelta, lastCommittedVsyncDelta);
218*38e8c45fSAndroid Build Coastguard Worker         mScheduleTiming = *mWorkloadUpdateInfo;
219*38e8c45fSAndroid Build Coastguard Worker         mWorkloadUpdateInfo.reset();
220*38e8c45fSAndroid Build Coastguard Worker     }
221*38e8c45fSAndroid Build Coastguard Worker 
222*38e8c45fSAndroid Build Coastguard Worker     mArmedInfo = getArmedInfo(tracker, now, mScheduleTiming, mArmedInfo);
223*38e8c45fSAndroid Build Coastguard Worker }
224*38e8c45fSAndroid Build Coastguard Worker 
disarm()225*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueueEntry::disarm() {
226*38e8c45fSAndroid Build Coastguard Worker     mArmedInfo.reset();
227*38e8c45fSAndroid Build Coastguard Worker }
228*38e8c45fSAndroid Build Coastguard Worker 
executing()229*38e8c45fSAndroid Build Coastguard Worker nsecs_t VSyncDispatchTimerQueueEntry::executing() {
230*38e8c45fSAndroid Build Coastguard Worker     mLastDispatchTime = mArmedInfo->mActualVsyncTime;
231*38e8c45fSAndroid Build Coastguard Worker     disarm();
232*38e8c45fSAndroid Build Coastguard Worker     return *mLastDispatchTime;
233*38e8c45fSAndroid Build Coastguard Worker }
234*38e8c45fSAndroid Build Coastguard Worker 
callback(nsecs_t vsyncTimestamp,nsecs_t wakeupTimestamp,nsecs_t deadlineTimestamp)235*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
236*38e8c45fSAndroid Build Coastguard Worker                                             nsecs_t deadlineTimestamp) {
237*38e8c45fSAndroid Build Coastguard Worker     {
238*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lk(mRunningMutex);
239*38e8c45fSAndroid Build Coastguard Worker         mRunning = true;
240*38e8c45fSAndroid Build Coastguard Worker     }
241*38e8c45fSAndroid Build Coastguard Worker 
242*38e8c45fSAndroid Build Coastguard Worker     mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
243*38e8c45fSAndroid Build Coastguard Worker 
244*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lk(mRunningMutex);
245*38e8c45fSAndroid Build Coastguard Worker     mRunning = false;
246*38e8c45fSAndroid Build Coastguard Worker     mCv.notify_all();
247*38e8c45fSAndroid Build Coastguard Worker }
248*38e8c45fSAndroid Build Coastguard Worker 
ensureNotRunning()249*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
250*38e8c45fSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lk(mRunningMutex);
251*38e8c45fSAndroid Build Coastguard Worker     mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
252*38e8c45fSAndroid Build Coastguard Worker }
253*38e8c45fSAndroid Build Coastguard Worker 
dump(std::string & result) const254*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
255*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lk(mRunningMutex);
256*38e8c45fSAndroid Build Coastguard Worker     std::string armedInfo;
257*38e8c45fSAndroid Build Coastguard Worker     if (mArmedInfo) {
258*38e8c45fSAndroid Build Coastguard Worker         StringAppendF(&armedInfo,
259*38e8c45fSAndroid Build Coastguard Worker                       "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
260*38e8c45fSAndroid Build Coastguard Worker                       (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
261*38e8c45fSAndroid Build Coastguard Worker                       (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
262*38e8c45fSAndroid Build Coastguard Worker                       (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
263*38e8c45fSAndroid Build Coastguard Worker     }
264*38e8c45fSAndroid Build Coastguard Worker 
265*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
266*38e8c45fSAndroid Build Coastguard Worker                   mRunning ? "(in callback function)" : "", armedInfo.c_str());
267*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&result,
268*38e8c45fSAndroid Build Coastguard Worker                   "\t\t\tworkDuration: %.2fms readyDuration: %.2fms "
269*38e8c45fSAndroid Build Coastguard Worker                   "lastVsync: %.2fms relative to now "
270*38e8c45fSAndroid Build Coastguard Worker                   "committedVsync: %.2fms relative to now\n",
271*38e8c45fSAndroid Build Coastguard Worker                   mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
272*38e8c45fSAndroid Build Coastguard Worker                   (mScheduleTiming.lastVsync - systemTime()) / 1e6f,
273*38e8c45fSAndroid Build Coastguard Worker                   (mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync) -
274*38e8c45fSAndroid Build Coastguard Worker                    systemTime()) /
275*38e8c45fSAndroid Build Coastguard Worker                           1e6f);
276*38e8c45fSAndroid Build Coastguard Worker 
277*38e8c45fSAndroid Build Coastguard Worker     if (mLastDispatchTime) {
278*38e8c45fSAndroid Build Coastguard Worker         StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
279*38e8c45fSAndroid Build Coastguard Worker                       (systemTime() - *mLastDispatchTime) / 1e6f);
280*38e8c45fSAndroid Build Coastguard Worker     } else {
281*38e8c45fSAndroid Build Coastguard Worker         StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
282*38e8c45fSAndroid Build Coastguard Worker     }
283*38e8c45fSAndroid Build Coastguard Worker }
284*38e8c45fSAndroid Build Coastguard Worker 
VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,VsyncSchedule::TrackerPtr tracker,nsecs_t timerSlack,nsecs_t minVsyncDistance)285*38e8c45fSAndroid Build Coastguard Worker VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
286*38e8c45fSAndroid Build Coastguard Worker                                                  VsyncSchedule::TrackerPtr tracker,
287*38e8c45fSAndroid Build Coastguard Worker                                                  nsecs_t timerSlack, nsecs_t minVsyncDistance)
288*38e8c45fSAndroid Build Coastguard Worker       : mTimeKeeper(std::move(tk)),
289*38e8c45fSAndroid Build Coastguard Worker         mTracker(std::move(tracker)),
290*38e8c45fSAndroid Build Coastguard Worker         mTimerSlack(timerSlack),
291*38e8c45fSAndroid Build Coastguard Worker         mMinVsyncDistance(minVsyncDistance) {}
292*38e8c45fSAndroid Build Coastguard Worker 
~VSyncDispatchTimerQueue()293*38e8c45fSAndroid Build Coastguard Worker VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
294*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
295*38e8c45fSAndroid Build Coastguard Worker     mRunning = false;
296*38e8c45fSAndroid Build Coastguard Worker     cancelTimer();
297*38e8c45fSAndroid Build Coastguard Worker     for (auto& [_, entry] : mCallbacks) {
298*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Forgot to unregister a callback on VSyncDispatch!");
299*38e8c45fSAndroid Build Coastguard Worker         entry->ensureNotRunning();
300*38e8c45fSAndroid Build Coastguard Worker     }
301*38e8c45fSAndroid Build Coastguard Worker }
302*38e8c45fSAndroid Build Coastguard Worker 
cancelTimer()303*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueue::cancelTimer() {
304*38e8c45fSAndroid Build Coastguard Worker     mIntendedWakeupTime = kInvalidTime;
305*38e8c45fSAndroid Build Coastguard Worker     mTimeKeeper->alarmCancel();
306*38e8c45fSAndroid Build Coastguard Worker }
307*38e8c45fSAndroid Build Coastguard Worker 
setTimer(nsecs_t targetTime,nsecs_t)308*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
309*38e8c45fSAndroid Build Coastguard Worker     mIntendedWakeupTime = targetTime;
310*38e8c45fSAndroid Build Coastguard Worker     mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
311*38e8c45fSAndroid Build Coastguard Worker                          mIntendedWakeupTime);
312*38e8c45fSAndroid Build Coastguard Worker     mLastTimerSchedule = mTimeKeeper->now();
313*38e8c45fSAndroid Build Coastguard Worker }
314*38e8c45fSAndroid Build Coastguard Worker 
rearmTimer(nsecs_t now)315*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
316*38e8c45fSAndroid Build Coastguard Worker     rearmTimerSkippingUpdateFor(now, mCallbacks.cend());
317*38e8c45fSAndroid Build Coastguard Worker }
318*38e8c45fSAndroid Build Coastguard Worker 
rearmTimerSkippingUpdateFor(nsecs_t now,CallbackMap::const_iterator skipUpdateIt)319*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
320*38e8c45fSAndroid Build Coastguard Worker         nsecs_t now, CallbackMap::const_iterator skipUpdateIt) {
321*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_CALL();
322*38e8c45fSAndroid Build Coastguard Worker     std::optional<nsecs_t> min;
323*38e8c45fSAndroid Build Coastguard Worker     std::optional<nsecs_t> targetVsync;
324*38e8c45fSAndroid Build Coastguard Worker     std::optional<std::string_view> nextWakeupName;
325*38e8c45fSAndroid Build Coastguard Worker     for (auto it = mCallbacks.cbegin(); it != mCallbacks.cend(); ++it) {
326*38e8c45fSAndroid Build Coastguard Worker         auto& callback = it->second;
327*38e8c45fSAndroid Build Coastguard Worker         if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
328*38e8c45fSAndroid Build Coastguard Worker             continue;
329*38e8c45fSAndroid Build Coastguard Worker         }
330*38e8c45fSAndroid Build Coastguard Worker 
331*38e8c45fSAndroid Build Coastguard Worker         if (it != skipUpdateIt) {
332*38e8c45fSAndroid Build Coastguard Worker             callback->update(*mTracker, now);
333*38e8c45fSAndroid Build Coastguard Worker         }
334*38e8c45fSAndroid Build Coastguard Worker 
335*38e8c45fSAndroid Build Coastguard Worker         traceEntry(*callback, now);
336*38e8c45fSAndroid Build Coastguard Worker 
337*38e8c45fSAndroid Build Coastguard Worker         const auto wakeupTime = *callback->wakeupTime();
338*38e8c45fSAndroid Build Coastguard Worker         if (!min || *min > wakeupTime) {
339*38e8c45fSAndroid Build Coastguard Worker             nextWakeupName = callback->name();
340*38e8c45fSAndroid Build Coastguard Worker             min = wakeupTime;
341*38e8c45fSAndroid Build Coastguard Worker             targetVsync = callback->targetVsync();
342*38e8c45fSAndroid Build Coastguard Worker         }
343*38e8c45fSAndroid Build Coastguard Worker     }
344*38e8c45fSAndroid Build Coastguard Worker 
345*38e8c45fSAndroid Build Coastguard Worker     if (min && min < mIntendedWakeupTime) {
346*38e8c45fSAndroid Build Coastguard Worker         setTimer(*min, now);
347*38e8c45fSAndroid Build Coastguard Worker     } else {
348*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_NAME("cancel timer");
349*38e8c45fSAndroid Build Coastguard Worker         cancelTimer();
350*38e8c45fSAndroid Build Coastguard Worker     }
351*38e8c45fSAndroid Build Coastguard Worker }
352*38e8c45fSAndroid Build Coastguard Worker 
timerCallback()353*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueue::timerCallback() {
354*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_CALL();
355*38e8c45fSAndroid Build Coastguard Worker     struct Invocation {
356*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
357*38e8c45fSAndroid Build Coastguard Worker         nsecs_t vsyncTimestamp;
358*38e8c45fSAndroid Build Coastguard Worker         nsecs_t wakeupTimestamp;
359*38e8c45fSAndroid Build Coastguard Worker         nsecs_t deadlineTimestamp;
360*38e8c45fSAndroid Build Coastguard Worker     };
361*38e8c45fSAndroid Build Coastguard Worker     std::vector<Invocation> invocations;
362*38e8c45fSAndroid Build Coastguard Worker     {
363*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard lock(mMutex);
364*38e8c45fSAndroid Build Coastguard Worker         if (!mRunning) {
365*38e8c45fSAndroid Build Coastguard Worker             ALOGD("TimerQueue is not running. Skipping callback.");
366*38e8c45fSAndroid Build Coastguard Worker             return;
367*38e8c45fSAndroid Build Coastguard Worker         }
368*38e8c45fSAndroid Build Coastguard Worker         auto const now = mTimeKeeper->now();
369*38e8c45fSAndroid Build Coastguard Worker         mLastTimerCallback = now;
370*38e8c45fSAndroid Build Coastguard Worker         for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
371*38e8c45fSAndroid Build Coastguard Worker             auto& callback = it->second;
372*38e8c45fSAndroid Build Coastguard Worker             auto const wakeupTime = callback->wakeupTime();
373*38e8c45fSAndroid Build Coastguard Worker             if (!wakeupTime) {
374*38e8c45fSAndroid Build Coastguard Worker                 continue;
375*38e8c45fSAndroid Build Coastguard Worker             }
376*38e8c45fSAndroid Build Coastguard Worker 
377*38e8c45fSAndroid Build Coastguard Worker             traceEntry(*callback, now);
378*38e8c45fSAndroid Build Coastguard Worker 
379*38e8c45fSAndroid Build Coastguard Worker             auto const readyTime = callback->readyTime();
380*38e8c45fSAndroid Build Coastguard Worker             auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
381*38e8c45fSAndroid Build Coastguard Worker             if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
382*38e8c45fSAndroid Build Coastguard Worker                 callback->executing();
383*38e8c45fSAndroid Build Coastguard Worker                 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
384*38e8c45fSAndroid Build Coastguard Worker                                                     *wakeupTime, *readyTime});
385*38e8c45fSAndroid Build Coastguard Worker             }
386*38e8c45fSAndroid Build Coastguard Worker         }
387*38e8c45fSAndroid Build Coastguard Worker 
388*38e8c45fSAndroid Build Coastguard Worker         mIntendedWakeupTime = kInvalidTime;
389*38e8c45fSAndroid Build Coastguard Worker         rearmTimer(mTimeKeeper->now());
390*38e8c45fSAndroid Build Coastguard Worker     }
391*38e8c45fSAndroid Build Coastguard Worker 
392*38e8c45fSAndroid Build Coastguard Worker     for (auto const& invocation : invocations) {
393*38e8c45fSAndroid Build Coastguard Worker         ftl::Concat trace(ftl::truncated<5>(invocation.callback->name()));
394*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_FORMAT("%s: %s", __func__, trace.c_str());
395*38e8c45fSAndroid Build Coastguard Worker         invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
396*38e8c45fSAndroid Build Coastguard Worker                                       invocation.deadlineTimestamp);
397*38e8c45fSAndroid Build Coastguard Worker     }
398*38e8c45fSAndroid Build Coastguard Worker }
399*38e8c45fSAndroid Build Coastguard Worker 
registerCallback(Callback callback,std::string callbackName)400*38e8c45fSAndroid Build Coastguard Worker VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
401*38e8c45fSAndroid Build Coastguard Worker         Callback callback, std::string callbackName) {
402*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
403*38e8c45fSAndroid Build Coastguard Worker     return mCallbacks
404*38e8c45fSAndroid Build Coastguard Worker             .try_emplace(++mCallbackToken,
405*38e8c45fSAndroid Build Coastguard Worker                          std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
406*38e8c45fSAndroid Build Coastguard Worker                                                                         std::move(callback),
407*38e8c45fSAndroid Build Coastguard Worker                                                                         mMinVsyncDistance))
408*38e8c45fSAndroid Build Coastguard Worker             .first->first;
409*38e8c45fSAndroid Build Coastguard Worker }
410*38e8c45fSAndroid Build Coastguard Worker 
unregisterCallback(CallbackToken token)411*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
412*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
413*38e8c45fSAndroid Build Coastguard Worker     {
414*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard lock(mMutex);
415*38e8c45fSAndroid Build Coastguard Worker         auto it = mCallbacks.find(token);
416*38e8c45fSAndroid Build Coastguard Worker         if (it != mCallbacks.end()) {
417*38e8c45fSAndroid Build Coastguard Worker             entry = it->second;
418*38e8c45fSAndroid Build Coastguard Worker             mCallbacks.erase(it->first);
419*38e8c45fSAndroid Build Coastguard Worker         }
420*38e8c45fSAndroid Build Coastguard Worker     }
421*38e8c45fSAndroid Build Coastguard Worker 
422*38e8c45fSAndroid Build Coastguard Worker     if (entry) {
423*38e8c45fSAndroid Build Coastguard Worker         entry->ensureNotRunning();
424*38e8c45fSAndroid Build Coastguard Worker     }
425*38e8c45fSAndroid Build Coastguard Worker }
426*38e8c45fSAndroid Build Coastguard Worker 
schedule(CallbackToken token,ScheduleTiming scheduleTiming)427*38e8c45fSAndroid Build Coastguard Worker std::optional<ScheduleResult> VSyncDispatchTimerQueue::schedule(CallbackToken token,
428*38e8c45fSAndroid Build Coastguard Worker                                                                 ScheduleTiming scheduleTiming) {
429*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
430*38e8c45fSAndroid Build Coastguard Worker     return scheduleLocked(token, scheduleTiming);
431*38e8c45fSAndroid Build Coastguard Worker }
432*38e8c45fSAndroid Build Coastguard Worker 
scheduleLocked(CallbackToken token,ScheduleTiming scheduleTiming)433*38e8c45fSAndroid Build Coastguard Worker std::optional<ScheduleResult> VSyncDispatchTimerQueue::scheduleLocked(
434*38e8c45fSAndroid Build Coastguard Worker         CallbackToken token, ScheduleTiming scheduleTiming) {
435*38e8c45fSAndroid Build Coastguard Worker     auto it = mCallbacks.find(token);
436*38e8c45fSAndroid Build Coastguard Worker     if (it == mCallbacks.end()) {
437*38e8c45fSAndroid Build Coastguard Worker         return {};
438*38e8c45fSAndroid Build Coastguard Worker     }
439*38e8c45fSAndroid Build Coastguard Worker     auto& callback = it->second;
440*38e8c45fSAndroid Build Coastguard Worker     auto const now = mTimeKeeper->now();
441*38e8c45fSAndroid Build Coastguard Worker 
442*38e8c45fSAndroid Build Coastguard Worker     /* If the timer thread will run soon, we'll apply this work update via the callback
443*38e8c45fSAndroid Build Coastguard Worker      * timer recalculation to avoid cancelling a callback that is about to fire. */
444*38e8c45fSAndroid Build Coastguard Worker     auto const rearmImminent = now > mIntendedWakeupTime;
445*38e8c45fSAndroid Build Coastguard Worker     if (CC_UNLIKELY(rearmImminent)) {
446*38e8c45fSAndroid Build Coastguard Worker         return callback->addPendingWorkloadUpdate(*mTracker, now, scheduleTiming);
447*38e8c45fSAndroid Build Coastguard Worker     }
448*38e8c45fSAndroid Build Coastguard Worker 
449*38e8c45fSAndroid Build Coastguard Worker     const auto result = callback->schedule(scheduleTiming, *mTracker, now);
450*38e8c45fSAndroid Build Coastguard Worker 
451*38e8c45fSAndroid Build Coastguard Worker     if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
452*38e8c45fSAndroid Build Coastguard Worker         rearmTimerSkippingUpdateFor(now, it);
453*38e8c45fSAndroid Build Coastguard Worker     }
454*38e8c45fSAndroid Build Coastguard Worker 
455*38e8c45fSAndroid Build Coastguard Worker     return result;
456*38e8c45fSAndroid Build Coastguard Worker }
457*38e8c45fSAndroid Build Coastguard Worker 
update(CallbackToken token,ScheduleTiming scheduleTiming)458*38e8c45fSAndroid Build Coastguard Worker std::optional<ScheduleResult> VSyncDispatchTimerQueue::update(CallbackToken token,
459*38e8c45fSAndroid Build Coastguard Worker                                                               ScheduleTiming scheduleTiming) {
460*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
461*38e8c45fSAndroid Build Coastguard Worker     const auto it = mCallbacks.find(token);
462*38e8c45fSAndroid Build Coastguard Worker     if (it == mCallbacks.end()) {
463*38e8c45fSAndroid Build Coastguard Worker         return {};
464*38e8c45fSAndroid Build Coastguard Worker     }
465*38e8c45fSAndroid Build Coastguard Worker 
466*38e8c45fSAndroid Build Coastguard Worker     auto& callback = it->second;
467*38e8c45fSAndroid Build Coastguard Worker     if (!callback->targetVsync().has_value()) {
468*38e8c45fSAndroid Build Coastguard Worker         return {};
469*38e8c45fSAndroid Build Coastguard Worker     }
470*38e8c45fSAndroid Build Coastguard Worker 
471*38e8c45fSAndroid Build Coastguard Worker     return scheduleLocked(token, scheduleTiming);
472*38e8c45fSAndroid Build Coastguard Worker }
473*38e8c45fSAndroid Build Coastguard Worker 
cancel(CallbackToken token)474*38e8c45fSAndroid Build Coastguard Worker CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
475*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
476*38e8c45fSAndroid Build Coastguard Worker 
477*38e8c45fSAndroid Build Coastguard Worker     auto it = mCallbacks.find(token);
478*38e8c45fSAndroid Build Coastguard Worker     if (it == mCallbacks.end()) {
479*38e8c45fSAndroid Build Coastguard Worker         return CancelResult::Error;
480*38e8c45fSAndroid Build Coastguard Worker     }
481*38e8c45fSAndroid Build Coastguard Worker     auto& callback = it->second;
482*38e8c45fSAndroid Build Coastguard Worker 
483*38e8c45fSAndroid Build Coastguard Worker     auto const wakeupTime = callback->wakeupTime();
484*38e8c45fSAndroid Build Coastguard Worker     if (wakeupTime) {
485*38e8c45fSAndroid Build Coastguard Worker         callback->disarm();
486*38e8c45fSAndroid Build Coastguard Worker 
487*38e8c45fSAndroid Build Coastguard Worker         if (*wakeupTime == mIntendedWakeupTime) {
488*38e8c45fSAndroid Build Coastguard Worker             mIntendedWakeupTime = kInvalidTime;
489*38e8c45fSAndroid Build Coastguard Worker             rearmTimer(mTimeKeeper->now());
490*38e8c45fSAndroid Build Coastguard Worker         }
491*38e8c45fSAndroid Build Coastguard Worker         return CancelResult::Cancelled;
492*38e8c45fSAndroid Build Coastguard Worker     }
493*38e8c45fSAndroid Build Coastguard Worker     return CancelResult::TooLate;
494*38e8c45fSAndroid Build Coastguard Worker }
495*38e8c45fSAndroid Build Coastguard Worker 
dump(std::string & result) const496*38e8c45fSAndroid Build Coastguard Worker void VSyncDispatchTimerQueue::dump(std::string& result) const {
497*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
498*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&result, "\tTimer:\n");
499*38e8c45fSAndroid Build Coastguard Worker     mTimeKeeper->dump(result);
500*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
501*38e8c45fSAndroid Build Coastguard Worker                   mMinVsyncDistance / 1e6f);
502*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
503*38e8c45fSAndroid Build Coastguard Worker                   (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
504*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
505*38e8c45fSAndroid Build Coastguard Worker                   (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
506*38e8c45fSAndroid Build Coastguard Worker                   (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
507*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&result, "\tCallbacks:\n");
508*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [token, entry] : mCallbacks) {
509*38e8c45fSAndroid Build Coastguard Worker         entry->dump(result);
510*38e8c45fSAndroid Build Coastguard Worker     }
511*38e8c45fSAndroid Build Coastguard Worker }
512*38e8c45fSAndroid Build Coastguard Worker 
VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,VSyncDispatch::Callback callback,std::string callbackName)513*38e8c45fSAndroid Build Coastguard Worker VSyncCallbackRegistration::VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,
514*38e8c45fSAndroid Build Coastguard Worker                                                      VSyncDispatch::Callback callback,
515*38e8c45fSAndroid Build Coastguard Worker                                                      std::string callbackName)
516*38e8c45fSAndroid Build Coastguard Worker       : mDispatch(std::move(dispatch)),
517*38e8c45fSAndroid Build Coastguard Worker         mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
518*38e8c45fSAndroid Build Coastguard Worker 
VSyncCallbackRegistration(VSyncCallbackRegistration && other)519*38e8c45fSAndroid Build Coastguard Worker VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
520*38e8c45fSAndroid Build Coastguard Worker       : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
521*38e8c45fSAndroid Build Coastguard Worker 
operator =(VSyncCallbackRegistration && other)522*38e8c45fSAndroid Build Coastguard Worker VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
523*38e8c45fSAndroid Build Coastguard Worker     if (this == &other) return *this;
524*38e8c45fSAndroid Build Coastguard Worker     if (mToken) {
525*38e8c45fSAndroid Build Coastguard Worker         mDispatch->unregisterCallback(*mToken);
526*38e8c45fSAndroid Build Coastguard Worker     }
527*38e8c45fSAndroid Build Coastguard Worker     mDispatch = std::move(other.mDispatch);
528*38e8c45fSAndroid Build Coastguard Worker     mToken = std::exchange(other.mToken, std::nullopt);
529*38e8c45fSAndroid Build Coastguard Worker     return *this;
530*38e8c45fSAndroid Build Coastguard Worker }
531*38e8c45fSAndroid Build Coastguard Worker 
~VSyncCallbackRegistration()532*38e8c45fSAndroid Build Coastguard Worker VSyncCallbackRegistration::~VSyncCallbackRegistration() {
533*38e8c45fSAndroid Build Coastguard Worker     if (mToken) mDispatch->unregisterCallback(*mToken);
534*38e8c45fSAndroid Build Coastguard Worker }
535*38e8c45fSAndroid Build Coastguard Worker 
schedule(VSyncDispatch::ScheduleTiming scheduleTiming)536*38e8c45fSAndroid Build Coastguard Worker std::optional<ScheduleResult> VSyncCallbackRegistration::schedule(
537*38e8c45fSAndroid Build Coastguard Worker         VSyncDispatch::ScheduleTiming scheduleTiming) {
538*38e8c45fSAndroid Build Coastguard Worker     if (!mToken) {
539*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
540*38e8c45fSAndroid Build Coastguard Worker     }
541*38e8c45fSAndroid Build Coastguard Worker     return mDispatch->schedule(*mToken, scheduleTiming);
542*38e8c45fSAndroid Build Coastguard Worker }
543*38e8c45fSAndroid Build Coastguard Worker 
update(VSyncDispatch::ScheduleTiming scheduleTiming)544*38e8c45fSAndroid Build Coastguard Worker std::optional<ScheduleResult> VSyncCallbackRegistration::update(
545*38e8c45fSAndroid Build Coastguard Worker         VSyncDispatch::ScheduleTiming scheduleTiming) {
546*38e8c45fSAndroid Build Coastguard Worker     if (!mToken) {
547*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
548*38e8c45fSAndroid Build Coastguard Worker     }
549*38e8c45fSAndroid Build Coastguard Worker     return mDispatch->update(*mToken, scheduleTiming);
550*38e8c45fSAndroid Build Coastguard Worker }
551*38e8c45fSAndroid Build Coastguard Worker 
cancel()552*38e8c45fSAndroid Build Coastguard Worker CancelResult VSyncCallbackRegistration::cancel() {
553*38e8c45fSAndroid Build Coastguard Worker     if (!mToken) {
554*38e8c45fSAndroid Build Coastguard Worker         return CancelResult::Error;
555*38e8c45fSAndroid Build Coastguard Worker     }
556*38e8c45fSAndroid Build Coastguard Worker     return mDispatch->cancel(*mToken);
557*38e8c45fSAndroid Build Coastguard Worker }
558*38e8c45fSAndroid Build Coastguard Worker 
559*38e8c45fSAndroid Build Coastguard Worker } // namespace android::scheduler
560