blob: 47e3f4f9e922401610814623ef3fa96a98af09a3 [file] [log] [blame]
Kevin DuBoisb2501ba2019-11-12 14:20:29 -08001/*
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
Kevin DuBoisc94ca832019-11-26 12:56:24 -080017#undef LOG_TAG
18#define LOG_TAG "VSyncReactor"
Kevin DuBoisf91e9232019-11-21 10:51:23 -080019//#define LOG_NDEBUG 0
Kevin DuBoisb2501ba2019-11-12 14:20:29 -080020#include "VSyncReactor.h"
Kevin DuBoisf91e9232019-11-21 10:51:23 -080021#include <log/log.h>
Kevin DuBois2fd3cea2019-11-14 08:52:45 -080022#include "TimeKeeper.h"
Kevin DuBoisb2501ba2019-11-12 14:20:29 -080023#include "VSyncDispatch.h"
24#include "VSyncTracker.h"
25
26namespace android::scheduler {
27
Kevin DuBois2fd3cea2019-11-14 08:52:45 -080028Clock::~Clock() = default;
29
30VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
Kevin DuBoisb2501ba2019-11-12 14:20:29 -080031 std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit)
Kevin DuBois2fd3cea2019-11-14 08:52:45 -080032 : mClock(std::move(clock)),
33 mDispatch(std::move(dispatch)),
Kevin DuBoisb2501ba2019-11-12 14:20:29 -080034 mTracker(std::move(tracker)),
35 mPendingLimit(pendingFenceLimit) {}
36
Kevin DuBoisf91e9232019-11-21 10:51:23 -080037VSyncReactor::~VSyncReactor() = default;
38
39// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts
40// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic
41// for now.
42class CallbackRepeater {
43public:
44 CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name,
45 nsecs_t period, nsecs_t offset, nsecs_t notBefore)
46 : mCallback(cb),
47 mRegistration(dispatch,
48 std::bind(&CallbackRepeater::callback, this, std::placeholders::_1),
49 std::string(name)),
50 mPeriod(period),
51 mOffset(offset),
52 mLastCallTime(notBefore) {}
53
54 ~CallbackRepeater() {
55 std::lock_guard<std::mutex> lk(mMutex);
56 mRegistration.cancel();
57 }
58
59 void start(nsecs_t offset) {
60 std::lock_guard<std::mutex> lk(mMutex);
61 mStopped = false;
62 mOffset = offset;
63
Kevin DuBoisc94ca832019-11-26 12:56:24 -080064 auto const schedule_result = mRegistration.schedule(calculateWorkload(), mLastCallTime);
65 LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
66 "Error scheduling callback: rc %X", schedule_result);
Kevin DuBoisf91e9232019-11-21 10:51:23 -080067 }
68
69 void setPeriod(nsecs_t period) {
70 std::lock_guard<std::mutex> lk(mMutex);
71 if (period == mPeriod) {
72 return;
73 }
74 mPeriod = period;
75 }
76
77 void stop() {
78 std::lock_guard<std::mutex> lk(mMutex);
79 LOG_ALWAYS_FATAL_IF(mStopped, "DispSyncInterface misuse: callback already stopped");
80 mStopped = true;
81 mRegistration.cancel();
82 }
83
84private:
85 void callback(nsecs_t vsynctime) {
86 nsecs_t period = 0;
87 {
88 std::lock_guard<std::mutex> lk(mMutex);
89 period = mPeriod;
90 mLastCallTime = vsynctime;
91 }
92
93 mCallback->onDispSyncEvent(vsynctime - period);
94
95 {
96 std::lock_guard<std::mutex> lk(mMutex);
Kevin DuBoisc94ca832019-11-26 12:56:24 -080097 auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime);
98 LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
99 "Error rescheduling callback: rc %X", schedule_result);
Kevin DuBoisf91e9232019-11-21 10:51:23 -0800100 }
101 }
102
103 // DispSync offsets are defined as time after the vsync before presentation.
104 // VSyncReactor workloads are defined as time before the intended presentation vsync.
105 // Note change in sign between the two defnitions.
106 nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; }
107
108 DispSync::Callback* const mCallback;
109
110 std::mutex mutable mMutex;
111 VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
112 bool mStopped GUARDED_BY(mMutex) = false;
113 nsecs_t mPeriod GUARDED_BY(mMutex);
114 nsecs_t mOffset GUARDED_BY(mMutex);
115 nsecs_t mLastCallTime GUARDED_BY(mMutex);
116};
117
Kevin DuBoisb2501ba2019-11-12 14:20:29 -0800118bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) {
119 if (!fence) {
120 return false;
121 }
122
123 nsecs_t const signalTime = fence->getCachedSignalTime();
124 if (signalTime == Fence::SIGNAL_TIME_INVALID) {
125 return true;
126 }
127
128 std::lock_guard<std::mutex> lk(mMutex);
129 if (mIgnorePresentFences) {
130 return true;
131 }
132
133 for (auto it = mUnfiredFences.begin(); it != mUnfiredFences.end();) {
134 auto const time = (*it)->getCachedSignalTime();
135 if (time == Fence::SIGNAL_TIME_PENDING) {
136 it++;
137 } else if (time == Fence::SIGNAL_TIME_INVALID) {
138 it = mUnfiredFences.erase(it);
139 } else {
140 mTracker->addVsyncTimestamp(time);
141 it = mUnfiredFences.erase(it);
142 }
143 }
144
145 if (signalTime == Fence::SIGNAL_TIME_PENDING) {
146 if (mPendingLimit == mUnfiredFences.size()) {
147 mUnfiredFences.erase(mUnfiredFences.begin());
148 }
149 mUnfiredFences.push_back(fence);
150 } else {
151 mTracker->addVsyncTimestamp(signalTime);
152 }
153
154 return false; // TODO(b/144707443): add policy for turning on HWVsync.
155}
156
157void VSyncReactor::setIgnorePresentFences(bool ignoration) {
158 std::lock_guard<std::mutex> lk(mMutex);
159 mIgnorePresentFences = ignoration;
160 if (mIgnorePresentFences == true) {
161 mUnfiredFences.clear();
162 }
163}
164
Kevin DuBois2fd3cea2019-11-14 08:52:45 -0800165nsecs_t VSyncReactor::computeNextRefresh(int periodOffset) const {
166 auto const now = mClock->now();
167 auto const currentPeriod = periodOffset ? mTracker->currentPeriod() : 0;
168 return mTracker->nextAnticipatedVSyncTimeFrom(now + periodOffset * currentPeriod);
169}
170
171nsecs_t VSyncReactor::expectedPresentTime() {
172 return mTracker->nextAnticipatedVSyncTimeFrom(mClock->now());
173}
174
Kevin DuBoisee2ad9f2019-11-21 11:10:57 -0800175void VSyncReactor::setPeriod(nsecs_t period) {
176 mTracker->setPeriod(period);
Kevin DuBoisa9fdab72019-11-14 09:44:14 -0800177 {
178 std::lock_guard<std::mutex> lk(mMutex);
179 mPeriodChangeInProgress = true;
Kevin DuBoisf91e9232019-11-21 10:51:23 -0800180 for (auto& entry : mCallbacks) {
181 entry.second->setPeriod(period);
182 }
Kevin DuBoisa9fdab72019-11-14 09:44:14 -0800183 }
Kevin DuBoisee2ad9f2019-11-21 11:10:57 -0800184}
185
186nsecs_t VSyncReactor::getPeriod() {
187 return mTracker->currentPeriod();
188}
189
Kevin DuBoisa9fdab72019-11-14 09:44:14 -0800190void VSyncReactor::beginResync() {}
191
192void VSyncReactor::endResync() {}
193
194bool VSyncReactor::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
195 assert(periodFlushed);
196 mTracker->addVsyncTimestamp(timestamp);
197 {
198 std::lock_guard<std::mutex> lk(mMutex);
199 *periodFlushed = mPeriodChangeInProgress;
200 mPeriodChangeInProgress = false;
201 }
202 return false;
203}
204
Kevin DuBoisf91e9232019-11-21 10:51:23 -0800205status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase,
206 DispSync::Callback* callback,
207 nsecs_t /* lastCallbackTime */) {
208 std::lock_guard<std::mutex> lk(mMutex);
209 auto it = mCallbacks.find(callback);
210 if (it == mCallbacks.end()) {
211 // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f.
212 static auto constexpr maxListeners = 3;
213 if (mCallbacks.size() >= maxListeners) {
214 ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name,
215 maxListeners, mCallbacks.size());
216 return NO_MEMORY;
217 }
218
219 auto const period = mTracker->currentPeriod();
220 auto repeater = std::make_unique<CallbackRepeater>(*mDispatch, callback, name, period,
221 phase, mClock->now());
222 it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first;
223 }
224
225 it->second->start(phase);
226 return NO_ERROR;
227}
228
229status_t VSyncReactor::removeEventListener(DispSync::Callback* callback,
230 nsecs_t* /* outLastCallback */) {
231 std::lock_guard<std::mutex> lk(mMutex);
232 auto const it = mCallbacks.find(callback);
233 LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback %p not registered", callback);
234
235 it->second->stop();
236 return NO_ERROR;
237}
238
239status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
240 std::lock_guard<std::mutex> lk(mMutex);
241 auto const it = mCallbacks.find(callback);
242 LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback was %p not registered", callback);
243
244 it->second->start(phase);
245 return NO_ERROR;
246}
247
Kevin DuBoisb2501ba2019-11-12 14:20:29 -0800248} // namespace android::scheduler