blob: 792248494fc6c076f2b9a2ed2aa4e7655c0a9762 [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 DuBoise4f27a82019-11-12 11:41:41 -080050nsecs_t VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
51 VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -070052 mWorkDuration = workDuration;
53 mEarliestVsync = earliestVsync;
54 arm(tracker, now);
55 return mArmedInfo->mActualWakeupTime;
56}
57
Kevin DuBoise4f27a82019-11-12 11:41:41 -080058void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -070059 if (!mArmedInfo) {
60 return;
61 }
62 arm(tracker, now);
63}
64
Kevin DuBoise4f27a82019-11-12 11:41:41 -080065void VSyncDispatchTimerQueueEntry::arm(VSyncTracker& tracker, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -070066 auto const nextVsyncTime =
67 tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration));
68 mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime};
69}
70
Kevin DuBoise4f27a82019-11-12 11:41:41 -080071void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -070072 mArmedInfo.reset();
73}
74
Kevin DuBoise4f27a82019-11-12 11:41:41 -080075nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -070076 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
77 disarm();
78 return *mLastDispatchTime;
79}
80
Kevin DuBoise4f27a82019-11-12 11:41:41 -080081void VSyncDispatchTimerQueueEntry::callback(nsecs_t t) {
Kevin DuBois305bef12019-10-09 13:23:27 -070082 {
83 std::lock_guard<std::mutex> lk(mRunningMutex);
84 mRunning = true;
85 }
86
87 mCallback(t);
88
89 std::lock_guard<std::mutex> lk(mRunningMutex);
90 mRunning = false;
91 mCv.notify_all();
92}
93
Kevin DuBoise4f27a82019-11-12 11:41:41 -080094void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -070095 std::unique_lock<std::mutex> lk(mRunningMutex);
96 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
97}
98
Kevin DuBoise4f27a82019-11-12 11:41:41 -080099VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
100 VSyncTracker& tracker, nsecs_t timerSlack)
Kevin DuBois305bef12019-10-09 13:23:27 -0700101 : mTimeKeeper(std::move(tk)), mTracker(tracker), mTimerSlack(timerSlack) {}
102
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800103VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700104 std::lock_guard<decltype(mMutex)> lk(mMutex);
105 cancelTimer();
106}
107
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800108void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700109 mIntendedWakeupTime = kInvalidTime;
110 mTimeKeeper->alarmCancel();
111}
112
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800113void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700114 mIntendedWakeupTime = targetTime;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800115 mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
116 targetTime - now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700117}
118
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800119void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700120 rearmTimerSkippingUpdateFor(now, mCallbacks.end());
121}
122
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800123void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
124 nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700125 std::optional<nsecs_t> min;
126 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
127 auto& callback = it->second;
128 if (!callback->wakeupTime()) {
129 continue;
130 }
131
132 if (it != skipUpdateIt) {
133 callback->update(mTracker, now);
134 }
135 auto const wakeupTime = *callback->wakeupTime();
136 if (!min || (min && *min > wakeupTime)) {
137 min = wakeupTime;
138 }
139 }
140
141 if (min && (min < mIntendedWakeupTime)) {
142 setTimer(*min, now);
143 } else {
144 cancelTimer();
145 }
146}
147
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800148void VSyncDispatchTimerQueue::timerCallback() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700149 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800150 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois305bef12019-10-09 13:23:27 -0700151 nsecs_t timestamp;
152 };
153 std::vector<Invocation> invocations;
154 {
155 std::lock_guard<decltype(mMutex)> lk(mMutex);
156 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
157 auto& callback = it->second;
158 auto const wakeupTime = callback->wakeupTime();
159 if (!wakeupTime) {
160 continue;
161 }
162
163 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
164 callback->executing();
165 invocations.emplace_back(
166 Invocation{callback, *callback->lastExecutedVsyncTarget()});
167 }
168 }
169
170 mIntendedWakeupTime = kInvalidTime;
171 rearmTimer(mTimeKeeper->now());
172 }
173
174 for (auto const& invocation : invocations) {
175 invocation.callback->callback(invocation.timestamp);
176 }
177}
178
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800179VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Kevin DuBois305bef12019-10-09 13:23:27 -0700180 std::function<void(nsecs_t)> const& callbackFn, std::string callbackName) {
181 std::lock_guard<decltype(mMutex)> lk(mMutex);
182 return CallbackToken{
183 mCallbacks
184 .emplace(++mCallbackToken,
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800185 std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName,
186 callbackFn))
Kevin DuBois305bef12019-10-09 13:23:27 -0700187 .first->first};
188}
189
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800190void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
191 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700192 {
193 std::lock_guard<decltype(mMutex)> lk(mMutex);
194 auto it = mCallbacks.find(token);
195 if (it != mCallbacks.end()) {
196 entry = it->second;
197 mCallbacks.erase(it);
198 }
199 }
200
201 if (entry) {
202 entry->ensureNotRunning();
203 }
204}
205
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800206ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration,
207 nsecs_t earliestVsync) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700208 auto result = ScheduleResult::Error;
209 {
210 std::lock_guard<decltype(mMutex)> lk(mMutex);
211
212 auto it = mCallbacks.find(token);
213 if (it == mCallbacks.end()) {
214 return result;
215 }
216 auto& callback = it->second;
217 result = callback->wakeupTime() ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled;
218
219 auto const now = mTimeKeeper->now();
220 auto const wakeupTime = callback->schedule(workDuration, earliestVsync, mTracker, now);
221
222 if (wakeupTime < now - mTimerSlack || callback->lastExecutedVsyncTarget() > wakeupTime) {
223 return ScheduleResult::CannotSchedule;
224 }
225
226 if (wakeupTime < mIntendedWakeupTime - mTimerSlack) {
227 rearmTimerSkippingUpdateFor(now, it);
228 }
229 }
230
231 return result;
232}
233
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800234CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700235 std::lock_guard<decltype(mMutex)> lk(mMutex);
236
237 auto it = mCallbacks.find(token);
238 if (it == mCallbacks.end()) {
239 return CancelResult::Error;
240 }
241 auto& callback = it->second;
242
243 if (callback->wakeupTime()) {
244 callback->disarm();
245 mIntendedWakeupTime = kInvalidTime;
246 rearmTimer(mTimeKeeper->now());
247 return CancelResult::Cancelled;
248 }
249 return CancelResult::TooLate;
250}
251
252VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
253 std::function<void(nsecs_t)> const& callbackFn,
254 std::string const& callbackName)
255 : mDispatch(dispatch),
256 mToken(dispatch.registerCallback(callbackFn, callbackName)),
257 mValidToken(true) {}
258
259VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
260 : mDispatch(other.mDispatch),
261 mToken(std::move(other.mToken)),
262 mValidToken(std::move(other.mValidToken)) {
263 other.mValidToken = false;
264}
265
266VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
267 mDispatch = std::move(other.mDispatch);
268 mToken = std::move(other.mToken);
269 mValidToken = std::move(other.mValidToken);
270 other.mValidToken = false;
271 return *this;
272}
273
274VSyncCallbackRegistration::~VSyncCallbackRegistration() {
275 if (mValidToken) mDispatch.get().unregisterCallback(mToken);
276}
277
278ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
279 if (!mValidToken) return ScheduleResult::Error;
280 return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
281}
282
283CancelResult VSyncCallbackRegistration::cancel() {
284 if (!mValidToken) return CancelResult::Error;
285 return mDispatch.get().cancel(mToken);
286}
287
288} // namespace android::scheduler