blob: f5aaf06655f88702c8e8609f8389b9c71b7e16fc [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
46nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now,
47 const VSyncDispatch::ScheduleTiming& timing) {
Ady Abraham4335afd2023-12-18 19:10:47 -080048 const auto nextVsyncTime =
49 tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
50 now + timing.workDuration +
51 timing.readyDuration),
52 timing.lastVsync);
Ady Abrahamb0d3d982023-10-30 11:29:51 -070053 return getExpectedCallbackTime(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 Abraham4335afd2023-12-18 19:10:47 -080099 auto nextVsyncTime =
100 tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
101 now + timing.workDuration +
102 timing.readyDuration),
103 timing.lastVsync);
Ady Abraham69b9e622021-07-19 12:24:31 -0700104 auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800105
106 bool const wouldSkipAVsyncTarget =
107 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
Ady Abraham69b9e622021-07-19 12:24:31 -0700108 bool const wouldSkipAWakeup =
109 mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
Ady Abrahambf554892024-02-14 18:18:21 +0000110 if (FlagManager::getInstance().dont_skip_on_early_ro()) {
Ady Abraham529bd9f2023-10-05 14:55:30 -0700111 if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700112 nextVsyncTime = mArmedInfo->mActualVsyncTime;
113 } else {
114 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700115 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700116 nextWakeupTime = std::max(now, nextVsyncTime - timing.workDuration - timing.readyDuration);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700117 } else {
118 if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700119 return getExpectedCallbackTime(nextVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700120 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700121 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
122 nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800123 }
124
Ady Abraham9c53ee72020-07-22 21:16:18 -0700125 auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
126 mScheduleTiming = timing;
127 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700128 return nextWakeupTime;
Kevin DuBois305bef12019-10-09 13:23:27 -0700129}
130
Ady Abraham9c53ee72020-07-22 21:16:18 -0700131void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
132 mWorkloadUpdateInfo = timing;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700133}
134
135bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
136 return mWorkloadUpdateInfo.has_value();
137}
138
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700139nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
140 nsecs_t nextVsyncTime) const {
141 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
142 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
143 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
144 const nsecs_t currentPeriod = tracker.currentPeriod();
145 bool const nextVsyncTooClose = mLastDispatchTime &&
146 (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
147 if (alreadyDispatchedForVsync) {
Ady Abraham4335afd2023-12-18 19:10:47 -0800148 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance,
149 *mLastDispatchTime);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700150 }
151
152 if (nextVsyncTooClose) {
Ady Abraham4335afd2023-12-18 19:10:47 -0800153 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod,
154 *mLastDispatchTime + currentPeriod);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700155 }
156
157 return nextVsyncTime;
158}
159
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800160void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700161 if (!mArmedInfo && !mWorkloadUpdateInfo) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700162 return;
163 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700164
165 if (mWorkloadUpdateInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700166 mScheduleTiming = *mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700167 mWorkloadUpdateInfo.reset();
168 }
169
Ady Abraham9c53ee72020-07-22 21:16:18 -0700170 const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
Ady Abraham4335afd2023-12-18 19:10:47 -0800171 const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.lastVsync);
Ady Abraham9c53ee72020-07-22 21:16:18 -0700172
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700173 const auto nextVsyncTime =
174 adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
Ady Abraham4335afd2023-12-18 19:10:47 -0800175 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync,
176 mScheduleTiming.lastVsync));
Ady Abraham9c53ee72020-07-22 21:16:18 -0700177 const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
178 const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
179
180 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
Kevin DuBois305bef12019-10-09 13:23:27 -0700181}
182
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800183void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700184 mArmedInfo.reset();
185}
186
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800187nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700188 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
189 disarm();
190 return *mLastDispatchTime;
191}
192
Ady Abraham9c53ee72020-07-22 21:16:18 -0700193void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
194 nsecs_t deadlineTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700195 {
196 std::lock_guard<std::mutex> lk(mRunningMutex);
197 mRunning = true;
198 }
199
Ady Abraham9c53ee72020-07-22 21:16:18 -0700200 mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700201
202 std::lock_guard<std::mutex> lk(mRunningMutex);
203 mRunning = false;
204 mCv.notify_all();
205}
206
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800207void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700208 std::unique_lock<std::mutex> lk(mRunningMutex);
209 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
210}
211
Ady Abraham5e7371c2020-03-24 14:47:24 -0700212void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
213 std::lock_guard<std::mutex> lk(mRunningMutex);
214 std::string armedInfo;
215 if (mArmedInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700216 StringAppendF(&armedInfo,
217 "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
Ady Abraham5e7371c2020-03-24 14:47:24 -0700218 (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
Ady Abraham9c53ee72020-07-22 21:16:18 -0700219 (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
Ady Abraham5e7371c2020-03-24 14:47:24 -0700220 (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
221 }
222
223 StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
224 mRunning ? "(in callback function)" : "", armedInfo.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700225 StringAppendF(&result,
Ady Abraham4335afd2023-12-18 19:10:47 -0800226 "\t\t\tworkDuration: %.2fms readyDuration: %.2fms lastVsync: %.2fms relative "
Ady Abraham9c53ee72020-07-22 21:16:18 -0700227 "to now\n",
228 mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
Ady Abraham4335afd2023-12-18 19:10:47 -0800229 (mScheduleTiming.lastVsync - systemTime()) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700230
231 if (mLastDispatchTime) {
232 StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
233 (systemTime() - *mLastDispatchTime) / 1e6f);
234 } else {
235 StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
236 }
237}
238
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800239VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Leon Scroggins III67388622023-02-06 20:36:20 -0500240 VsyncSchedule::TrackerPtr tracker,
241 nsecs_t timerSlack, nsecs_t minVsyncDistance)
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800242 : mTimeKeeper(std::move(tk)),
Leon Scroggins III67388622023-02-06 20:36:20 -0500243 mTracker(std::move(tracker)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800244 mTimerSlack(timerSlack),
245 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700246
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800247VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700248 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800249 mRunning = false;
Kevin DuBois305bef12019-10-09 13:23:27 -0700250 cancelTimer();
Leon Scroggins III07738132023-04-24 11:43:53 -0400251 for (auto& [_, entry] : mCallbacks) {
252 ALOGE("Forgot to unregister a callback on VSyncDispatch!");
253 entry->ensureNotRunning();
254 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700255}
256
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800257void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700258 mIntendedWakeupTime = kInvalidTime;
259 mTimeKeeper->alarmCancel();
260}
261
Ady Abrahamb491c902020-08-15 15:47:56 -0700262void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700263 mIntendedWakeupTime = targetTime;
Ady Abrahamb491c902020-08-15 15:47:56 -0700264 mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
265 mIntendedWakeupTime);
Ady Abraham75398722020-04-07 14:08:45 -0700266 mLastTimerSchedule = mTimeKeeper->now();
Kevin DuBois305bef12019-10-09 13:23:27 -0700267}
268
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800269void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500270 rearmTimerSkippingUpdateFor(now, mCallbacks.cend());
Kevin DuBois305bef12019-10-09 13:23:27 -0700271}
272
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800273void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500274 nsecs_t now, CallbackMap::const_iterator skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700275 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800276 std::optional<nsecs_t> targetVsync;
277 std::optional<std::string_view> nextWakeupName;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500278 for (auto it = mCallbacks.cbegin(); it != mCallbacks.cend(); ++it) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700279 auto& callback = it->second;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700280 if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700281 continue;
282 }
283
284 if (it != skipUpdateIt) {
Leon Scroggins III67388622023-02-06 20:36:20 -0500285 callback->update(*mTracker, now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700286 }
287 auto const wakeupTime = *callback->wakeupTime();
Dominik Laskowski62eff352021-12-06 09:59:41 -0800288 if (!min || *min > wakeupTime) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800289 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700290 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800291 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700292 }
293 }
294
Dominik Laskowski62eff352021-12-06 09:59:41 -0800295 if (min && min < mIntendedWakeupTime) {
296 if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
297 ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
298 "us; VSYNC in ", ns2us(*targetVsync - now), "us");
299 ATRACE_NAME(trace.c_str());
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800300 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700301 setTimer(*min, now);
302 } else {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800303 ATRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700304 cancelTimer();
305 }
306}
307
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800308void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700309 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800310 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800311 nsecs_t vsyncTimestamp;
312 nsecs_t wakeupTimestamp;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700313 nsecs_t deadlineTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700314 };
315 std::vector<Invocation> invocations;
316 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700317 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800318 if (!mRunning) {
319 ALOGD("TimerQueue is not running. Skipping callback.");
320 return;
321 }
Kevin DuBoisf9477832020-07-16 10:21:36 -0700322 auto const now = mTimeKeeper->now();
323 mLastTimerCallback = now;
Kevin DuBois305bef12019-10-09 13:23:27 -0700324 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
325 auto& callback = it->second;
326 auto const wakeupTime = callback->wakeupTime();
327 if (!wakeupTime) {
328 continue;
329 }
330
Ady Abraham9c53ee72020-07-22 21:16:18 -0700331 auto const readyTime = callback->readyTime();
332
Kevin DuBoisf9477832020-07-16 10:21:36 -0700333 auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
334 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700335 callback->executing();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700336 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
337 *wakeupTime, *readyTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700338 }
339 }
340
341 mIntendedWakeupTime = kInvalidTime;
342 rearmTimer(mTimeKeeper->now());
343 }
344
345 for (auto const& invocation : invocations) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700346 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
347 invocation.deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700348 }
349}
350
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800351VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800352 Callback callback, std::string callbackName) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700353 std::lock_guard lock(mMutex);
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500354 return mCallbacks
Dominik Laskowski43baf902023-11-17 18:13:11 -0500355 .try_emplace(++mCallbackToken,
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500356 std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
357 std::move(callback),
358 mMinVsyncDistance))
359 .first->first;
Kevin DuBois305bef12019-10-09 13:23:27 -0700360}
361
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800362void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
363 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700364 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700365 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700366 auto it = mCallbacks.find(token);
367 if (it != mCallbacks.end()) {
368 entry = it->second;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500369 mCallbacks.erase(it->first);
Kevin DuBois305bef12019-10-09 13:23:27 -0700370 }
371 }
372
373 if (entry) {
374 entry->ensureNotRunning();
375 }
376}
377
Ady Abraham9c53ee72020-07-22 21:16:18 -0700378ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
379 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800380 std::lock_guard lock(mMutex);
381 return scheduleLocked(token, scheduleTiming);
382}
Kevin DuBois305bef12019-10-09 13:23:27 -0700383
Ady Abraham011f8ba2022-11-22 15:09:07 -0800384ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
385 ScheduleTiming scheduleTiming) {
386 auto it = mCallbacks.find(token);
387 if (it == mCallbacks.end()) {
388 return {};
389 }
390 auto& callback = it->second;
391 auto const now = mTimeKeeper->now();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700392
Ady Abraham011f8ba2022-11-22 15:09:07 -0800393 /* If the timer thread will run soon, we'll apply this work update via the callback
394 * timer recalculation to avoid cancelling a callback that is about to fire. */
395 auto const rearmImminent = now > mIntendedWakeupTime;
396 if (CC_UNLIKELY(rearmImminent)) {
397 callback->addPendingWorkloadUpdate(scheduleTiming);
Leon Scroggins III67388622023-02-06 20:36:20 -0500398 return getExpectedCallbackTime(*mTracker, now, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800399 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700400
Leon Scroggins III67388622023-02-06 20:36:20 -0500401 const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800402 if (!result.has_value()) {
403 return {};
404 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700405
Ady Abraham011f8ba2022-11-22 15:09:07 -0800406 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
407 rearmTimerSkippingUpdateFor(now, it);
Kevin DuBois305bef12019-10-09 13:23:27 -0700408 }
409
410 return result;
411}
412
Ady Abraham011f8ba2022-11-22 15:09:07 -0800413ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
414 std::lock_guard lock(mMutex);
415 const auto it = mCallbacks.find(token);
416 if (it == mCallbacks.end()) {
417 return {};
418 }
419
420 auto& callback = it->second;
421 if (!callback->targetVsync().has_value()) {
422 return {};
423 }
424
425 return scheduleLocked(token, scheduleTiming);
426}
427
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800428CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700429 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700430
431 auto it = mCallbacks.find(token);
432 if (it == mCallbacks.end()) {
433 return CancelResult::Error;
434 }
435 auto& callback = it->second;
436
Kevin DuBoisb340b732020-06-16 09:07:35 -0700437 auto const wakeupTime = callback->wakeupTime();
438 if (wakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700439 callback->disarm();
Kevin DuBoisb340b732020-06-16 09:07:35 -0700440
441 if (*wakeupTime == mIntendedWakeupTime) {
442 mIntendedWakeupTime = kInvalidTime;
443 rearmTimer(mTimeKeeper->now());
444 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700445 return CancelResult::Cancelled;
446 }
447 return CancelResult::TooLate;
448}
449
Ady Abraham5e7371c2020-03-24 14:47:24 -0700450void VSyncDispatchTimerQueue::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700451 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700452 StringAppendF(&result, "\tTimer:\n");
453 mTimeKeeper->dump(result);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700454 StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
455 mMinVsyncDistance / 1e6f);
456 StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
Ady Abraham75398722020-04-07 14:08:45 -0700457 (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
458 StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
459 (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
460 (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700461 StringAppendF(&result, "\tCallbacks:\n");
462 for (const auto& [token, entry] : mCallbacks) {
463 entry->dump(result);
464 }
465}
466
Leon Scroggins III67388622023-02-06 20:36:20 -0500467VSyncCallbackRegistration::VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800468 VSyncDispatch::Callback callback,
469 std::string callbackName)
Leon Scroggins III67388622023-02-06 20:36:20 -0500470 : mDispatch(std::move(dispatch)),
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400471 mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700472
473VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400474 : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700475
476VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400477 if (this == &other) return *this;
478 if (mToken) {
479 mDispatch->unregisterCallback(*mToken);
480 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700481 mDispatch = std::move(other.mDispatch);
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400482 mToken = std::exchange(other.mToken, std::nullopt);
Kevin DuBois305bef12019-10-09 13:23:27 -0700483 return *this;
484}
485
486VSyncCallbackRegistration::~VSyncCallbackRegistration() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400487 if (mToken) mDispatch->unregisterCallback(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700488}
489
Ady Abraham9c53ee72020-07-22 21:16:18 -0700490ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400491 if (!mToken) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700492 return std::nullopt;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800493 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400494 return mDispatch->schedule(*mToken, scheduleTiming);
Kevin DuBois305bef12019-10-09 13:23:27 -0700495}
496
Ady Abraham011f8ba2022-11-22 15:09:07 -0800497ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400498 if (!mToken) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800499 return std::nullopt;
500 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400501 return mDispatch->update(*mToken, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800502}
503
Kevin DuBois305bef12019-10-09 13:23:27 -0700504CancelResult VSyncCallbackRegistration::cancel() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400505 if (!mToken) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800506 return CancelResult::Error;
507 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400508 return mDispatch->cancel(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700509}
510
511} // namespace android::scheduler