blob: b92fa24670c988cf7a40c9bc4b64fb3f9cffcc5e [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
Ady Abrahamb0d3d982023-10-30 11:29:51 -070041nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070042 const VSyncDispatch::ScheduleTiming& timing) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -070043 return nextVsyncTime - timing.readyDuration - timing.workDuration;
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070044}
45
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070046} // namespace
47
Kevin DuBoise4f27a82019-11-12 11:41:41 -080048VSyncDispatch::~VSyncDispatch() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070049VSyncTracker::~VSyncTracker() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070050
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080051VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
52 VSyncDispatch::Callback callback,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080053 nsecs_t minVsyncDistance)
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080054 : mName(std::move(name)),
55 mCallback(std::move(callback)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -080056 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -070057
Kevin DuBoise4f27a82019-11-12 11:41:41 -080058std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070059 return mLastDispatchTime;
60}
61
Kevin DuBoise4f27a82019-11-12 11:41:41 -080062std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070063 return mName;
64}
65
Kevin DuBoise4f27a82019-11-12 11:41:41 -080066std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070067 if (!mArmedInfo) {
68 return {};
69 }
70 return {mArmedInfo->mActualWakeupTime};
71}
72
Ady Abraham9c53ee72020-07-22 21:16:18 -070073std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
74 if (!mArmedInfo) {
75 return {};
76 }
77 return {mArmedInfo->mActualReadyTime};
78}
79
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080080std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
81 if (!mArmedInfo) {
82 return {};
83 }
84 return {mArmedInfo->mActualVsyncTime};
85}
86
Ady Abraham9c53ee72020-07-22 21:16:18 -070087ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
Kevin DuBois2311b1a2019-11-18 16:19:08 -080088 VSyncTracker& tracker, nsecs_t now) {
Ady Abraham4335afd2023-12-18 19:10:47 -080089 auto nextVsyncTime =
90 tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
91 now + timing.workDuration +
92 timing.readyDuration),
93 timing.lastVsync);
Ady Abraham69b9e622021-07-19 12:24:31 -070094 auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -080095
96 bool const wouldSkipAVsyncTarget =
97 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
Ady Abraham69b9e622021-07-19 12:24:31 -070098 bool const wouldSkipAWakeup =
99 mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
Ady Abrahambf554892024-02-14 18:18:21 +0000100 if (FlagManager::getInstance().dont_skip_on_early_ro()) {
Ady Abraham529bd9f2023-10-05 14:55:30 -0700101 if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700102 nextVsyncTime = mArmedInfo->mActualVsyncTime;
103 } else {
104 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700105 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700106 nextWakeupTime = std::max(now, nextVsyncTime - timing.workDuration - timing.readyDuration);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700107 } else {
108 if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700109 return getExpectedCallbackTime(nextVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700110 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700111 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
112 nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800113 }
114
Ady Abraham9c53ee72020-07-22 21:16:18 -0700115 auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
116 mScheduleTiming = timing;
117 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700118 return nextWakeupTime;
Kevin DuBois305bef12019-10-09 13:23:27 -0700119}
120
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000121nsecs_t VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
122 VSyncTracker& tracker, nsecs_t now, VSyncDispatch::ScheduleTiming timing) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700123 mWorkloadUpdateInfo = timing;
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000124 const auto armedInfo = update(tracker, now, timing, mArmedInfo);
125 return armedInfo.mActualWakeupTime;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700126}
127
128bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
129 return mWorkloadUpdateInfo.has_value();
130}
131
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700132nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
133 nsecs_t nextVsyncTime) const {
134 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
135 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
136 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
137 const nsecs_t currentPeriod = tracker.currentPeriod();
138 bool const nextVsyncTooClose = mLastDispatchTime &&
139 (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
140 if (alreadyDispatchedForVsync) {
Ady Abraham4335afd2023-12-18 19:10:47 -0800141 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance,
142 *mLastDispatchTime);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700143 }
144
145 if (nextVsyncTooClose) {
Ady Abraham4335afd2023-12-18 19:10:47 -0800146 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod,
147 *mLastDispatchTime + currentPeriod);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700148 }
149
150 return nextVsyncTime;
151}
152
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000153auto VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now,
154 VSyncDispatch::ScheduleTiming timing,
155 std::optional<ArmingInfo> armedInfo) const -> ArmingInfo {
156 const auto earliestReadyBy = now + timing.workDuration + timing.readyDuration;
157 const auto earliestVsync = std::max(earliestReadyBy, timing.lastVsync);
158
159 const auto nextVsyncTime =
160 adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
161 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync,
162 timing.lastVsync));
163 const auto nextReadyTime = nextVsyncTime - timing.readyDuration;
164 const auto nextWakeupTime = nextReadyTime - timing.workDuration;
165
166 bool const wouldSkipAVsyncTarget =
167 armedInfo && (nextVsyncTime > (armedInfo->mActualVsyncTime + mMinVsyncDistance));
168 bool const wouldSkipAWakeup =
169 armedInfo && (nextWakeupTime > (armedInfo->mActualWakeupTime + mMinVsyncDistance));
170 if (FlagManager::getInstance().dont_skip_on_early_ro() &&
171 (wouldSkipAVsyncTarget || wouldSkipAWakeup)) {
172 return *armedInfo;
173 }
174
175 return ArmingInfo{nextWakeupTime, nextVsyncTime, nextReadyTime};
176}
177
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800178void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700179 if (!mArmedInfo && !mWorkloadUpdateInfo) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700180 return;
181 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700182
183 if (mWorkloadUpdateInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700184 mScheduleTiming = *mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700185 mWorkloadUpdateInfo.reset();
186 }
187
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000188 mArmedInfo = update(tracker, now, mScheduleTiming, mArmedInfo);
Kevin DuBois305bef12019-10-09 13:23:27 -0700189}
190
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800191void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700192 mArmedInfo.reset();
193}
194
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800195nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700196 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
197 disarm();
198 return *mLastDispatchTime;
199}
200
Ady Abraham9c53ee72020-07-22 21:16:18 -0700201void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
202 nsecs_t deadlineTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700203 {
204 std::lock_guard<std::mutex> lk(mRunningMutex);
205 mRunning = true;
206 }
207
Ady Abraham9c53ee72020-07-22 21:16:18 -0700208 mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700209
210 std::lock_guard<std::mutex> lk(mRunningMutex);
211 mRunning = false;
212 mCv.notify_all();
213}
214
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800215void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700216 std::unique_lock<std::mutex> lk(mRunningMutex);
217 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
218}
219
Ady Abraham5e7371c2020-03-24 14:47:24 -0700220void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
221 std::lock_guard<std::mutex> lk(mRunningMutex);
222 std::string armedInfo;
223 if (mArmedInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700224 StringAppendF(&armedInfo,
225 "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
Ady Abraham5e7371c2020-03-24 14:47:24 -0700226 (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
Ady Abraham9c53ee72020-07-22 21:16:18 -0700227 (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
Ady Abraham5e7371c2020-03-24 14:47:24 -0700228 (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
229 }
230
231 StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
232 mRunning ? "(in callback function)" : "", armedInfo.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700233 StringAppendF(&result,
Ady Abraham4335afd2023-12-18 19:10:47 -0800234 "\t\t\tworkDuration: %.2fms readyDuration: %.2fms lastVsync: %.2fms relative "
Ady Abraham9c53ee72020-07-22 21:16:18 -0700235 "to now\n",
236 mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
Ady Abraham4335afd2023-12-18 19:10:47 -0800237 (mScheduleTiming.lastVsync - systemTime()) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700238
239 if (mLastDispatchTime) {
240 StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
241 (systemTime() - *mLastDispatchTime) / 1e6f);
242 } else {
243 StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
244 }
245}
246
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800247VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Leon Scroggins III67388622023-02-06 20:36:20 -0500248 VsyncSchedule::TrackerPtr tracker,
249 nsecs_t timerSlack, nsecs_t minVsyncDistance)
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800250 : mTimeKeeper(std::move(tk)),
Leon Scroggins III67388622023-02-06 20:36:20 -0500251 mTracker(std::move(tracker)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800252 mTimerSlack(timerSlack),
253 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700254
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800255VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700256 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800257 mRunning = false;
Kevin DuBois305bef12019-10-09 13:23:27 -0700258 cancelTimer();
Leon Scroggins III07738132023-04-24 11:43:53 -0400259 for (auto& [_, entry] : mCallbacks) {
260 ALOGE("Forgot to unregister a callback on VSyncDispatch!");
261 entry->ensureNotRunning();
262 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700263}
264
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800265void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700266 mIntendedWakeupTime = kInvalidTime;
267 mTimeKeeper->alarmCancel();
268}
269
Ady Abrahamb491c902020-08-15 15:47:56 -0700270void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700271 mIntendedWakeupTime = targetTime;
Ady Abrahamb491c902020-08-15 15:47:56 -0700272 mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
273 mIntendedWakeupTime);
Ady Abraham75398722020-04-07 14:08:45 -0700274 mLastTimerSchedule = mTimeKeeper->now();
Kevin DuBois305bef12019-10-09 13:23:27 -0700275}
276
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800277void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500278 rearmTimerSkippingUpdateFor(now, mCallbacks.cend());
Kevin DuBois305bef12019-10-09 13:23:27 -0700279}
280
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800281void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500282 nsecs_t now, CallbackMap::const_iterator skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700283 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800284 std::optional<nsecs_t> targetVsync;
285 std::optional<std::string_view> nextWakeupName;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500286 for (auto it = mCallbacks.cbegin(); it != mCallbacks.cend(); ++it) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700287 auto& callback = it->second;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700288 if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700289 continue;
290 }
291
292 if (it != skipUpdateIt) {
Leon Scroggins III67388622023-02-06 20:36:20 -0500293 callback->update(*mTracker, now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700294 }
295 auto const wakeupTime = *callback->wakeupTime();
Dominik Laskowski62eff352021-12-06 09:59:41 -0800296 if (!min || *min > wakeupTime) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800297 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700298 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800299 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700300 }
301 }
302
Dominik Laskowski62eff352021-12-06 09:59:41 -0800303 if (min && min < mIntendedWakeupTime) {
304 if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
305 ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
306 "us; VSYNC in ", ns2us(*targetVsync - now), "us");
307 ATRACE_NAME(trace.c_str());
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800308 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700309 setTimer(*min, now);
310 } else {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800311 ATRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700312 cancelTimer();
313 }
314}
315
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800316void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700317 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800318 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800319 nsecs_t vsyncTimestamp;
320 nsecs_t wakeupTimestamp;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700321 nsecs_t deadlineTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700322 };
323 std::vector<Invocation> invocations;
324 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700325 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800326 if (!mRunning) {
327 ALOGD("TimerQueue is not running. Skipping callback.");
328 return;
329 }
Kevin DuBoisf9477832020-07-16 10:21:36 -0700330 auto const now = mTimeKeeper->now();
331 mLastTimerCallback = now;
Kevin DuBois305bef12019-10-09 13:23:27 -0700332 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
333 auto& callback = it->second;
334 auto const wakeupTime = callback->wakeupTime();
335 if (!wakeupTime) {
336 continue;
337 }
338
Ady Abraham9c53ee72020-07-22 21:16:18 -0700339 auto const readyTime = callback->readyTime();
340
Kevin DuBoisf9477832020-07-16 10:21:36 -0700341 auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
342 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700343 callback->executing();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700344 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
345 *wakeupTime, *readyTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700346 }
347 }
348
349 mIntendedWakeupTime = kInvalidTime;
350 rearmTimer(mTimeKeeper->now());
351 }
352
353 for (auto const& invocation : invocations) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700354 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
355 invocation.deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700356 }
357}
358
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800359VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800360 Callback callback, std::string callbackName) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700361 std::lock_guard lock(mMutex);
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500362 return mCallbacks
Dominik Laskowski43baf902023-11-17 18:13:11 -0500363 .try_emplace(++mCallbackToken,
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500364 std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
365 std::move(callback),
366 mMinVsyncDistance))
367 .first->first;
Kevin DuBois305bef12019-10-09 13:23:27 -0700368}
369
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800370void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
371 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700372 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700373 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700374 auto it = mCallbacks.find(token);
375 if (it != mCallbacks.end()) {
376 entry = it->second;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500377 mCallbacks.erase(it->first);
Kevin DuBois305bef12019-10-09 13:23:27 -0700378 }
379 }
380
381 if (entry) {
382 entry->ensureNotRunning();
383 }
384}
385
Ady Abraham9c53ee72020-07-22 21:16:18 -0700386ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
387 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800388 std::lock_guard lock(mMutex);
389 return scheduleLocked(token, scheduleTiming);
390}
Kevin DuBois305bef12019-10-09 13:23:27 -0700391
Ady Abraham011f8ba2022-11-22 15:09:07 -0800392ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
393 ScheduleTiming scheduleTiming) {
394 auto it = mCallbacks.find(token);
395 if (it == mCallbacks.end()) {
396 return {};
397 }
398 auto& callback = it->second;
399 auto const now = mTimeKeeper->now();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700400
Ady Abraham011f8ba2022-11-22 15:09:07 -0800401 /* If the timer thread will run soon, we'll apply this work update via the callback
402 * timer recalculation to avoid cancelling a callback that is about to fire. */
403 auto const rearmImminent = now > mIntendedWakeupTime;
404 if (CC_UNLIKELY(rearmImminent)) {
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000405 return callback->addPendingWorkloadUpdate(*mTracker, now, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800406 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700407
Leon Scroggins III67388622023-02-06 20:36:20 -0500408 const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800409 if (!result.has_value()) {
410 return {};
411 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700412
Ady Abraham011f8ba2022-11-22 15:09:07 -0800413 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
414 rearmTimerSkippingUpdateFor(now, it);
Kevin DuBois305bef12019-10-09 13:23:27 -0700415 }
416
417 return result;
418}
419
Ady Abraham011f8ba2022-11-22 15:09:07 -0800420ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
421 std::lock_guard lock(mMutex);
422 const auto it = mCallbacks.find(token);
423 if (it == mCallbacks.end()) {
424 return {};
425 }
426
427 auto& callback = it->second;
428 if (!callback->targetVsync().has_value()) {
429 return {};
430 }
431
432 return scheduleLocked(token, scheduleTiming);
433}
434
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800435CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700436 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700437
438 auto it = mCallbacks.find(token);
439 if (it == mCallbacks.end()) {
440 return CancelResult::Error;
441 }
442 auto& callback = it->second;
443
Kevin DuBoisb340b732020-06-16 09:07:35 -0700444 auto const wakeupTime = callback->wakeupTime();
445 if (wakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700446 callback->disarm();
Kevin DuBoisb340b732020-06-16 09:07:35 -0700447
448 if (*wakeupTime == mIntendedWakeupTime) {
449 mIntendedWakeupTime = kInvalidTime;
450 rearmTimer(mTimeKeeper->now());
451 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700452 return CancelResult::Cancelled;
453 }
454 return CancelResult::TooLate;
455}
456
Ady Abraham5e7371c2020-03-24 14:47:24 -0700457void VSyncDispatchTimerQueue::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700458 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700459 StringAppendF(&result, "\tTimer:\n");
460 mTimeKeeper->dump(result);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700461 StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
462 mMinVsyncDistance / 1e6f);
463 StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
Ady Abraham75398722020-04-07 14:08:45 -0700464 (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
465 StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
466 (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
467 (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700468 StringAppendF(&result, "\tCallbacks:\n");
469 for (const auto& [token, entry] : mCallbacks) {
470 entry->dump(result);
471 }
472}
473
Leon Scroggins III67388622023-02-06 20:36:20 -0500474VSyncCallbackRegistration::VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800475 VSyncDispatch::Callback callback,
476 std::string callbackName)
Leon Scroggins III67388622023-02-06 20:36:20 -0500477 : mDispatch(std::move(dispatch)),
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400478 mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700479
480VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400481 : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700482
483VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400484 if (this == &other) return *this;
485 if (mToken) {
486 mDispatch->unregisterCallback(*mToken);
487 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700488 mDispatch = std::move(other.mDispatch);
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400489 mToken = std::exchange(other.mToken, std::nullopt);
Kevin DuBois305bef12019-10-09 13:23:27 -0700490 return *this;
491}
492
493VSyncCallbackRegistration::~VSyncCallbackRegistration() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400494 if (mToken) mDispatch->unregisterCallback(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700495}
496
Ady Abraham9c53ee72020-07-22 21:16:18 -0700497ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400498 if (!mToken) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700499 return std::nullopt;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800500 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400501 return mDispatch->schedule(*mToken, scheduleTiming);
Kevin DuBois305bef12019-10-09 13:23:27 -0700502}
503
Ady Abraham011f8ba2022-11-22 15:09:07 -0800504ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400505 if (!mToken) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800506 return std::nullopt;
507 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400508 return mDispatch->update(*mToken, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800509}
510
Kevin DuBois305bef12019-10-09 13:23:27 -0700511CancelResult VSyncCallbackRegistration::cancel() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400512 if (!mToken) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800513 return CancelResult::Error;
514 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400515 return mDispatch->cancel(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700516}
517
518} // namespace android::scheduler