blob: 2a3e5b6381d1c5a745bd27af243697f0763fee2e [file] [log] [blame]
Kevin DuBois305bef12019-10-09 13:23:27 -07001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define ATRACE_TAG ATRACE_TAG_GRAPHICS
Dominik Laskowski62eff352021-12-06 09:59:41 -080018
Kevin DuBois305bef12019-10-09 13:23:27 -070019#include <vector>
20
Dominik Laskowski62eff352021-12-06 09:59:41 -080021#include <android-base/stringprintf.h>
22#include <ftl/concat.h>
23#include <utils/Trace.h>
Leon Scroggins III07738132023-04-24 11:43:53 -040024#include <log/log_main.h>
Dominik Laskowski62eff352021-12-06 09:59:41 -080025
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080026#include <scheduler/TimeKeeper.h>
27
Alec Mouri9b133ca2023-11-14 19:00:01 +000028#include <common/FlagManager.h>
Kevin DuBoise4f27a82019-11-12 11:41:41 -080029#include "VSyncDispatchTimerQueue.h"
Kevin DuBois305bef12019-10-09 13:23:27 -070030#include "VSyncTracker.h"
31
Leon Scroggins III07738132023-04-24 11:43:53 -040032#undef LOG_TAG
33#define LOG_TAG "VSyncDispatch"
34
Kevin DuBois305bef12019-10-09 13:23:27 -070035namespace android::scheduler {
Dominik Laskowski62eff352021-12-06 09:59:41 -080036
Ady Abraham5e7371c2020-03-24 14:47:24 -070037using base::StringAppendF;
Kevin DuBois305bef12019-10-09 13:23:27 -070038
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070039namespace {
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080040
ramindani32a88b12024-01-31 18:45:30 -080041ScheduleResult getExpectedCallbackTime(nsecs_t nextVsyncTime,
42 const VSyncDispatch::ScheduleTiming& timing) {
43 return {TimePoint::fromNs(nextVsyncTime - timing.readyDuration - timing.workDuration),
44 TimePoint::fromNs(nextVsyncTime)};
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070045}
46
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070047} // namespace
48
Kevin DuBoise4f27a82019-11-12 11:41:41 -080049VSyncDispatch::~VSyncDispatch() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070050VSyncTracker::~VSyncTracker() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070051
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080052VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
53 VSyncDispatch::Callback callback,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080054 nsecs_t minVsyncDistance)
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080055 : mName(std::move(name)),
56 mCallback(std::move(callback)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -080057 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -070058
Kevin DuBoise4f27a82019-11-12 11:41:41 -080059std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070060 return mLastDispatchTime;
61}
62
Kevin DuBoise4f27a82019-11-12 11:41:41 -080063std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070064 return mName;
65}
66
Kevin DuBoise4f27a82019-11-12 11:41:41 -080067std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070068 if (!mArmedInfo) {
69 return {};
70 }
71 return {mArmedInfo->mActualWakeupTime};
72}
73
Ady Abraham9c53ee72020-07-22 21:16:18 -070074std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
75 if (!mArmedInfo) {
76 return {};
77 }
78 return {mArmedInfo->mActualReadyTime};
79}
80
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080081std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
82 if (!mArmedInfo) {
83 return {};
84 }
85 return {mArmedInfo->mActualVsyncTime};
86}
87
ramindani32a88b12024-01-31 18:45:30 -080088std::optional<ScheduleResult> VSyncDispatchTimerQueueEntry::schedule(
89 VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker, nsecs_t now) {
Ady Abraham4335afd2023-12-18 19:10:47 -080090 auto nextVsyncTime =
91 tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
92 now + timing.workDuration +
93 timing.readyDuration),
94 timing.lastVsync);
Ady Abraham69b9e622021-07-19 12:24:31 -070095 auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -080096
97 bool const wouldSkipAVsyncTarget =
98 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
Ady Abraham69b9e622021-07-19 12:24:31 -070099 bool const wouldSkipAWakeup =
100 mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
Ady Abrahambf554892024-02-14 18:18:21 +0000101 if (FlagManager::getInstance().dont_skip_on_early_ro()) {
Ady Abraham529bd9f2023-10-05 14:55:30 -0700102 if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700103 nextVsyncTime = mArmedInfo->mActualVsyncTime;
104 } else {
105 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700106 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700107 nextWakeupTime = std::max(now, nextVsyncTime - timing.workDuration - timing.readyDuration);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700108 } else {
109 if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700110 return getExpectedCallbackTime(nextVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700111 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700112 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
113 nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800114 }
115
Ady Abraham9c53ee72020-07-22 21:16:18 -0700116 auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
117 mScheduleTiming = timing;
118 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
ramindani32a88b12024-01-31 18:45:30 -0800119 return ScheduleResult{TimePoint::fromNs(nextWakeupTime), TimePoint::fromNs(nextVsyncTime)};
Kevin DuBois305bef12019-10-09 13:23:27 -0700120}
121
ramindani32a88b12024-01-31 18:45:30 -0800122ScheduleResult VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000123 VSyncTracker& tracker, nsecs_t now, VSyncDispatch::ScheduleTiming timing) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700124 mWorkloadUpdateInfo = timing;
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000125 const auto armedInfo = update(tracker, now, timing, mArmedInfo);
ramindani32a88b12024-01-31 18:45:30 -0800126 return {TimePoint::fromNs(armedInfo.mActualWakeupTime),
127 TimePoint::fromNs(armedInfo.mActualVsyncTime)};
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700128}
129
130bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
131 return mWorkloadUpdateInfo.has_value();
132}
133
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700134nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
135 nsecs_t nextVsyncTime) const {
136 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
137 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
138 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
139 const nsecs_t currentPeriod = tracker.currentPeriod();
140 bool const nextVsyncTooClose = mLastDispatchTime &&
141 (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
142 if (alreadyDispatchedForVsync) {
Ady Abraham4335afd2023-12-18 19:10:47 -0800143 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance,
144 *mLastDispatchTime);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700145 }
146
147 if (nextVsyncTooClose) {
Ady Abraham4335afd2023-12-18 19:10:47 -0800148 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod,
149 *mLastDispatchTime + currentPeriod);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700150 }
151
152 return nextVsyncTime;
153}
154
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000155auto VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now,
156 VSyncDispatch::ScheduleTiming timing,
157 std::optional<ArmingInfo> armedInfo) const -> ArmingInfo {
158 const auto earliestReadyBy = now + timing.workDuration + timing.readyDuration;
159 const auto earliestVsync = std::max(earliestReadyBy, timing.lastVsync);
160
161 const auto nextVsyncTime =
162 adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
163 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync,
164 timing.lastVsync));
165 const auto nextReadyTime = nextVsyncTime - timing.readyDuration;
166 const auto nextWakeupTime = nextReadyTime - timing.workDuration;
167
168 bool const wouldSkipAVsyncTarget =
169 armedInfo && (nextVsyncTime > (armedInfo->mActualVsyncTime + mMinVsyncDistance));
170 bool const wouldSkipAWakeup =
171 armedInfo && (nextWakeupTime > (armedInfo->mActualWakeupTime + mMinVsyncDistance));
172 if (FlagManager::getInstance().dont_skip_on_early_ro() &&
173 (wouldSkipAVsyncTarget || wouldSkipAWakeup)) {
174 return *armedInfo;
175 }
176
177 return ArmingInfo{nextWakeupTime, nextVsyncTime, nextReadyTime};
178}
179
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800180void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700181 if (!mArmedInfo && !mWorkloadUpdateInfo) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700182 return;
183 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700184
185 if (mWorkloadUpdateInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700186 mScheduleTiming = *mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700187 mWorkloadUpdateInfo.reset();
188 }
189
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000190 mArmedInfo = update(tracker, now, mScheduleTiming, mArmedInfo);
Kevin DuBois305bef12019-10-09 13:23:27 -0700191}
192
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800193void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700194 mArmedInfo.reset();
195}
196
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800197nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700198 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
199 disarm();
200 return *mLastDispatchTime;
201}
202
Ady Abraham9c53ee72020-07-22 21:16:18 -0700203void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
204 nsecs_t deadlineTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700205 {
206 std::lock_guard<std::mutex> lk(mRunningMutex);
207 mRunning = true;
208 }
209
Ady Abraham9c53ee72020-07-22 21:16:18 -0700210 mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700211
212 std::lock_guard<std::mutex> lk(mRunningMutex);
213 mRunning = false;
214 mCv.notify_all();
215}
216
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800217void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700218 std::unique_lock<std::mutex> lk(mRunningMutex);
219 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
220}
221
Ady Abraham5e7371c2020-03-24 14:47:24 -0700222void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
223 std::lock_guard<std::mutex> lk(mRunningMutex);
224 std::string armedInfo;
225 if (mArmedInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700226 StringAppendF(&armedInfo,
227 "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
Ady Abraham5e7371c2020-03-24 14:47:24 -0700228 (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
Ady Abraham9c53ee72020-07-22 21:16:18 -0700229 (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
Ady Abraham5e7371c2020-03-24 14:47:24 -0700230 (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
231 }
232
233 StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
234 mRunning ? "(in callback function)" : "", armedInfo.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700235 StringAppendF(&result,
Ady Abraham4335afd2023-12-18 19:10:47 -0800236 "\t\t\tworkDuration: %.2fms readyDuration: %.2fms lastVsync: %.2fms relative "
Ady Abraham9c53ee72020-07-22 21:16:18 -0700237 "to now\n",
238 mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
Ady Abraham4335afd2023-12-18 19:10:47 -0800239 (mScheduleTiming.lastVsync - systemTime()) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700240
241 if (mLastDispatchTime) {
242 StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
243 (systemTime() - *mLastDispatchTime) / 1e6f);
244 } else {
245 StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
246 }
247}
248
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800249VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Leon Scroggins III67388622023-02-06 20:36:20 -0500250 VsyncSchedule::TrackerPtr tracker,
251 nsecs_t timerSlack, nsecs_t minVsyncDistance)
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800252 : mTimeKeeper(std::move(tk)),
Leon Scroggins III67388622023-02-06 20:36:20 -0500253 mTracker(std::move(tracker)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800254 mTimerSlack(timerSlack),
255 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700256
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800257VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700258 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800259 mRunning = false;
Kevin DuBois305bef12019-10-09 13:23:27 -0700260 cancelTimer();
Leon Scroggins III07738132023-04-24 11:43:53 -0400261 for (auto& [_, entry] : mCallbacks) {
262 ALOGE("Forgot to unregister a callback on VSyncDispatch!");
263 entry->ensureNotRunning();
264 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700265}
266
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800267void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700268 mIntendedWakeupTime = kInvalidTime;
269 mTimeKeeper->alarmCancel();
270}
271
Ady Abrahamb491c902020-08-15 15:47:56 -0700272void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700273 mIntendedWakeupTime = targetTime;
Ady Abrahamb491c902020-08-15 15:47:56 -0700274 mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
275 mIntendedWakeupTime);
Ady Abraham75398722020-04-07 14:08:45 -0700276 mLastTimerSchedule = mTimeKeeper->now();
Kevin DuBois305bef12019-10-09 13:23:27 -0700277}
278
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800279void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500280 rearmTimerSkippingUpdateFor(now, mCallbacks.cend());
Kevin DuBois305bef12019-10-09 13:23:27 -0700281}
282
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800283void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500284 nsecs_t now, CallbackMap::const_iterator skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700285 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800286 std::optional<nsecs_t> targetVsync;
287 std::optional<std::string_view> nextWakeupName;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500288 for (auto it = mCallbacks.cbegin(); it != mCallbacks.cend(); ++it) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700289 auto& callback = it->second;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700290 if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700291 continue;
292 }
293
294 if (it != skipUpdateIt) {
Leon Scroggins III67388622023-02-06 20:36:20 -0500295 callback->update(*mTracker, now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700296 }
297 auto const wakeupTime = *callback->wakeupTime();
Dominik Laskowski62eff352021-12-06 09:59:41 -0800298 if (!min || *min > wakeupTime) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800299 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700300 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800301 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700302 }
303 }
304
Dominik Laskowski62eff352021-12-06 09:59:41 -0800305 if (min && min < mIntendedWakeupTime) {
306 if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
307 ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
308 "us; VSYNC in ", ns2us(*targetVsync - now), "us");
309 ATRACE_NAME(trace.c_str());
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800310 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700311 setTimer(*min, now);
312 } else {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800313 ATRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700314 cancelTimer();
315 }
316}
317
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800318void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700319 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800320 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800321 nsecs_t vsyncTimestamp;
322 nsecs_t wakeupTimestamp;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700323 nsecs_t deadlineTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700324 };
325 std::vector<Invocation> invocations;
326 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700327 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800328 if (!mRunning) {
329 ALOGD("TimerQueue is not running. Skipping callback.");
330 return;
331 }
Kevin DuBoisf9477832020-07-16 10:21:36 -0700332 auto const now = mTimeKeeper->now();
333 mLastTimerCallback = now;
Kevin DuBois305bef12019-10-09 13:23:27 -0700334 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
335 auto& callback = it->second;
336 auto const wakeupTime = callback->wakeupTime();
337 if (!wakeupTime) {
338 continue;
339 }
340
Ady Abraham9c53ee72020-07-22 21:16:18 -0700341 auto const readyTime = callback->readyTime();
342
Kevin DuBoisf9477832020-07-16 10:21:36 -0700343 auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
344 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700345 callback->executing();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700346 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
347 *wakeupTime, *readyTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700348 }
349 }
350
351 mIntendedWakeupTime = kInvalidTime;
352 rearmTimer(mTimeKeeper->now());
353 }
354
355 for (auto const& invocation : invocations) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700356 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
357 invocation.deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700358 }
359}
360
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800361VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800362 Callback callback, std::string callbackName) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700363 std::lock_guard lock(mMutex);
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500364 return mCallbacks
Dominik Laskowski43baf902023-11-17 18:13:11 -0500365 .try_emplace(++mCallbackToken,
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500366 std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
367 std::move(callback),
368 mMinVsyncDistance))
369 .first->first;
Kevin DuBois305bef12019-10-09 13:23:27 -0700370}
371
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800372void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
373 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700374 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700375 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700376 auto it = mCallbacks.find(token);
377 if (it != mCallbacks.end()) {
378 entry = it->second;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500379 mCallbacks.erase(it->first);
Kevin DuBois305bef12019-10-09 13:23:27 -0700380 }
381 }
382
383 if (entry) {
384 entry->ensureNotRunning();
385 }
386}
387
ramindani32a88b12024-01-31 18:45:30 -0800388std::optional<ScheduleResult> VSyncDispatchTimerQueue::schedule(CallbackToken token,
389 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800390 std::lock_guard lock(mMutex);
391 return scheduleLocked(token, scheduleTiming);
392}
Kevin DuBois305bef12019-10-09 13:23:27 -0700393
ramindani32a88b12024-01-31 18:45:30 -0800394std::optional<ScheduleResult> VSyncDispatchTimerQueue::scheduleLocked(
395 CallbackToken token, ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800396 auto it = mCallbacks.find(token);
397 if (it == mCallbacks.end()) {
398 return {};
399 }
400 auto& callback = it->second;
401 auto const now = mTimeKeeper->now();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700402
Ady Abraham011f8ba2022-11-22 15:09:07 -0800403 /* If the timer thread will run soon, we'll apply this work update via the callback
404 * timer recalculation to avoid cancelling a callback that is about to fire. */
405 auto const rearmImminent = now > mIntendedWakeupTime;
406 if (CC_UNLIKELY(rearmImminent)) {
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000407 return callback->addPendingWorkloadUpdate(*mTracker, now, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800408 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700409
ramindani32a88b12024-01-31 18:45:30 -0800410 const auto resultOpt = callback->schedule(scheduleTiming, *mTracker, now);
411
412 if (!resultOpt) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800413 return {};
414 }
Ady Abraham011f8ba2022-11-22 15:09:07 -0800415 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
416 rearmTimerSkippingUpdateFor(now, it);
Kevin DuBois305bef12019-10-09 13:23:27 -0700417 }
418
ramindani32a88b12024-01-31 18:45:30 -0800419 return resultOpt;
Kevin DuBois305bef12019-10-09 13:23:27 -0700420}
421
ramindani32a88b12024-01-31 18:45:30 -0800422std::optional<ScheduleResult> VSyncDispatchTimerQueue::update(CallbackToken token,
423 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800424 std::lock_guard lock(mMutex);
425 const auto it = mCallbacks.find(token);
426 if (it == mCallbacks.end()) {
427 return {};
428 }
429
430 auto& callback = it->second;
431 if (!callback->targetVsync().has_value()) {
432 return {};
433 }
434
435 return scheduleLocked(token, scheduleTiming);
436}
437
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800438CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700439 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700440
441 auto it = mCallbacks.find(token);
442 if (it == mCallbacks.end()) {
443 return CancelResult::Error;
444 }
445 auto& callback = it->second;
446
Kevin DuBoisb340b732020-06-16 09:07:35 -0700447 auto const wakeupTime = callback->wakeupTime();
448 if (wakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700449 callback->disarm();
Kevin DuBoisb340b732020-06-16 09:07:35 -0700450
451 if (*wakeupTime == mIntendedWakeupTime) {
452 mIntendedWakeupTime = kInvalidTime;
453 rearmTimer(mTimeKeeper->now());
454 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700455 return CancelResult::Cancelled;
456 }
457 return CancelResult::TooLate;
458}
459
Ady Abraham5e7371c2020-03-24 14:47:24 -0700460void VSyncDispatchTimerQueue::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700461 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700462 StringAppendF(&result, "\tTimer:\n");
463 mTimeKeeper->dump(result);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700464 StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
465 mMinVsyncDistance / 1e6f);
466 StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
Ady Abraham75398722020-04-07 14:08:45 -0700467 (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
468 StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
469 (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
470 (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700471 StringAppendF(&result, "\tCallbacks:\n");
472 for (const auto& [token, entry] : mCallbacks) {
473 entry->dump(result);
474 }
475}
476
Leon Scroggins III67388622023-02-06 20:36:20 -0500477VSyncCallbackRegistration::VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800478 VSyncDispatch::Callback callback,
479 std::string callbackName)
Leon Scroggins III67388622023-02-06 20:36:20 -0500480 : mDispatch(std::move(dispatch)),
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400481 mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700482
483VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400484 : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700485
486VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400487 if (this == &other) return *this;
488 if (mToken) {
489 mDispatch->unregisterCallback(*mToken);
490 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700491 mDispatch = std::move(other.mDispatch);
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400492 mToken = std::exchange(other.mToken, std::nullopt);
Kevin DuBois305bef12019-10-09 13:23:27 -0700493 return *this;
494}
495
496VSyncCallbackRegistration::~VSyncCallbackRegistration() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400497 if (mToken) mDispatch->unregisterCallback(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700498}
499
ramindani32a88b12024-01-31 18:45:30 -0800500std::optional<ScheduleResult> VSyncCallbackRegistration::schedule(
501 VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400502 if (!mToken) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700503 return std::nullopt;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800504 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400505 return mDispatch->schedule(*mToken, scheduleTiming);
Kevin DuBois305bef12019-10-09 13:23:27 -0700506}
507
ramindani32a88b12024-01-31 18:45:30 -0800508std::optional<ScheduleResult> VSyncCallbackRegistration::update(
509 VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400510 if (!mToken) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800511 return std::nullopt;
512 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400513 return mDispatch->update(*mToken, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800514}
515
Kevin DuBois305bef12019-10-09 13:23:27 -0700516CancelResult VSyncCallbackRegistration::cancel() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400517 if (!mToken) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800518 return CancelResult::Error;
519 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400520 return mDispatch->cancel(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700521}
522
523} // namespace android::scheduler