blob: 48f2abb7aaaa8d9e67d3bbdfd0c46adba4020448 [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 DuBoisc94ca832019-11-26 12:56:24 -080032 std::function<void(nsecs_t)> const& cb,
33 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 DuBoise4f27a82019-11-12 11:41:41 -0800100void VSyncDispatchTimerQueueEntry::callback(nsecs_t t) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700101 {
102 std::lock_guard<std::mutex> lk(mRunningMutex);
103 mRunning = true;
104 }
105
106 mCallback(t);
107
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 DuBois305bef12019-10-09 13:23:27 -0700174 nsecs_t timestamp;
175 };
176 std::vector<Invocation> invocations;
177 {
178 std::lock_guard<decltype(mMutex)> lk(mMutex);
179 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
180 auto& callback = it->second;
181 auto const wakeupTime = callback->wakeupTime();
182 if (!wakeupTime) {
183 continue;
184 }
185
186 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
187 callback->executing();
188 invocations.emplace_back(
189 Invocation{callback, *callback->lastExecutedVsyncTarget()});
190 }
191 }
192
193 mIntendedWakeupTime = kInvalidTime;
194 rearmTimer(mTimeKeeper->now());
195 }
196
197 for (auto const& invocation : invocations) {
198 invocation.callback->callback(invocation.timestamp);
199 }
200}
201
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800202VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Kevin DuBois305bef12019-10-09 13:23:27 -0700203 std::function<void(nsecs_t)> const& callbackFn, std::string callbackName) {
204 std::lock_guard<decltype(mMutex)> lk(mMutex);
205 return CallbackToken{
206 mCallbacks
207 .emplace(++mCallbackToken,
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800208 std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800209 callbackFn,
210 mMinVsyncDistance))
Kevin DuBois305bef12019-10-09 13:23:27 -0700211 .first->first};
212}
213
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800214void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
215 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700216 {
217 std::lock_guard<decltype(mMutex)> lk(mMutex);
218 auto it = mCallbacks.find(token);
219 if (it != mCallbacks.end()) {
220 entry = it->second;
221 mCallbacks.erase(it);
222 }
223 }
224
225 if (entry) {
226 entry->ensureNotRunning();
227 }
228}
229
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800230ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration,
231 nsecs_t earliestVsync) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700232 auto result = ScheduleResult::Error;
233 {
234 std::lock_guard<decltype(mMutex)> lk(mMutex);
235
236 auto it = mCallbacks.find(token);
237 if (it == mCallbacks.end()) {
238 return result;
239 }
240 auto& callback = it->second;
Kevin DuBois305bef12019-10-09 13:23:27 -0700241 auto const now = mTimeKeeper->now();
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800242 result = callback->schedule(workDuration, earliestVsync, mTracker, now);
243 if (result == ScheduleResult::CannotSchedule) {
244 return result;
Kevin DuBois305bef12019-10-09 13:23:27 -0700245 }
246
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800247 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700248 rearmTimerSkippingUpdateFor(now, it);
249 }
250 }
251
252 return result;
253}
254
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800255CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700256 std::lock_guard<decltype(mMutex)> lk(mMutex);
257
258 auto it = mCallbacks.find(token);
259 if (it == mCallbacks.end()) {
260 return CancelResult::Error;
261 }
262 auto& callback = it->second;
263
264 if (callback->wakeupTime()) {
265 callback->disarm();
266 mIntendedWakeupTime = kInvalidTime;
267 rearmTimer(mTimeKeeper->now());
268 return CancelResult::Cancelled;
269 }
270 return CancelResult::TooLate;
271}
272
273VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
274 std::function<void(nsecs_t)> const& callbackFn,
275 std::string const& callbackName)
276 : mDispatch(dispatch),
277 mToken(dispatch.registerCallback(callbackFn, callbackName)),
278 mValidToken(true) {}
279
280VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
281 : mDispatch(other.mDispatch),
282 mToken(std::move(other.mToken)),
283 mValidToken(std::move(other.mValidToken)) {
284 other.mValidToken = false;
285}
286
287VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
288 mDispatch = std::move(other.mDispatch);
289 mToken = std::move(other.mToken);
290 mValidToken = std::move(other.mValidToken);
291 other.mValidToken = false;
292 return *this;
293}
294
295VSyncCallbackRegistration::~VSyncCallbackRegistration() {
296 if (mValidToken) mDispatch.get().unregisterCallback(mToken);
297}
298
299ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800300 if (!mValidToken) {
301 return ScheduleResult::Error;
302 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700303 return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
304}
305
306CancelResult VSyncCallbackRegistration::cancel() {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800307 if (!mValidToken) {
308 return CancelResult::Error;
309 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700310 return mDispatch.get().cancel(mToken);
311}
312
313} // namespace android::scheduler