blob: 73d52cf986d87da3e721abab8a5acaa0abcc0c7c [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>
24
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080025#include <scheduler/TimeKeeper.h>
26
Kevin DuBoise4f27a82019-11-12 11:41:41 -080027#include "VSyncDispatchTimerQueue.h"
Kevin DuBois305bef12019-10-09 13:23:27 -070028#include "VSyncTracker.h"
29
30namespace android::scheduler {
Dominik Laskowski62eff352021-12-06 09:59:41 -080031
Ady Abraham5e7371c2020-03-24 14:47:24 -070032using base::StringAppendF;
Kevin DuBois305bef12019-10-09 13:23:27 -070033
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070034namespace {
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080035
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070036nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
37 const VSyncDispatch::ScheduleTiming& timing) {
38 return nextVsyncTime - timing.readyDuration - timing.workDuration;
39}
40
41nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now,
42 const VSyncDispatch::ScheduleTiming& timing) {
43 const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
44 std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
45 return getExpectedCallbackTime(nextVsyncTime, timing);
46}
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080047
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070048} // namespace
49
Kevin DuBoise4f27a82019-11-12 11:41:41 -080050VSyncDispatch::~VSyncDispatch() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070051VSyncTracker::~VSyncTracker() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070052
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080053VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
54 VSyncDispatch::Callback callback,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080055 nsecs_t minVsyncDistance)
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080056 : mName(std::move(name)),
57 mCallback(std::move(callback)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -080058 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -070059
Kevin DuBoise4f27a82019-11-12 11:41:41 -080060std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070061 return mLastDispatchTime;
62}
63
Kevin DuBoise4f27a82019-11-12 11:41:41 -080064std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070065 return mName;
66}
67
Kevin DuBoise4f27a82019-11-12 11:41:41 -080068std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070069 if (!mArmedInfo) {
70 return {};
71 }
72 return {mArmedInfo->mActualWakeupTime};
73}
74
Ady Abraham9c53ee72020-07-22 21:16:18 -070075std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
76 if (!mArmedInfo) {
77 return {};
78 }
79 return {mArmedInfo->mActualReadyTime};
80}
81
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080082std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
83 if (!mArmedInfo) {
84 return {};
85 }
86 return {mArmedInfo->mActualVsyncTime};
87}
88
Ady Abraham9c53ee72020-07-22 21:16:18 -070089ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
Kevin DuBois2311b1a2019-11-18 16:19:08 -080090 VSyncTracker& tracker, nsecs_t now) {
Ady Abraham9c53ee72020-07-22 21:16:18 -070091 auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
92 std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
Ady Abraham69b9e622021-07-19 12:24:31 -070093 auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -080094
95 bool const wouldSkipAVsyncTarget =
96 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
Ady Abraham69b9e622021-07-19 12:24:31 -070097 bool const wouldSkipAWakeup =
98 mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
99 if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700100 return getExpectedCallbackTime(nextVsyncTime, timing);
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800101 }
102
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700103 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
104 nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800105
Ady Abraham9c53ee72020-07-22 21:16:18 -0700106 auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
107 mScheduleTiming = timing;
108 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700109 return getExpectedCallbackTime(nextVsyncTime, timing);
Kevin DuBois305bef12019-10-09 13:23:27 -0700110}
111
Ady Abraham9c53ee72020-07-22 21:16:18 -0700112void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
113 mWorkloadUpdateInfo = timing;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700114}
115
116bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
117 return mWorkloadUpdateInfo.has_value();
118}
119
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700120nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
121 nsecs_t nextVsyncTime) const {
122 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
123 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
124 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
125 const nsecs_t currentPeriod = tracker.currentPeriod();
126 bool const nextVsyncTooClose = mLastDispatchTime &&
127 (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
128 if (alreadyDispatchedForVsync) {
129 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
130 }
131
132 if (nextVsyncTooClose) {
133 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod);
134 }
135
136 return nextVsyncTime;
137}
138
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800139void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700140 if (!mArmedInfo && !mWorkloadUpdateInfo) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700141 return;
142 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700143
144 if (mWorkloadUpdateInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700145 mScheduleTiming = *mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700146 mWorkloadUpdateInfo.reset();
147 }
148
Ady Abraham9c53ee72020-07-22 21:16:18 -0700149 const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
150 const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync);
151
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700152 const auto nextVsyncTime =
153 adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
154 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync));
Ady Abraham9c53ee72020-07-22 21:16:18 -0700155 const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
156 const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
157
158 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Kevin DuBois305bef12019-10-09 13:23:27 -0700159}
160
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800161void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700162 mArmedInfo.reset();
163}
164
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800165nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700166 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
167 disarm();
168 return *mLastDispatchTime;
169}
170
Ady Abraham9c53ee72020-07-22 21:16:18 -0700171void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
172 nsecs_t deadlineTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700173 {
174 std::lock_guard<std::mutex> lk(mRunningMutex);
175 mRunning = true;
176 }
177
Ady Abraham9c53ee72020-07-22 21:16:18 -0700178 mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700179
180 std::lock_guard<std::mutex> lk(mRunningMutex);
181 mRunning = false;
182 mCv.notify_all();
183}
184
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800185void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700186 std::unique_lock<std::mutex> lk(mRunningMutex);
187 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
188}
189
Ady Abraham5e7371c2020-03-24 14:47:24 -0700190void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
191 std::lock_guard<std::mutex> lk(mRunningMutex);
192 std::string armedInfo;
193 if (mArmedInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700194 StringAppendF(&armedInfo,
195 "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
Ady Abraham5e7371c2020-03-24 14:47:24 -0700196 (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
Ady Abraham9c53ee72020-07-22 21:16:18 -0700197 (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
Ady Abraham5e7371c2020-03-24 14:47:24 -0700198 (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
199 }
200
201 StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
202 mRunning ? "(in callback function)" : "", armedInfo.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700203 StringAppendF(&result,
204 "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative "
205 "to now\n",
206 mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
207 (mScheduleTiming.earliestVsync - systemTime()) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700208
209 if (mLastDispatchTime) {
210 StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
211 (systemTime() - *mLastDispatchTime) / 1e6f);
212 } else {
213 StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
214 }
215}
216
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800217VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800218 VSyncTracker& tracker, nsecs_t timerSlack,
219 nsecs_t minVsyncDistance)
220 : mTimeKeeper(std::move(tk)),
221 mTracker(tracker),
222 mTimerSlack(timerSlack),
223 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700224
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800225VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700226 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700227 cancelTimer();
228}
229
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800230void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700231 mIntendedWakeupTime = kInvalidTime;
232 mTimeKeeper->alarmCancel();
233}
234
Ady Abrahamb491c902020-08-15 15:47:56 -0700235void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700236 mIntendedWakeupTime = targetTime;
Ady Abrahamb491c902020-08-15 15:47:56 -0700237 mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
238 mIntendedWakeupTime);
Ady Abraham75398722020-04-07 14:08:45 -0700239 mLastTimerSchedule = mTimeKeeper->now();
Kevin DuBois305bef12019-10-09 13:23:27 -0700240}
241
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800242void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700243 rearmTimerSkippingUpdateFor(now, mCallbacks.end());
244}
245
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800246void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
247 nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700248 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800249 std::optional<nsecs_t> targetVsync;
250 std::optional<std::string_view> nextWakeupName;
Kevin DuBois305bef12019-10-09 13:23:27 -0700251 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
252 auto& callback = it->second;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700253 if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700254 continue;
255 }
256
257 if (it != skipUpdateIt) {
258 callback->update(mTracker, now);
259 }
260 auto const wakeupTime = *callback->wakeupTime();
Dominik Laskowski62eff352021-12-06 09:59:41 -0800261 if (!min || *min > wakeupTime) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800262 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700263 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800264 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700265 }
266 }
267
Dominik Laskowski62eff352021-12-06 09:59:41 -0800268 if (min && min < mIntendedWakeupTime) {
269 if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
270 ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
271 "us; VSYNC in ", ns2us(*targetVsync - now), "us");
272 ATRACE_NAME(trace.c_str());
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800273 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700274 setTimer(*min, now);
275 } else {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800276 ATRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700277 cancelTimer();
278 }
279}
280
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800281void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700282 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800283 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800284 nsecs_t vsyncTimestamp;
285 nsecs_t wakeupTimestamp;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700286 nsecs_t deadlineTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700287 };
288 std::vector<Invocation> invocations;
289 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700290 std::lock_guard lock(mMutex);
Kevin DuBoisf9477832020-07-16 10:21:36 -0700291 auto const now = mTimeKeeper->now();
292 mLastTimerCallback = now;
Kevin DuBois305bef12019-10-09 13:23:27 -0700293 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
294 auto& callback = it->second;
295 auto const wakeupTime = callback->wakeupTime();
296 if (!wakeupTime) {
297 continue;
298 }
299
Ady Abraham9c53ee72020-07-22 21:16:18 -0700300 auto const readyTime = callback->readyTime();
301
Kevin DuBoisf9477832020-07-16 10:21:36 -0700302 auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
303 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700304 callback->executing();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700305 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
306 *wakeupTime, *readyTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700307 }
308 }
309
310 mIntendedWakeupTime = kInvalidTime;
311 rearmTimer(mTimeKeeper->now());
312 }
313
314 for (auto const& invocation : invocations) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700315 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
316 invocation.deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700317 }
318}
319
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800320VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800321 Callback callback, std::string callbackName) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700322 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700323 return CallbackToken{
324 mCallbacks
325 .emplace(++mCallbackToken,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800326 std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
327 std::move(callback),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800328 mMinVsyncDistance))
Kevin DuBois305bef12019-10-09 13:23:27 -0700329 .first->first};
330}
331
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800332void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
333 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700334 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700335 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700336 auto it = mCallbacks.find(token);
337 if (it != mCallbacks.end()) {
338 entry = it->second;
339 mCallbacks.erase(it);
340 }
341 }
342
343 if (entry) {
344 entry->ensureNotRunning();
345 }
346}
347
Ady Abraham9c53ee72020-07-22 21:16:18 -0700348ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
349 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800350 std::lock_guard lock(mMutex);
351 return scheduleLocked(token, scheduleTiming);
352}
Kevin DuBois305bef12019-10-09 13:23:27 -0700353
Ady Abraham011f8ba2022-11-22 15:09:07 -0800354ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
355 ScheduleTiming scheduleTiming) {
356 auto it = mCallbacks.find(token);
357 if (it == mCallbacks.end()) {
358 return {};
359 }
360 auto& callback = it->second;
361 auto const now = mTimeKeeper->now();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700362
Ady Abraham011f8ba2022-11-22 15:09:07 -0800363 /* If the timer thread will run soon, we'll apply this work update via the callback
364 * timer recalculation to avoid cancelling a callback that is about to fire. */
365 auto const rearmImminent = now > mIntendedWakeupTime;
366 if (CC_UNLIKELY(rearmImminent)) {
367 callback->addPendingWorkloadUpdate(scheduleTiming);
368 return getExpectedCallbackTime(mTracker, now, scheduleTiming);
369 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700370
Ady Abraham011f8ba2022-11-22 15:09:07 -0800371 const ScheduleResult result = callback->schedule(scheduleTiming, mTracker, now);
372 if (!result.has_value()) {
373 return {};
374 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700375
Ady Abraham011f8ba2022-11-22 15:09:07 -0800376 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
377 rearmTimerSkippingUpdateFor(now, it);
Kevin DuBois305bef12019-10-09 13:23:27 -0700378 }
379
380 return result;
381}
382
Ady Abraham011f8ba2022-11-22 15:09:07 -0800383ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
384 std::lock_guard lock(mMutex);
385 const auto it = mCallbacks.find(token);
386 if (it == mCallbacks.end()) {
387 return {};
388 }
389
390 auto& callback = it->second;
391 if (!callback->targetVsync().has_value()) {
392 return {};
393 }
394
395 return scheduleLocked(token, scheduleTiming);
396}
397
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800398CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700399 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700400
401 auto it = mCallbacks.find(token);
402 if (it == mCallbacks.end()) {
403 return CancelResult::Error;
404 }
405 auto& callback = it->second;
406
Kevin DuBoisb340b732020-06-16 09:07:35 -0700407 auto const wakeupTime = callback->wakeupTime();
408 if (wakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700409 callback->disarm();
Kevin DuBoisb340b732020-06-16 09:07:35 -0700410
411 if (*wakeupTime == mIntendedWakeupTime) {
412 mIntendedWakeupTime = kInvalidTime;
413 rearmTimer(mTimeKeeper->now());
414 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700415 return CancelResult::Cancelled;
416 }
417 return CancelResult::TooLate;
418}
419
Ady Abraham5e7371c2020-03-24 14:47:24 -0700420void VSyncDispatchTimerQueue::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700421 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700422 StringAppendF(&result, "\tTimer:\n");
423 mTimeKeeper->dump(result);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700424 StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
425 mMinVsyncDistance / 1e6f);
426 StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
Ady Abraham75398722020-04-07 14:08:45 -0700427 (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
428 StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
429 (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
430 (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700431 StringAppendF(&result, "\tCallbacks:\n");
432 for (const auto& [token, entry] : mCallbacks) {
433 entry->dump(result);
434 }
435}
436
Kevin DuBois305bef12019-10-09 13:23:27 -0700437VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800438 VSyncDispatch::Callback callback,
439 std::string callbackName)
Kevin DuBois305bef12019-10-09 13:23:27 -0700440 : mDispatch(dispatch),
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800441 mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),
Kevin DuBois305bef12019-10-09 13:23:27 -0700442 mValidToken(true) {}
443
444VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
445 : mDispatch(other.mDispatch),
446 mToken(std::move(other.mToken)),
447 mValidToken(std::move(other.mValidToken)) {
448 other.mValidToken = false;
449}
450
451VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
452 mDispatch = std::move(other.mDispatch);
453 mToken = std::move(other.mToken);
454 mValidToken = std::move(other.mValidToken);
455 other.mValidToken = false;
456 return *this;
457}
458
459VSyncCallbackRegistration::~VSyncCallbackRegistration() {
460 if (mValidToken) mDispatch.get().unregisterCallback(mToken);
461}
462
Ady Abraham9c53ee72020-07-22 21:16:18 -0700463ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800464 if (!mValidToken) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700465 return std::nullopt;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800466 }
Ady Abraham9c53ee72020-07-22 21:16:18 -0700467 return mDispatch.get().schedule(mToken, scheduleTiming);
Kevin DuBois305bef12019-10-09 13:23:27 -0700468}
469
Ady Abraham011f8ba2022-11-22 15:09:07 -0800470ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
471 if (!mValidToken) {
472 return std::nullopt;
473 }
474 return mDispatch.get().update(mToken, scheduleTiming);
475}
476
Kevin DuBois305bef12019-10-09 13:23:27 -0700477CancelResult VSyncCallbackRegistration::cancel() {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800478 if (!mValidToken) {
479 return CancelResult::Error;
480 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700481 return mDispatch.get().cancel(mToken);
482}
483
484} // namespace android::scheduler