blob: f4676706fd368c221207668b7e5e19bc7493d3a2 [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
Kevin DuBoise4f27a82019-11-12 11:41:41 -080028#include "VSyncDispatchTimerQueue.h"
Kevin DuBois305bef12019-10-09 13:23:27 -070029#include "VSyncTracker.h"
30
Ady Abraham529bd9f2023-10-05 14:55:30 -070031#include <com_android_graphics_surfaceflinger_flags.h>
32
Leon Scroggins III07738132023-04-24 11:43:53 -040033#undef LOG_TAG
34#define LOG_TAG "VSyncDispatch"
35
Kevin DuBois305bef12019-10-09 13:23:27 -070036namespace android::scheduler {
Ady Abraham529bd9f2023-10-05 14:55:30 -070037using namespace com::android::graphics::surfaceflinger;
Dominik Laskowski62eff352021-12-06 09:59:41 -080038
Ady Abraham5e7371c2020-03-24 14:47:24 -070039using base::StringAppendF;
Kevin DuBois305bef12019-10-09 13:23:27 -070040
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070041namespace {
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080042
Ady Abraham3e019972023-10-20 13:23:48 -070043nsecs_t getExpectedCallbackTime(nsecs_t now, nsecs_t nextVsyncTime,
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070044 const VSyncDispatch::ScheduleTiming& timing) {
Ady Abraham3e019972023-10-20 13:23:48 -070045 const auto expectedCallbackTime = nextVsyncTime - timing.readyDuration - timing.workDuration;
46 const auto baseTime = flags::dont_skip_on_early() ? now : expectedCallbackTime;
47 return std::max(baseTime, expectedCallbackTime);
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070048}
49
50nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now,
51 const VSyncDispatch::ScheduleTiming& timing) {
52 const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
53 std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
Ady Abraham3e019972023-10-20 13:23:48 -070054 return getExpectedCallbackTime(now, nextVsyncTime, timing);
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070055}
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080056
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070057} // namespace
58
Kevin DuBoise4f27a82019-11-12 11:41:41 -080059VSyncDispatch::~VSyncDispatch() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070060VSyncTracker::~VSyncTracker() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070061
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080062VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
63 VSyncDispatch::Callback callback,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080064 nsecs_t minVsyncDistance)
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080065 : mName(std::move(name)),
66 mCallback(std::move(callback)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -080067 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -070068
Kevin DuBoise4f27a82019-11-12 11:41:41 -080069std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070070 return mLastDispatchTime;
71}
72
Kevin DuBoise4f27a82019-11-12 11:41:41 -080073std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070074 return mName;
75}
76
Kevin DuBoise4f27a82019-11-12 11:41:41 -080077std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070078 if (!mArmedInfo) {
79 return {};
80 }
81 return {mArmedInfo->mActualWakeupTime};
82}
83
Ady Abraham9c53ee72020-07-22 21:16:18 -070084std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
85 if (!mArmedInfo) {
86 return {};
87 }
88 return {mArmedInfo->mActualReadyTime};
89}
90
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080091std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
92 if (!mArmedInfo) {
93 return {};
94 }
95 return {mArmedInfo->mActualVsyncTime};
96}
97
Ady Abraham9c53ee72020-07-22 21:16:18 -070098ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
Kevin DuBois2311b1a2019-11-18 16:19:08 -080099 VSyncTracker& tracker, nsecs_t now) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700100 auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
101 std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
Ady Abraham69b9e622021-07-19 12:24:31 -0700102 auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800103
104 bool const wouldSkipAVsyncTarget =
105 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
Ady Abraham69b9e622021-07-19 12:24:31 -0700106 bool const wouldSkipAWakeup =
107 mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
Ady Abraham529bd9f2023-10-05 14:55:30 -0700108 if (flags::dont_skip_on_early()) {
109 if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
Ady Abraham3e019972023-10-20 13:23:48 -0700110 return getExpectedCallbackTime(now, mArmedInfo->mActualVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700111 }
112 } else {
113 if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
Ady Abraham3e019972023-10-20 13:23:48 -0700114 return getExpectedCallbackTime(now, nextVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700115 }
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800116 }
117
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700118 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
119 nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800120
Ady Abraham9c53ee72020-07-22 21:16:18 -0700121 auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
122 mScheduleTiming = timing;
123 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Ady Abraham3e019972023-10-20 13:23:48 -0700124 return getExpectedCallbackTime(now, nextVsyncTime, timing);
Kevin DuBois305bef12019-10-09 13:23:27 -0700125}
126
Ady Abraham9c53ee72020-07-22 21:16:18 -0700127void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
128 mWorkloadUpdateInfo = timing;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700129}
130
131bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
132 return mWorkloadUpdateInfo.has_value();
133}
134
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700135nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
136 nsecs_t nextVsyncTime) const {
137 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
138 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
139 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
140 const nsecs_t currentPeriod = tracker.currentPeriod();
141 bool const nextVsyncTooClose = mLastDispatchTime &&
142 (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
143 if (alreadyDispatchedForVsync) {
144 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
145 }
146
147 if (nextVsyncTooClose) {
148 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod);
149 }
150
151 return nextVsyncTime;
152}
153
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800154void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700155 if (!mArmedInfo && !mWorkloadUpdateInfo) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700156 return;
157 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700158
159 if (mWorkloadUpdateInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700160 mScheduleTiming = *mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700161 mWorkloadUpdateInfo.reset();
162 }
163
Ady Abraham9c53ee72020-07-22 21:16:18 -0700164 const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
165 const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync);
166
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700167 const auto nextVsyncTime =
168 adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
169 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync));
Ady Abraham9c53ee72020-07-22 21:16:18 -0700170 const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
171 const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
172
173 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Kevin DuBois305bef12019-10-09 13:23:27 -0700174}
175
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800176void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700177 mArmedInfo.reset();
178}
179
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800180nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700181 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
182 disarm();
183 return *mLastDispatchTime;
184}
185
Ady Abraham9c53ee72020-07-22 21:16:18 -0700186void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
187 nsecs_t deadlineTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700188 {
189 std::lock_guard<std::mutex> lk(mRunningMutex);
190 mRunning = true;
191 }
192
Ady Abraham9c53ee72020-07-22 21:16:18 -0700193 mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700194
195 std::lock_guard<std::mutex> lk(mRunningMutex);
196 mRunning = false;
197 mCv.notify_all();
198}
199
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800200void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700201 std::unique_lock<std::mutex> lk(mRunningMutex);
202 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
203}
204
Ady Abraham5e7371c2020-03-24 14:47:24 -0700205void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
206 std::lock_guard<std::mutex> lk(mRunningMutex);
207 std::string armedInfo;
208 if (mArmedInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700209 StringAppendF(&armedInfo,
210 "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
Ady Abraham5e7371c2020-03-24 14:47:24 -0700211 (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
Ady Abraham9c53ee72020-07-22 21:16:18 -0700212 (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
Ady Abraham5e7371c2020-03-24 14:47:24 -0700213 (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
214 }
215
216 StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
217 mRunning ? "(in callback function)" : "", armedInfo.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700218 StringAppendF(&result,
219 "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative "
220 "to now\n",
221 mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
222 (mScheduleTiming.earliestVsync - systemTime()) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700223
224 if (mLastDispatchTime) {
225 StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
226 (systemTime() - *mLastDispatchTime) / 1e6f);
227 } else {
228 StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
229 }
230}
231
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800232VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Leon Scroggins III67388622023-02-06 20:36:20 -0500233 VsyncSchedule::TrackerPtr tracker,
234 nsecs_t timerSlack, nsecs_t minVsyncDistance)
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800235 : mTimeKeeper(std::move(tk)),
Leon Scroggins III67388622023-02-06 20:36:20 -0500236 mTracker(std::move(tracker)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800237 mTimerSlack(timerSlack),
238 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700239
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800240VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700241 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700242 cancelTimer();
Leon Scroggins III07738132023-04-24 11:43:53 -0400243 for (auto& [_, entry] : mCallbacks) {
244 ALOGE("Forgot to unregister a callback on VSyncDispatch!");
245 entry->ensureNotRunning();
246 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700247}
248
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800249void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700250 mIntendedWakeupTime = kInvalidTime;
251 mTimeKeeper->alarmCancel();
252}
253
Ady Abrahamb491c902020-08-15 15:47:56 -0700254void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700255 mIntendedWakeupTime = targetTime;
Ady Abrahamb491c902020-08-15 15:47:56 -0700256 mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
257 mIntendedWakeupTime);
Ady Abraham75398722020-04-07 14:08:45 -0700258 mLastTimerSchedule = mTimeKeeper->now();
Kevin DuBois305bef12019-10-09 13:23:27 -0700259}
260
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800261void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700262 rearmTimerSkippingUpdateFor(now, mCallbacks.end());
263}
264
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800265void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
266 nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700267 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800268 std::optional<nsecs_t> targetVsync;
269 std::optional<std::string_view> nextWakeupName;
Kevin DuBois305bef12019-10-09 13:23:27 -0700270 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
271 auto& callback = it->second;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700272 if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700273 continue;
274 }
275
276 if (it != skipUpdateIt) {
Leon Scroggins III67388622023-02-06 20:36:20 -0500277 callback->update(*mTracker, now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700278 }
279 auto const wakeupTime = *callback->wakeupTime();
Dominik Laskowski62eff352021-12-06 09:59:41 -0800280 if (!min || *min > wakeupTime) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800281 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700282 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800283 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700284 }
285 }
286
Dominik Laskowski62eff352021-12-06 09:59:41 -0800287 if (min && min < mIntendedWakeupTime) {
288 if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
289 ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
290 "us; VSYNC in ", ns2us(*targetVsync - now), "us");
291 ATRACE_NAME(trace.c_str());
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800292 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700293 setTimer(*min, now);
294 } else {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800295 ATRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700296 cancelTimer();
297 }
298}
299
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800300void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700301 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800302 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800303 nsecs_t vsyncTimestamp;
304 nsecs_t wakeupTimestamp;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700305 nsecs_t deadlineTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700306 };
307 std::vector<Invocation> invocations;
308 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700309 std::lock_guard lock(mMutex);
Kevin DuBoisf9477832020-07-16 10:21:36 -0700310 auto const now = mTimeKeeper->now();
311 mLastTimerCallback = now;
Kevin DuBois305bef12019-10-09 13:23:27 -0700312 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
313 auto& callback = it->second;
314 auto const wakeupTime = callback->wakeupTime();
315 if (!wakeupTime) {
316 continue;
317 }
318
Ady Abraham9c53ee72020-07-22 21:16:18 -0700319 auto const readyTime = callback->readyTime();
320
Kevin DuBoisf9477832020-07-16 10:21:36 -0700321 auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
322 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700323 callback->executing();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700324 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
325 *wakeupTime, *readyTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700326 }
327 }
328
329 mIntendedWakeupTime = kInvalidTime;
330 rearmTimer(mTimeKeeper->now());
331 }
332
333 for (auto const& invocation : invocations) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700334 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
335 invocation.deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700336 }
337}
338
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800339VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800340 Callback callback, std::string callbackName) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700341 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700342 return CallbackToken{
343 mCallbacks
344 .emplace(++mCallbackToken,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800345 std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
346 std::move(callback),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800347 mMinVsyncDistance))
Kevin DuBois305bef12019-10-09 13:23:27 -0700348 .first->first};
349}
350
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800351void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
352 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700353 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700354 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700355 auto it = mCallbacks.find(token);
356 if (it != mCallbacks.end()) {
357 entry = it->second;
358 mCallbacks.erase(it);
359 }
360 }
361
362 if (entry) {
363 entry->ensureNotRunning();
364 }
365}
366
Ady Abraham9c53ee72020-07-22 21:16:18 -0700367ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
368 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800369 std::lock_guard lock(mMutex);
370 return scheduleLocked(token, scheduleTiming);
371}
Kevin DuBois305bef12019-10-09 13:23:27 -0700372
Ady Abraham011f8ba2022-11-22 15:09:07 -0800373ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
374 ScheduleTiming scheduleTiming) {
375 auto it = mCallbacks.find(token);
376 if (it == mCallbacks.end()) {
377 return {};
378 }
379 auto& callback = it->second;
380 auto const now = mTimeKeeper->now();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700381
Ady Abraham011f8ba2022-11-22 15:09:07 -0800382 /* If the timer thread will run soon, we'll apply this work update via the callback
383 * timer recalculation to avoid cancelling a callback that is about to fire. */
384 auto const rearmImminent = now > mIntendedWakeupTime;
385 if (CC_UNLIKELY(rearmImminent)) {
386 callback->addPendingWorkloadUpdate(scheduleTiming);
Leon Scroggins III67388622023-02-06 20:36:20 -0500387 return getExpectedCallbackTime(*mTracker, now, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800388 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700389
Leon Scroggins III67388622023-02-06 20:36:20 -0500390 const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800391 if (!result.has_value()) {
392 return {};
393 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700394
Ady Abraham011f8ba2022-11-22 15:09:07 -0800395 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
396 rearmTimerSkippingUpdateFor(now, it);
Kevin DuBois305bef12019-10-09 13:23:27 -0700397 }
398
399 return result;
400}
401
Ady Abraham011f8ba2022-11-22 15:09:07 -0800402ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
403 std::lock_guard lock(mMutex);
404 const auto it = mCallbacks.find(token);
405 if (it == mCallbacks.end()) {
406 return {};
407 }
408
409 auto& callback = it->second;
410 if (!callback->targetVsync().has_value()) {
411 return {};
412 }
413
414 return scheduleLocked(token, scheduleTiming);
415}
416
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800417CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700418 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700419
420 auto it = mCallbacks.find(token);
421 if (it == mCallbacks.end()) {
422 return CancelResult::Error;
423 }
424 auto& callback = it->second;
425
Kevin DuBoisb340b732020-06-16 09:07:35 -0700426 auto const wakeupTime = callback->wakeupTime();
427 if (wakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700428 callback->disarm();
Kevin DuBoisb340b732020-06-16 09:07:35 -0700429
430 if (*wakeupTime == mIntendedWakeupTime) {
431 mIntendedWakeupTime = kInvalidTime;
432 rearmTimer(mTimeKeeper->now());
433 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700434 return CancelResult::Cancelled;
435 }
436 return CancelResult::TooLate;
437}
438
Ady Abraham5e7371c2020-03-24 14:47:24 -0700439void VSyncDispatchTimerQueue::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700440 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700441 StringAppendF(&result, "\tTimer:\n");
442 mTimeKeeper->dump(result);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700443 StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
444 mMinVsyncDistance / 1e6f);
445 StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
Ady Abraham75398722020-04-07 14:08:45 -0700446 (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
447 StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
448 (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
449 (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700450 StringAppendF(&result, "\tCallbacks:\n");
451 for (const auto& [token, entry] : mCallbacks) {
452 entry->dump(result);
453 }
454}
455
Leon Scroggins III67388622023-02-06 20:36:20 -0500456VSyncCallbackRegistration::VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800457 VSyncDispatch::Callback callback,
458 std::string callbackName)
Leon Scroggins III67388622023-02-06 20:36:20 -0500459 : mDispatch(std::move(dispatch)),
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400460 mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700461
462VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400463 : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700464
465VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400466 if (this == &other) return *this;
467 if (mToken) {
468 mDispatch->unregisterCallback(*mToken);
469 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700470 mDispatch = std::move(other.mDispatch);
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400471 mToken = std::exchange(other.mToken, std::nullopt);
Kevin DuBois305bef12019-10-09 13:23:27 -0700472 return *this;
473}
474
475VSyncCallbackRegistration::~VSyncCallbackRegistration() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400476 if (mToken) mDispatch->unregisterCallback(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700477}
478
Ady Abraham9c53ee72020-07-22 21:16:18 -0700479ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400480 if (!mToken) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700481 return std::nullopt;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800482 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400483 return mDispatch->schedule(*mToken, scheduleTiming);
Kevin DuBois305bef12019-10-09 13:23:27 -0700484}
485
Ady Abraham011f8ba2022-11-22 15:09:07 -0800486ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400487 if (!mToken) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800488 return std::nullopt;
489 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400490 return mDispatch->update(*mToken, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800491}
492
Kevin DuBois305bef12019-10-09 13:23:27 -0700493CancelResult VSyncCallbackRegistration::cancel() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400494 if (!mToken) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800495 return CancelResult::Error;
496 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400497 return mDispatch->cancel(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700498}
499
500} // namespace android::scheduler