blob: a79fe98a27c3588b178c2420c5a1aeeceb242709 [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,
32 std::function<void(nsecs_t)> const& cb)
Kevin DuBois305bef12019-10-09 13:23:27 -070033 : mName(name), mCallback(cb), mWorkDuration(0), mEarliestVsync(0) {}
34
Kevin DuBoise4f27a82019-11-12 11:41:41 -080035std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070036 return mLastDispatchTime;
37}
38
Kevin DuBoise4f27a82019-11-12 11:41:41 -080039std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070040 return mName;
41}
42
Kevin DuBoise4f27a82019-11-12 11:41:41 -080043std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070044 if (!mArmedInfo) {
45 return {};
46 }
47 return {mArmedInfo->mActualWakeupTime};
48}
49
Kevin DuBois2311b1a2019-11-18 16:19:08 -080050ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
51 VSyncTracker& tracker, nsecs_t now) {
52 auto const nextVsyncTime =
53 tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration));
54 if (mLastDispatchTime >= nextVsyncTime) { // already dispatched a callback for this vsync
55 return ScheduleResult::CannotSchedule;
56 }
57
58 auto const nextWakeupTime = nextVsyncTime - workDuration;
59 auto result = mArmedInfo ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled;
Kevin DuBois305bef12019-10-09 13:23:27 -070060 mWorkDuration = workDuration;
61 mEarliestVsync = earliestVsync;
Kevin DuBois2311b1a2019-11-18 16:19:08 -080062 mArmedInfo = {nextWakeupTime, nextVsyncTime};
63 return result;
Kevin DuBois305bef12019-10-09 13:23:27 -070064}
65
Kevin DuBoise4f27a82019-11-12 11:41:41 -080066void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -070067 if (!mArmedInfo) {
68 return;
69 }
Kevin DuBois305bef12019-10-09 13:23:27 -070070 auto const nextVsyncTime =
71 tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration));
72 mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime};
73}
74
Kevin DuBoise4f27a82019-11-12 11:41:41 -080075void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -070076 mArmedInfo.reset();
77}
78
Kevin DuBoise4f27a82019-11-12 11:41:41 -080079nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -070080 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
81 disarm();
82 return *mLastDispatchTime;
83}
84
Kevin DuBoise4f27a82019-11-12 11:41:41 -080085void VSyncDispatchTimerQueueEntry::callback(nsecs_t t) {
Kevin DuBois305bef12019-10-09 13:23:27 -070086 {
87 std::lock_guard<std::mutex> lk(mRunningMutex);
88 mRunning = true;
89 }
90
91 mCallback(t);
92
93 std::lock_guard<std::mutex> lk(mRunningMutex);
94 mRunning = false;
95 mCv.notify_all();
96}
97
Kevin DuBoise4f27a82019-11-12 11:41:41 -080098void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -070099 std::unique_lock<std::mutex> lk(mRunningMutex);
100 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
101}
102
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800103VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
104 VSyncTracker& tracker, nsecs_t timerSlack)
Kevin DuBois305bef12019-10-09 13:23:27 -0700105 : mTimeKeeper(std::move(tk)), mTracker(tracker), mTimerSlack(timerSlack) {}
106
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800107VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700108 std::lock_guard<decltype(mMutex)> lk(mMutex);
109 cancelTimer();
110}
111
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800112void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700113 mIntendedWakeupTime = kInvalidTime;
114 mTimeKeeper->alarmCancel();
115}
116
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800117void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700118 mIntendedWakeupTime = targetTime;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800119 mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
120 targetTime - now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700121}
122
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800123void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700124 rearmTimerSkippingUpdateFor(now, mCallbacks.end());
125}
126
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800127void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
128 nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700129 std::optional<nsecs_t> min;
130 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
131 auto& callback = it->second;
132 if (!callback->wakeupTime()) {
133 continue;
134 }
135
136 if (it != skipUpdateIt) {
137 callback->update(mTracker, now);
138 }
139 auto const wakeupTime = *callback->wakeupTime();
140 if (!min || (min && *min > wakeupTime)) {
141 min = wakeupTime;
142 }
143 }
144
145 if (min && (min < mIntendedWakeupTime)) {
146 setTimer(*min, now);
147 } else {
148 cancelTimer();
149 }
150}
151
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800152void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700153 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800154 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois305bef12019-10-09 13:23:27 -0700155 nsecs_t timestamp;
156 };
157 std::vector<Invocation> invocations;
158 {
159 std::lock_guard<decltype(mMutex)> lk(mMutex);
160 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
161 auto& callback = it->second;
162 auto const wakeupTime = callback->wakeupTime();
163 if (!wakeupTime) {
164 continue;
165 }
166
167 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
168 callback->executing();
169 invocations.emplace_back(
170 Invocation{callback, *callback->lastExecutedVsyncTarget()});
171 }
172 }
173
174 mIntendedWakeupTime = kInvalidTime;
175 rearmTimer(mTimeKeeper->now());
176 }
177
178 for (auto const& invocation : invocations) {
179 invocation.callback->callback(invocation.timestamp);
180 }
181}
182
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800183VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Kevin DuBois305bef12019-10-09 13:23:27 -0700184 std::function<void(nsecs_t)> const& callbackFn, std::string callbackName) {
185 std::lock_guard<decltype(mMutex)> lk(mMutex);
186 return CallbackToken{
187 mCallbacks
188 .emplace(++mCallbackToken,
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800189 std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName,
190 callbackFn))
Kevin DuBois305bef12019-10-09 13:23:27 -0700191 .first->first};
192}
193
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800194void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
195 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700196 {
197 std::lock_guard<decltype(mMutex)> lk(mMutex);
198 auto it = mCallbacks.find(token);
199 if (it != mCallbacks.end()) {
200 entry = it->second;
201 mCallbacks.erase(it);
202 }
203 }
204
205 if (entry) {
206 entry->ensureNotRunning();
207 }
208}
209
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800210ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration,
211 nsecs_t earliestVsync) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700212 auto result = ScheduleResult::Error;
213 {
214 std::lock_guard<decltype(mMutex)> lk(mMutex);
215
216 auto it = mCallbacks.find(token);
217 if (it == mCallbacks.end()) {
218 return result;
219 }
220 auto& callback = it->second;
Kevin DuBois305bef12019-10-09 13:23:27 -0700221 auto const now = mTimeKeeper->now();
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800222 result = callback->schedule(workDuration, earliestVsync, mTracker, now);
223 if (result == ScheduleResult::CannotSchedule) {
224 return result;
Kevin DuBois305bef12019-10-09 13:23:27 -0700225 }
226
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800227 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700228 rearmTimerSkippingUpdateFor(now, it);
229 }
230 }
231
232 return result;
233}
234
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800235CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700236 std::lock_guard<decltype(mMutex)> lk(mMutex);
237
238 auto it = mCallbacks.find(token);
239 if (it == mCallbacks.end()) {
240 return CancelResult::Error;
241 }
242 auto& callback = it->second;
243
244 if (callback->wakeupTime()) {
245 callback->disarm();
246 mIntendedWakeupTime = kInvalidTime;
247 rearmTimer(mTimeKeeper->now());
248 return CancelResult::Cancelled;
249 }
250 return CancelResult::TooLate;
251}
252
253VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
254 std::function<void(nsecs_t)> const& callbackFn,
255 std::string const& callbackName)
256 : mDispatch(dispatch),
257 mToken(dispatch.registerCallback(callbackFn, callbackName)),
258 mValidToken(true) {}
259
260VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
261 : mDispatch(other.mDispatch),
262 mToken(std::move(other.mToken)),
263 mValidToken(std::move(other.mValidToken)) {
264 other.mValidToken = false;
265}
266
267VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
268 mDispatch = std::move(other.mDispatch);
269 mToken = std::move(other.mToken);
270 mValidToken = std::move(other.mValidToken);
271 other.mValidToken = false;
272 return *this;
273}
274
275VSyncCallbackRegistration::~VSyncCallbackRegistration() {
276 if (mValidToken) mDispatch.get().unregisterCallback(mToken);
277}
278
279ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
280 if (!mValidToken) return ScheduleResult::Error;
281 return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
282}
283
284CancelResult VSyncCallbackRegistration::cancel() {
285 if (!mValidToken) return CancelResult::Error;
286 return mDispatch.get().cancel(mToken);
287}
288
289} // namespace android::scheduler