blob: 2e5b6e96932b242b99c631ab253f79c1a47361fd [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 DuBois2311b1a2019-11-18 16:19:08 -080055ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
56 VSyncTracker& tracker, nsecs_t now) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -080057 auto nextVsyncTime =
Kevin DuBois2311b1a2019-11-18 16:19:08 -080058 tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration));
Kevin DuBoisc94ca832019-11-26 12:56:24 -080059
60 bool const wouldSkipAVsyncTarget =
61 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
62 if (wouldSkipAVsyncTarget) {
63 return ScheduleResult::Scheduled;
64 }
65
66 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
67 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
68 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
69 if (alreadyDispatchedForVsync) {
70 nextVsyncTime =
71 tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
Kevin DuBois2311b1a2019-11-18 16:19:08 -080072 }
73
74 auto const nextWakeupTime = nextVsyncTime - workDuration;
Kevin DuBois305bef12019-10-09 13:23:27 -070075 mWorkDuration = workDuration;
76 mEarliestVsync = earliestVsync;
Kevin DuBois2311b1a2019-11-18 16:19:08 -080077 mArmedInfo = {nextWakeupTime, nextVsyncTime};
Kevin DuBoisc94ca832019-11-26 12:56:24 -080078 return ScheduleResult::Scheduled;
Kevin DuBois305bef12019-10-09 13:23:27 -070079}
80
Kevin DuBoise4f27a82019-11-12 11:41:41 -080081void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -070082 if (!mArmedInfo) {
83 return;
84 }
Kevin DuBois305bef12019-10-09 13:23:27 -070085 auto const nextVsyncTime =
86 tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration));
87 mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime};
88}
89
Kevin DuBoise4f27a82019-11-12 11:41:41 -080090void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -070091 mArmedInfo.reset();
92}
93
Kevin DuBoise4f27a82019-11-12 11:41:41 -080094nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -070095 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
96 disarm();
97 return *mLastDispatchTime;
98}
99
Kevin DuBois2968afc2020-01-14 09:48:50 -0800100void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700101 {
102 std::lock_guard<std::mutex> lk(mRunningMutex);
103 mRunning = true;
104 }
105
Kevin DuBois2968afc2020-01-14 09:48:50 -0800106 mCallback(vsyncTimestamp, wakeupTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700107
108 std::lock_guard<std::mutex> lk(mRunningMutex);
109 mRunning = false;
110 mCv.notify_all();
111}
112
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800113void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700114 std::unique_lock<std::mutex> lk(mRunningMutex);
115 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
116}
117
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800118VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800119 VSyncTracker& tracker, nsecs_t timerSlack,
120 nsecs_t minVsyncDistance)
121 : mTimeKeeper(std::move(tk)),
122 mTracker(tracker),
123 mTimerSlack(timerSlack),
124 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700125
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800126VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700127 std::lock_guard<decltype(mMutex)> lk(mMutex);
128 cancelTimer();
129}
130
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800131void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700132 mIntendedWakeupTime = kInvalidTime;
133 mTimeKeeper->alarmCancel();
134}
135
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800136void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700137 mIntendedWakeupTime = targetTime;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800138 mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
139 targetTime - now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700140}
141
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800142void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700143 rearmTimerSkippingUpdateFor(now, mCallbacks.end());
144}
145
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800146void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
147 nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700148 std::optional<nsecs_t> min;
149 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
150 auto& callback = it->second;
151 if (!callback->wakeupTime()) {
152 continue;
153 }
154
155 if (it != skipUpdateIt) {
156 callback->update(mTracker, now);
157 }
158 auto const wakeupTime = *callback->wakeupTime();
159 if (!min || (min && *min > wakeupTime)) {
160 min = wakeupTime;
161 }
162 }
163
164 if (min && (min < mIntendedWakeupTime)) {
165 setTimer(*min, now);
166 } else {
167 cancelTimer();
168 }
169}
170
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800171void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700172 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800173 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800174 nsecs_t vsyncTimestamp;
175 nsecs_t wakeupTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700176 };
177 std::vector<Invocation> invocations;
178 {
179 std::lock_guard<decltype(mMutex)> lk(mMutex);
180 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
181 auto& callback = it->second;
182 auto const wakeupTime = callback->wakeupTime();
183 if (!wakeupTime) {
184 continue;
185 }
186
187 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
188 callback->executing();
189 invocations.emplace_back(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800190 Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700191 }
192 }
193
194 mIntendedWakeupTime = kInvalidTime;
195 rearmTimer(mTimeKeeper->now());
196 }
197
198 for (auto const& invocation : invocations) {
Kevin DuBois2968afc2020-01-14 09:48:50 -0800199 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700200 }
201}
202
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800203VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800204 Callback const& callbackFn, std::string callbackName) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700205 std::lock_guard<decltype(mMutex)> lk(mMutex);
206 return CallbackToken{
207 mCallbacks
208 .emplace(++mCallbackToken,
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800209 std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800210 callbackFn,
211 mMinVsyncDistance))
Kevin DuBois305bef12019-10-09 13:23:27 -0700212 .first->first};
213}
214
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800215void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
216 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700217 {
218 std::lock_guard<decltype(mMutex)> lk(mMutex);
219 auto it = mCallbacks.find(token);
220 if (it != mCallbacks.end()) {
221 entry = it->second;
222 mCallbacks.erase(it);
223 }
224 }
225
226 if (entry) {
227 entry->ensureNotRunning();
228 }
229}
230
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800231ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration,
232 nsecs_t earliestVsync) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700233 auto result = ScheduleResult::Error;
234 {
235 std::lock_guard<decltype(mMutex)> lk(mMutex);
236
237 auto it = mCallbacks.find(token);
238 if (it == mCallbacks.end()) {
239 return result;
240 }
241 auto& callback = it->second;
Kevin DuBois305bef12019-10-09 13:23:27 -0700242 auto const now = mTimeKeeper->now();
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800243 result = callback->schedule(workDuration, earliestVsync, mTracker, now);
244 if (result == ScheduleResult::CannotSchedule) {
245 return result;
Kevin DuBois305bef12019-10-09 13:23:27 -0700246 }
247
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800248 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700249 rearmTimerSkippingUpdateFor(now, it);
250 }
251 }
252
253 return result;
254}
255
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800256CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700257 std::lock_guard<decltype(mMutex)> lk(mMutex);
258
259 auto it = mCallbacks.find(token);
260 if (it == mCallbacks.end()) {
261 return CancelResult::Error;
262 }
263 auto& callback = it->second;
264
265 if (callback->wakeupTime()) {
266 callback->disarm();
267 mIntendedWakeupTime = kInvalidTime;
268 rearmTimer(mTimeKeeper->now());
269 return CancelResult::Cancelled;
270 }
271 return CancelResult::TooLate;
272}
273
274VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
Kevin DuBois2968afc2020-01-14 09:48:50 -0800275 VSyncDispatch::Callback const& callbackFn,
Kevin DuBois305bef12019-10-09 13:23:27 -0700276 std::string const& callbackName)
277 : mDispatch(dispatch),
278 mToken(dispatch.registerCallback(callbackFn, callbackName)),
279 mValidToken(true) {}
280
281VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
282 : mDispatch(other.mDispatch),
283 mToken(std::move(other.mToken)),
284 mValidToken(std::move(other.mValidToken)) {
285 other.mValidToken = false;
286}
287
288VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
289 mDispatch = std::move(other.mDispatch);
290 mToken = std::move(other.mToken);
291 mValidToken = std::move(other.mValidToken);
292 other.mValidToken = false;
293 return *this;
294}
295
296VSyncCallbackRegistration::~VSyncCallbackRegistration() {
297 if (mValidToken) mDispatch.get().unregisterCallback(mToken);
298}
299
300ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800301 if (!mValidToken) {
302 return ScheduleResult::Error;
303 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700304 return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
305}
306
307CancelResult VSyncCallbackRegistration::cancel() {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800308 if (!mValidToken) {
309 return CancelResult::Error;
310 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700311 return mDispatch.get().cancel(mToken);
312}
313
314} // namespace android::scheduler