blob: d0f18abe77cb269175a1d0d1ac6c17715bb83f26 [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
18#include <utils/Trace.h>
19#include <vector>
20
21#include "TimeKeeper.h"
Kevin DuBoise4f27a82019-11-12 11:41:41 -080022#include "VSyncDispatchTimerQueue.h"
Kevin DuBois305bef12019-10-09 13:23:27 -070023#include "VSyncTracker.h"
24
25namespace android::scheduler {
26
Kevin DuBoise4f27a82019-11-12 11:41:41 -080027VSyncDispatch::~VSyncDispatch() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070028VSyncTracker::~VSyncTracker() = default;
29TimeKeeper::~TimeKeeper() = default;
30
Kevin DuBoise4f27a82019-11-12 11:41:41 -080031VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& name,
Kevin DuBois2968afc2020-01-14 09:48:50 -080032 VSyncDispatch::Callback const& cb,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080033 nsecs_t minVsyncDistance)
34 : mName(name),
35 mCallback(cb),
36 mWorkDuration(0),
37 mEarliestVsync(0),
38 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -070039
Kevin DuBoise4f27a82019-11-12 11:41:41 -080040std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070041 return mLastDispatchTime;
42}
43
Kevin DuBoise4f27a82019-11-12 11:41:41 -080044std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070045 return mName;
46}
47
Kevin DuBoise4f27a82019-11-12 11:41:41 -080048std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070049 if (!mArmedInfo) {
50 return {};
51 }
52 return {mArmedInfo->mActualWakeupTime};
53}
54
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080055std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
56 if (!mArmedInfo) {
57 return {};
58 }
59 return {mArmedInfo->mActualVsyncTime};
60}
61
Kevin DuBois2311b1a2019-11-18 16:19:08 -080062ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
63 VSyncTracker& tracker, nsecs_t now) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -080064 auto nextVsyncTime =
Kevin DuBois2311b1a2019-11-18 16:19:08 -080065 tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration));
Kevin DuBoisc94ca832019-11-26 12:56:24 -080066
67 bool const wouldSkipAVsyncTarget =
68 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
69 if (wouldSkipAVsyncTarget) {
70 return ScheduleResult::Scheduled;
71 }
72
73 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
74 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
75 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
76 if (alreadyDispatchedForVsync) {
77 nextVsyncTime =
78 tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
Kevin DuBois2311b1a2019-11-18 16:19:08 -080079 }
80
81 auto const nextWakeupTime = nextVsyncTime - workDuration;
Kevin DuBois305bef12019-10-09 13:23:27 -070082 mWorkDuration = workDuration;
83 mEarliestVsync = earliestVsync;
Kevin DuBois2311b1a2019-11-18 16:19:08 -080084 mArmedInfo = {nextWakeupTime, nextVsyncTime};
Kevin DuBoisc94ca832019-11-26 12:56:24 -080085 return ScheduleResult::Scheduled;
Kevin DuBois305bef12019-10-09 13:23:27 -070086}
87
Kevin DuBoise4f27a82019-11-12 11:41:41 -080088void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -070089 if (!mArmedInfo) {
90 return;
91 }
Kevin DuBois305bef12019-10-09 13:23:27 -070092 auto const nextVsyncTime =
93 tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration));
94 mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime};
95}
96
Kevin DuBoise4f27a82019-11-12 11:41:41 -080097void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -070098 mArmedInfo.reset();
99}
100
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800101nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700102 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
103 disarm();
104 return *mLastDispatchTime;
105}
106
Kevin DuBois2968afc2020-01-14 09:48:50 -0800107void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700108 {
109 std::lock_guard<std::mutex> lk(mRunningMutex);
110 mRunning = true;
111 }
112
Kevin DuBois2968afc2020-01-14 09:48:50 -0800113 mCallback(vsyncTimestamp, wakeupTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700114
115 std::lock_guard<std::mutex> lk(mRunningMutex);
116 mRunning = false;
117 mCv.notify_all();
118}
119
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800120void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700121 std::unique_lock<std::mutex> lk(mRunningMutex);
122 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
123}
124
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800125VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800126 VSyncTracker& tracker, nsecs_t timerSlack,
127 nsecs_t minVsyncDistance)
128 : mTimeKeeper(std::move(tk)),
129 mTracker(tracker),
130 mTimerSlack(timerSlack),
131 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700132
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800133VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700134 std::lock_guard<decltype(mMutex)> lk(mMutex);
135 cancelTimer();
136}
137
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800138void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700139 mIntendedWakeupTime = kInvalidTime;
140 mTimeKeeper->alarmCancel();
141}
142
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800143void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700144 mIntendedWakeupTime = targetTime;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800145 mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
146 targetTime - now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700147}
148
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800149void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700150 rearmTimerSkippingUpdateFor(now, mCallbacks.end());
151}
152
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800153void VSyncDispatchTimerQueue::TraceBuffer::note(std::string_view name, nsecs_t alarmIn,
154 nsecs_t vsFor) {
155 if (ATRACE_ENABLED()) {
156 snprintf(str_buffer.data(), str_buffer.size(), "%.4s%s%" PRId64 "%s%" PRId64,
157 name.substr(0, kMaxNamePrint).data(), kTraceNamePrefix, alarmIn,
158 kTraceNameSeparator, vsFor);
159 }
160 ATRACE_NAME(str_buffer.data());
161}
162
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800163void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
164 nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700165 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800166 std::optional<nsecs_t> targetVsync;
167 std::optional<std::string_view> nextWakeupName;
Kevin DuBois305bef12019-10-09 13:23:27 -0700168 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
169 auto& callback = it->second;
170 if (!callback->wakeupTime()) {
171 continue;
172 }
173
174 if (it != skipUpdateIt) {
175 callback->update(mTracker, now);
176 }
177 auto const wakeupTime = *callback->wakeupTime();
178 if (!min || (min && *min > wakeupTime)) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800179 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700180 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800181 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700182 }
183 }
184
185 if (min && (min < mIntendedWakeupTime)) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800186 if (targetVsync && nextWakeupName) {
187 mTraceBuffer.note(*nextWakeupName, *min - now, *targetVsync - now);
188 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700189 setTimer(*min, now);
190 } else {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800191 ATRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700192 cancelTimer();
193 }
194}
195
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800196void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700197 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800198 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800199 nsecs_t vsyncTimestamp;
200 nsecs_t wakeupTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700201 };
202 std::vector<Invocation> invocations;
203 {
204 std::lock_guard<decltype(mMutex)> lk(mMutex);
205 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
206 auto& callback = it->second;
207 auto const wakeupTime = callback->wakeupTime();
208 if (!wakeupTime) {
209 continue;
210 }
211
212 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
213 callback->executing();
214 invocations.emplace_back(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800215 Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700216 }
217 }
218
219 mIntendedWakeupTime = kInvalidTime;
220 rearmTimer(mTimeKeeper->now());
221 }
222
223 for (auto const& invocation : invocations) {
Kevin DuBois2968afc2020-01-14 09:48:50 -0800224 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700225 }
226}
227
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800228VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800229 Callback const& callbackFn, std::string callbackName) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700230 std::lock_guard<decltype(mMutex)> lk(mMutex);
231 return CallbackToken{
232 mCallbacks
233 .emplace(++mCallbackToken,
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800234 std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800235 callbackFn,
236 mMinVsyncDistance))
Kevin DuBois305bef12019-10-09 13:23:27 -0700237 .first->first};
238}
239
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800240void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
241 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700242 {
243 std::lock_guard<decltype(mMutex)> lk(mMutex);
244 auto it = mCallbacks.find(token);
245 if (it != mCallbacks.end()) {
246 entry = it->second;
247 mCallbacks.erase(it);
248 }
249 }
250
251 if (entry) {
252 entry->ensureNotRunning();
253 }
254}
255
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800256ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration,
257 nsecs_t earliestVsync) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700258 auto result = ScheduleResult::Error;
259 {
260 std::lock_guard<decltype(mMutex)> lk(mMutex);
261
262 auto it = mCallbacks.find(token);
263 if (it == mCallbacks.end()) {
264 return result;
265 }
266 auto& callback = it->second;
Kevin DuBois305bef12019-10-09 13:23:27 -0700267 auto const now = mTimeKeeper->now();
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800268 result = callback->schedule(workDuration, earliestVsync, mTracker, now);
269 if (result == ScheduleResult::CannotSchedule) {
270 return result;
Kevin DuBois305bef12019-10-09 13:23:27 -0700271 }
272
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800273 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700274 rearmTimerSkippingUpdateFor(now, it);
275 }
276 }
277
278 return result;
279}
280
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800281CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700282 std::lock_guard<decltype(mMutex)> lk(mMutex);
283
284 auto it = mCallbacks.find(token);
285 if (it == mCallbacks.end()) {
286 return CancelResult::Error;
287 }
288 auto& callback = it->second;
289
290 if (callback->wakeupTime()) {
291 callback->disarm();
292 mIntendedWakeupTime = kInvalidTime;
293 rearmTimer(mTimeKeeper->now());
294 return CancelResult::Cancelled;
295 }
296 return CancelResult::TooLate;
297}
298
299VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
Kevin DuBois2968afc2020-01-14 09:48:50 -0800300 VSyncDispatch::Callback const& callbackFn,
Kevin DuBois305bef12019-10-09 13:23:27 -0700301 std::string const& callbackName)
302 : mDispatch(dispatch),
303 mToken(dispatch.registerCallback(callbackFn, callbackName)),
304 mValidToken(true) {}
305
306VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
307 : mDispatch(other.mDispatch),
308 mToken(std::move(other.mToken)),
309 mValidToken(std::move(other.mValidToken)) {
310 other.mValidToken = false;
311}
312
313VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
314 mDispatch = std::move(other.mDispatch);
315 mToken = std::move(other.mToken);
316 mValidToken = std::move(other.mValidToken);
317 other.mValidToken = false;
318 return *this;
319}
320
321VSyncCallbackRegistration::~VSyncCallbackRegistration() {
322 if (mValidToken) mDispatch.get().unregisterCallback(mToken);
323}
324
325ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800326 if (!mValidToken) {
327 return ScheduleResult::Error;
328 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700329 return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
330}
331
332CancelResult VSyncCallbackRegistration::cancel() {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800333 if (!mValidToken) {
334 return CancelResult::Error;
335 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700336 return mDispatch.get().cancel(mToken);
337}
338
339} // namespace android::scheduler