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