blob: 186a6bc9d6d674688d46d17db4124c6744a73b1a [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
Ady Abrahamd6d80162023-10-23 12:57:41 -070028#include "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 Abraham3e019972023-10-20 13:23:48 -070041nsecs_t getExpectedCallbackTime(nsecs_t now, nsecs_t nextVsyncTime,
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070042 const VSyncDispatch::ScheduleTiming& timing) {
Ady Abraham3e019972023-10-20 13:23:48 -070043 const auto expectedCallbackTime = nextVsyncTime - timing.readyDuration - timing.workDuration;
Ady Abrahamd6d80162023-10-23 12:57:41 -070044 const auto baseTime =
45 FlagManager::getInstance().dont_skip_on_early() ? now : expectedCallbackTime;
Ady Abraham3e019972023-10-20 13:23:48 -070046 return std::max(baseTime, expectedCallbackTime);
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070047}
48
49nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now,
50 const VSyncDispatch::ScheduleTiming& timing) {
51 const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
52 std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
Ady Abraham3e019972023-10-20 13:23:48 -070053 return getExpectedCallbackTime(now, nextVsyncTime, timing);
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070054}
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080055
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070056} // namespace
57
Kevin DuBoise4f27a82019-11-12 11:41:41 -080058VSyncDispatch::~VSyncDispatch() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070059VSyncTracker::~VSyncTracker() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070060
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080061VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
62 VSyncDispatch::Callback callback,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080063 nsecs_t minVsyncDistance)
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080064 : mName(std::move(name)),
65 mCallback(std::move(callback)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -080066 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -070067
Kevin DuBoise4f27a82019-11-12 11:41:41 -080068std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070069 return mLastDispatchTime;
70}
71
Kevin DuBoise4f27a82019-11-12 11:41:41 -080072std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070073 return mName;
74}
75
Kevin DuBoise4f27a82019-11-12 11:41:41 -080076std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070077 if (!mArmedInfo) {
78 return {};
79 }
80 return {mArmedInfo->mActualWakeupTime};
81}
82
Ady Abraham9c53ee72020-07-22 21:16:18 -070083std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
84 if (!mArmedInfo) {
85 return {};
86 }
87 return {mArmedInfo->mActualReadyTime};
88}
89
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080090std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
91 if (!mArmedInfo) {
92 return {};
93 }
94 return {mArmedInfo->mActualVsyncTime};
95}
96
Ady Abraham9c53ee72020-07-22 21:16:18 -070097ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
Kevin DuBois2311b1a2019-11-18 16:19:08 -080098 VSyncTracker& tracker, nsecs_t now) {
Ady Abraham9c53ee72020-07-22 21:16:18 -070099 auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
100 std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
Ady Abraham69b9e622021-07-19 12:24:31 -0700101 auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800102
103 bool const wouldSkipAVsyncTarget =
104 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
Ady Abraham69b9e622021-07-19 12:24:31 -0700105 bool const wouldSkipAWakeup =
106 mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
Ady Abrahamd6d80162023-10-23 12:57:41 -0700107 if (FlagManager::getInstance().dont_skip_on_early()) {
Ady Abraham529bd9f2023-10-05 14:55:30 -0700108 if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
Ady Abraham3e019972023-10-20 13:23:48 -0700109 return getExpectedCallbackTime(now, mArmedInfo->mActualVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700110 }
111 } else {
112 if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
Ady Abraham3e019972023-10-20 13:23:48 -0700113 return getExpectedCallbackTime(now, nextVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700114 }
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800115 }
116
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700117 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
118 nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800119
Ady Abraham9c53ee72020-07-22 21:16:18 -0700120 auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
121 mScheduleTiming = timing;
122 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Ady Abraham3e019972023-10-20 13:23:48 -0700123 return getExpectedCallbackTime(now, nextVsyncTime, timing);
Kevin DuBois305bef12019-10-09 13:23:27 -0700124}
125
Ady Abraham9c53ee72020-07-22 21:16:18 -0700126void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
127 mWorkloadUpdateInfo = timing;
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) {
143 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
144 }
145
146 if (nextVsyncTooClose) {
147 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod);
148 }
149
150 return nextVsyncTime;
151}
152
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800153void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700154 if (!mArmedInfo && !mWorkloadUpdateInfo) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700155 return;
156 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700157
158 if (mWorkloadUpdateInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700159 mScheduleTiming = *mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700160 mWorkloadUpdateInfo.reset();
161 }
162
Ady Abraham9c53ee72020-07-22 21:16:18 -0700163 const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
164 const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync);
165
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700166 const auto nextVsyncTime =
167 adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
168 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync));
Ady Abraham9c53ee72020-07-22 21:16:18 -0700169 const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
170 const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
171
172 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Kevin DuBois305bef12019-10-09 13:23:27 -0700173}
174
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800175void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700176 mArmedInfo.reset();
177}
178
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800179nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700180 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
181 disarm();
182 return *mLastDispatchTime;
183}
184
Ady Abraham9c53ee72020-07-22 21:16:18 -0700185void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
186 nsecs_t deadlineTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700187 {
188 std::lock_guard<std::mutex> lk(mRunningMutex);
189 mRunning = true;
190 }
191
Ady Abraham9c53ee72020-07-22 21:16:18 -0700192 mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700193
194 std::lock_guard<std::mutex> lk(mRunningMutex);
195 mRunning = false;
196 mCv.notify_all();
197}
198
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800199void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700200 std::unique_lock<std::mutex> lk(mRunningMutex);
201 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
202}
203
Ady Abraham5e7371c2020-03-24 14:47:24 -0700204void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
205 std::lock_guard<std::mutex> lk(mRunningMutex);
206 std::string armedInfo;
207 if (mArmedInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700208 StringAppendF(&armedInfo,
209 "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
Ady Abraham5e7371c2020-03-24 14:47:24 -0700210 (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
Ady Abraham9c53ee72020-07-22 21:16:18 -0700211 (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
Ady Abraham5e7371c2020-03-24 14:47:24 -0700212 (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
213 }
214
215 StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
216 mRunning ? "(in callback function)" : "", armedInfo.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700217 StringAppendF(&result,
218 "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative "
219 "to now\n",
220 mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
221 (mScheduleTiming.earliestVsync - systemTime()) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700222
223 if (mLastDispatchTime) {
224 StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
225 (systemTime() - *mLastDispatchTime) / 1e6f);
226 } else {
227 StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
228 }
229}
230
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800231VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Leon Scroggins III67388622023-02-06 20:36:20 -0500232 VsyncSchedule::TrackerPtr tracker,
233 nsecs_t timerSlack, nsecs_t minVsyncDistance)
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800234 : mTimeKeeper(std::move(tk)),
Leon Scroggins III67388622023-02-06 20:36:20 -0500235 mTracker(std::move(tracker)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800236 mTimerSlack(timerSlack),
237 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700238
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800239VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700240 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700241 cancelTimer();
Leon Scroggins III07738132023-04-24 11:43:53 -0400242 for (auto& [_, entry] : mCallbacks) {
243 ALOGE("Forgot to unregister a callback on VSyncDispatch!");
244 entry->ensureNotRunning();
245 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700246}
247
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800248void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700249 mIntendedWakeupTime = kInvalidTime;
250 mTimeKeeper->alarmCancel();
251}
252
Ady Abrahamb491c902020-08-15 15:47:56 -0700253void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700254 mIntendedWakeupTime = targetTime;
Ady Abrahamb491c902020-08-15 15:47:56 -0700255 mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
256 mIntendedWakeupTime);
Ady Abraham75398722020-04-07 14:08:45 -0700257 mLastTimerSchedule = mTimeKeeper->now();
Kevin DuBois305bef12019-10-09 13:23:27 -0700258}
259
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800260void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700261 rearmTimerSkippingUpdateFor(now, mCallbacks.end());
262}
263
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800264void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
265 nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700266 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800267 std::optional<nsecs_t> targetVsync;
268 std::optional<std::string_view> nextWakeupName;
Kevin DuBois305bef12019-10-09 13:23:27 -0700269 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
270 auto& callback = it->second;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700271 if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700272 continue;
273 }
274
275 if (it != skipUpdateIt) {
Leon Scroggins III67388622023-02-06 20:36:20 -0500276 callback->update(*mTracker, now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700277 }
278 auto const wakeupTime = *callback->wakeupTime();
Dominik Laskowski62eff352021-12-06 09:59:41 -0800279 if (!min || *min > wakeupTime) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800280 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700281 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800282 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700283 }
284 }
285
Dominik Laskowski62eff352021-12-06 09:59:41 -0800286 if (min && min < mIntendedWakeupTime) {
287 if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
288 ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
289 "us; VSYNC in ", ns2us(*targetVsync - now), "us");
290 ATRACE_NAME(trace.c_str());
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800291 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700292 setTimer(*min, now);
293 } else {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800294 ATRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700295 cancelTimer();
296 }
297}
298
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800299void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700300 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800301 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800302 nsecs_t vsyncTimestamp;
303 nsecs_t wakeupTimestamp;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700304 nsecs_t deadlineTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700305 };
306 std::vector<Invocation> invocations;
307 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700308 std::lock_guard lock(mMutex);
Kevin DuBoisf9477832020-07-16 10:21:36 -0700309 auto const now = mTimeKeeper->now();
310 mLastTimerCallback = now;
Kevin DuBois305bef12019-10-09 13:23:27 -0700311 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
312 auto& callback = it->second;
313 auto const wakeupTime = callback->wakeupTime();
314 if (!wakeupTime) {
315 continue;
316 }
317
Ady Abraham9c53ee72020-07-22 21:16:18 -0700318 auto const readyTime = callback->readyTime();
319
Kevin DuBoisf9477832020-07-16 10:21:36 -0700320 auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
321 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700322 callback->executing();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700323 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
324 *wakeupTime, *readyTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700325 }
326 }
327
328 mIntendedWakeupTime = kInvalidTime;
329 rearmTimer(mTimeKeeper->now());
330 }
331
332 for (auto const& invocation : invocations) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700333 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
334 invocation.deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700335 }
336}
337
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800338VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800339 Callback callback, std::string callbackName) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700340 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700341 return CallbackToken{
342 mCallbacks
343 .emplace(++mCallbackToken,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800344 std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
345 std::move(callback),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800346 mMinVsyncDistance))
Kevin DuBois305bef12019-10-09 13:23:27 -0700347 .first->first};
348}
349
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800350void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
351 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700352 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700353 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700354 auto it = mCallbacks.find(token);
355 if (it != mCallbacks.end()) {
356 entry = it->second;
357 mCallbacks.erase(it);
358 }
359 }
360
361 if (entry) {
362 entry->ensureNotRunning();
363 }
364}
365
Ady Abraham9c53ee72020-07-22 21:16:18 -0700366ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
367 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800368 std::lock_guard lock(mMutex);
369 return scheduleLocked(token, scheduleTiming);
370}
Kevin DuBois305bef12019-10-09 13:23:27 -0700371
Ady Abraham011f8ba2022-11-22 15:09:07 -0800372ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
373 ScheduleTiming scheduleTiming) {
374 auto it = mCallbacks.find(token);
375 if (it == mCallbacks.end()) {
376 return {};
377 }
378 auto& callback = it->second;
379 auto const now = mTimeKeeper->now();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700380
Ady Abraham011f8ba2022-11-22 15:09:07 -0800381 /* If the timer thread will run soon, we'll apply this work update via the callback
382 * timer recalculation to avoid cancelling a callback that is about to fire. */
383 auto const rearmImminent = now > mIntendedWakeupTime;
384 if (CC_UNLIKELY(rearmImminent)) {
385 callback->addPendingWorkloadUpdate(scheduleTiming);
Leon Scroggins III67388622023-02-06 20:36:20 -0500386 return getExpectedCallbackTime(*mTracker, now, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800387 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700388
Leon Scroggins III67388622023-02-06 20:36:20 -0500389 const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800390 if (!result.has_value()) {
391 return {};
392 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700393
Ady Abraham011f8ba2022-11-22 15:09:07 -0800394 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
395 rearmTimerSkippingUpdateFor(now, it);
Kevin DuBois305bef12019-10-09 13:23:27 -0700396 }
397
398 return result;
399}
400
Ady Abraham011f8ba2022-11-22 15:09:07 -0800401ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
402 std::lock_guard lock(mMutex);
403 const auto it = mCallbacks.find(token);
404 if (it == mCallbacks.end()) {
405 return {};
406 }
407
408 auto& callback = it->second;
409 if (!callback->targetVsync().has_value()) {
410 return {};
411 }
412
413 return scheduleLocked(token, scheduleTiming);
414}
415
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800416CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700417 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700418
419 auto it = mCallbacks.find(token);
420 if (it == mCallbacks.end()) {
421 return CancelResult::Error;
422 }
423 auto& callback = it->second;
424
Kevin DuBoisb340b732020-06-16 09:07:35 -0700425 auto const wakeupTime = callback->wakeupTime();
426 if (wakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700427 callback->disarm();
Kevin DuBoisb340b732020-06-16 09:07:35 -0700428
429 if (*wakeupTime == mIntendedWakeupTime) {
430 mIntendedWakeupTime = kInvalidTime;
431 rearmTimer(mTimeKeeper->now());
432 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700433 return CancelResult::Cancelled;
434 }
435 return CancelResult::TooLate;
436}
437
Ady Abraham5e7371c2020-03-24 14:47:24 -0700438void VSyncDispatchTimerQueue::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700439 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700440 StringAppendF(&result, "\tTimer:\n");
441 mTimeKeeper->dump(result);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700442 StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
443 mMinVsyncDistance / 1e6f);
444 StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
Ady Abraham75398722020-04-07 14:08:45 -0700445 (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
446 StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
447 (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
448 (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700449 StringAppendF(&result, "\tCallbacks:\n");
450 for (const auto& [token, entry] : mCallbacks) {
451 entry->dump(result);
452 }
453}
454
Leon Scroggins III67388622023-02-06 20:36:20 -0500455VSyncCallbackRegistration::VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800456 VSyncDispatch::Callback callback,
457 std::string callbackName)
Leon Scroggins III67388622023-02-06 20:36:20 -0500458 : mDispatch(std::move(dispatch)),
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400459 mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700460
461VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400462 : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700463
464VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400465 if (this == &other) return *this;
466 if (mToken) {
467 mDispatch->unregisterCallback(*mToken);
468 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700469 mDispatch = std::move(other.mDispatch);
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400470 mToken = std::exchange(other.mToken, std::nullopt);
Kevin DuBois305bef12019-10-09 13:23:27 -0700471 return *this;
472}
473
474VSyncCallbackRegistration::~VSyncCallbackRegistration() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400475 if (mToken) mDispatch->unregisterCallback(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700476}
477
Ady Abraham9c53ee72020-07-22 21:16:18 -0700478ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400479 if (!mToken) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700480 return std::nullopt;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800481 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400482 return mDispatch->schedule(*mToken, scheduleTiming);
Kevin DuBois305bef12019-10-09 13:23:27 -0700483}
484
Ady Abraham011f8ba2022-11-22 15:09:07 -0800485ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400486 if (!mToken) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800487 return std::nullopt;
488 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400489 return mDispatch->update(*mToken, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800490}
491
Kevin DuBois305bef12019-10-09 13:23:27 -0700492CancelResult VSyncCallbackRegistration::cancel() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400493 if (!mToken) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800494 return CancelResult::Error;
495 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400496 return mDispatch->cancel(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700497}
498
499} // namespace android::scheduler