1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2009 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18*38e8c45fSAndroid Build Coastguard Worker
19*38e8c45fSAndroid Build Coastguard Worker #include <binder/IPCThreadState.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <utils/threads.h>
23*38e8c45fSAndroid Build Coastguard Worker
24*38e8c45fSAndroid Build Coastguard Worker #include <scheduler/interface/ICompositor.h>
25*38e8c45fSAndroid Build Coastguard Worker
26*38e8c45fSAndroid Build Coastguard Worker #include "EventThread.h"
27*38e8c45fSAndroid Build Coastguard Worker #include "FrameTimeline.h"
28*38e8c45fSAndroid Build Coastguard Worker #include "MessageQueue.h"
29*38e8c45fSAndroid Build Coastguard Worker
30*38e8c45fSAndroid Build Coastguard Worker namespace android::impl {
31*38e8c45fSAndroid Build Coastguard Worker
dispatchFrame(VsyncId vsyncId,TimePoint expectedVsyncTime)32*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) {
33*38e8c45fSAndroid Build Coastguard Worker if (!mFramePending.exchange(true)) {
34*38e8c45fSAndroid Build Coastguard Worker mVsyncId = vsyncId;
35*38e8c45fSAndroid Build Coastguard Worker mExpectedVsyncTime = expectedVsyncTime;
36*38e8c45fSAndroid Build Coastguard Worker mQueue.mLooper->sendMessage(sp<MessageHandler>::fromExisting(this), Message());
37*38e8c45fSAndroid Build Coastguard Worker }
38*38e8c45fSAndroid Build Coastguard Worker }
39*38e8c45fSAndroid Build Coastguard Worker
isFramePending() const40*38e8c45fSAndroid Build Coastguard Worker bool MessageQueue::Handler::isFramePending() const {
41*38e8c45fSAndroid Build Coastguard Worker return mFramePending.load();
42*38e8c45fSAndroid Build Coastguard Worker }
43*38e8c45fSAndroid Build Coastguard Worker
handleMessage(const Message &)44*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::Handler::handleMessage(const Message&) {
45*38e8c45fSAndroid Build Coastguard Worker mFramePending.store(false);
46*38e8c45fSAndroid Build Coastguard Worker mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime);
47*38e8c45fSAndroid Build Coastguard Worker }
48*38e8c45fSAndroid Build Coastguard Worker
MessageQueue(ICompositor & compositor)49*38e8c45fSAndroid Build Coastguard Worker MessageQueue::MessageQueue(ICompositor& compositor)
50*38e8c45fSAndroid Build Coastguard Worker : MessageQueue(compositor, sp<Handler>::make(*this)) {}
51*38e8c45fSAndroid Build Coastguard Worker
52*38e8c45fSAndroid Build Coastguard Worker constexpr bool kAllowNonCallbacks = true;
53*38e8c45fSAndroid Build Coastguard Worker
MessageQueue(ICompositor & compositor,sp<Handler> handler)54*38e8c45fSAndroid Build Coastguard Worker MessageQueue::MessageQueue(ICompositor& compositor, sp<Handler> handler)
55*38e8c45fSAndroid Build Coastguard Worker : mCompositor(compositor),
56*38e8c45fSAndroid Build Coastguard Worker mLooper(sp<Looper>::make(kAllowNonCallbacks)),
57*38e8c45fSAndroid Build Coastguard Worker mHandler(std::move(handler)) {}
58*38e8c45fSAndroid Build Coastguard Worker
vsyncCallback(nsecs_t vsyncTime,nsecs_t targetWakeupTime,nsecs_t readyTime)59*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
60*38e8c45fSAndroid Build Coastguard Worker SFTRACE_CALL();
61*38e8c45fSAndroid Build Coastguard Worker // Trace VSYNC-sf
62*38e8c45fSAndroid Build Coastguard Worker mVsync.value = (mVsync.value + 1) % 2;
63*38e8c45fSAndroid Build Coastguard Worker
64*38e8c45fSAndroid Build Coastguard Worker const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime);
65*38e8c45fSAndroid Build Coastguard Worker {
66*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mVsync.mutex);
67*38e8c45fSAndroid Build Coastguard Worker mVsync.lastCallbackTime = expectedVsyncTime;
68*38e8c45fSAndroid Build Coastguard Worker mVsync.scheduledFrameTimeOpt.reset();
69*38e8c45fSAndroid Build Coastguard Worker }
70*38e8c45fSAndroid Build Coastguard Worker
71*38e8c45fSAndroid Build Coastguard Worker const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
72*38e8c45fSAndroid Build Coastguard Worker {targetWakeupTime, readyTime, vsyncTime})};
73*38e8c45fSAndroid Build Coastguard Worker
74*38e8c45fSAndroid Build Coastguard Worker mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
75*38e8c45fSAndroid Build Coastguard Worker }
76*38e8c45fSAndroid Build Coastguard Worker
initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch> dispatch,frametimeline::TokenManager & tokenManager,std::chrono::nanoseconds workDuration)77*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch> dispatch,
78*38e8c45fSAndroid Build Coastguard Worker frametimeline::TokenManager& tokenManager,
79*38e8c45fSAndroid Build Coastguard Worker std::chrono::nanoseconds workDuration) {
80*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<scheduler::VSyncCallbackRegistration> oldRegistration;
81*38e8c45fSAndroid Build Coastguard Worker {
82*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mVsync.mutex);
83*38e8c45fSAndroid Build Coastguard Worker mVsync.workDuration = workDuration;
84*38e8c45fSAndroid Build Coastguard Worker mVsync.tokenManager = &tokenManager;
85*38e8c45fSAndroid Build Coastguard Worker oldRegistration = onNewVsyncScheduleLocked(std::move(dispatch));
86*38e8c45fSAndroid Build Coastguard Worker }
87*38e8c45fSAndroid Build Coastguard Worker
88*38e8c45fSAndroid Build Coastguard Worker // See comments in onNewVsyncSchedule. Today, oldRegistration should be
89*38e8c45fSAndroid Build Coastguard Worker // empty, but nothing prevents us from calling initVsyncInternal multiple times, so
90*38e8c45fSAndroid Build Coastguard Worker // go ahead and destruct it outside the lock for safety.
91*38e8c45fSAndroid Build Coastguard Worker oldRegistration.reset();
92*38e8c45fSAndroid Build Coastguard Worker }
93*38e8c45fSAndroid Build Coastguard Worker
onNewVsyncSchedule(std::shared_ptr<scheduler::VSyncDispatch> dispatch)94*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::onNewVsyncSchedule(std::shared_ptr<scheduler::VSyncDispatch> dispatch) {
95*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<scheduler::VSyncCallbackRegistration> oldRegistration;
96*38e8c45fSAndroid Build Coastguard Worker {
97*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mVsync.mutex);
98*38e8c45fSAndroid Build Coastguard Worker oldRegistration = onNewVsyncScheduleLocked(std::move(dispatch));
99*38e8c45fSAndroid Build Coastguard Worker }
100*38e8c45fSAndroid Build Coastguard Worker
101*38e8c45fSAndroid Build Coastguard Worker // The old registration needs to be deleted after releasing mVsync.mutex to
102*38e8c45fSAndroid Build Coastguard Worker // avoid deadlock. This is because the callback may be running on the timer
103*38e8c45fSAndroid Build Coastguard Worker // thread. In that case, timerCallback sets
104*38e8c45fSAndroid Build Coastguard Worker // VSyncDispatchTimerQueueEntry::mRunning to true, then attempts to lock
105*38e8c45fSAndroid Build Coastguard Worker // mVsync.mutex. But if it's already locked, the VSyncCallbackRegistration's
106*38e8c45fSAndroid Build Coastguard Worker // destructor has to wait until VSyncDispatchTimerQueueEntry::mRunning is
107*38e8c45fSAndroid Build Coastguard Worker // set back to false, but it won't be until mVsync.mutex is released.
108*38e8c45fSAndroid Build Coastguard Worker oldRegistration.reset();
109*38e8c45fSAndroid Build Coastguard Worker }
110*38e8c45fSAndroid Build Coastguard Worker
onNewVsyncScheduleLocked(std::shared_ptr<scheduler::VSyncDispatch> dispatch)111*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<scheduler::VSyncCallbackRegistration> MessageQueue::onNewVsyncScheduleLocked(
112*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<scheduler::VSyncDispatch> dispatch) {
113*38e8c45fSAndroid Build Coastguard Worker const bool reschedule = mVsync.registration &&
114*38e8c45fSAndroid Build Coastguard Worker mVsync.registration->cancel() == scheduler::CancelResult::Cancelled;
115*38e8c45fSAndroid Build Coastguard Worker auto oldRegistration = std::move(mVsync.registration);
116*38e8c45fSAndroid Build Coastguard Worker mVsync.registration = std::make_unique<
117*38e8c45fSAndroid Build Coastguard Worker scheduler::VSyncCallbackRegistration>(std::move(dispatch),
118*38e8c45fSAndroid Build Coastguard Worker std::bind(&MessageQueue::vsyncCallback, this,
119*38e8c45fSAndroid Build Coastguard Worker std::placeholders::_1,
120*38e8c45fSAndroid Build Coastguard Worker std::placeholders::_2,
121*38e8c45fSAndroid Build Coastguard Worker std::placeholders::_3),
122*38e8c45fSAndroid Build Coastguard Worker "sf");
123*38e8c45fSAndroid Build Coastguard Worker if (reschedule) {
124*38e8c45fSAndroid Build Coastguard Worker mVsync.scheduledFrameTimeOpt =
125*38e8c45fSAndroid Build Coastguard Worker mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
126*38e8c45fSAndroid Build Coastguard Worker .readyDuration = 0,
127*38e8c45fSAndroid Build Coastguard Worker .lastVsync = mVsync.lastCallbackTime.ns()});
128*38e8c45fSAndroid Build Coastguard Worker }
129*38e8c45fSAndroid Build Coastguard Worker return oldRegistration;
130*38e8c45fSAndroid Build Coastguard Worker }
131*38e8c45fSAndroid Build Coastguard Worker
destroyVsync()132*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::destroyVsync() {
133*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mVsync.mutex);
134*38e8c45fSAndroid Build Coastguard Worker mVsync.tokenManager = nullptr;
135*38e8c45fSAndroid Build Coastguard Worker mVsync.registration.reset();
136*38e8c45fSAndroid Build Coastguard Worker }
137*38e8c45fSAndroid Build Coastguard Worker
setDuration(std::chrono::nanoseconds workDuration)138*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) {
139*38e8c45fSAndroid Build Coastguard Worker SFTRACE_CALL();
140*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mVsync.mutex);
141*38e8c45fSAndroid Build Coastguard Worker mVsync.workDuration = workDuration;
142*38e8c45fSAndroid Build Coastguard Worker mVsync.scheduledFrameTimeOpt =
143*38e8c45fSAndroid Build Coastguard Worker mVsync.registration->update({.workDuration = mVsync.workDuration.get().count(),
144*38e8c45fSAndroid Build Coastguard Worker .readyDuration = 0,
145*38e8c45fSAndroid Build Coastguard Worker .lastVsync = mVsync.lastCallbackTime.ns()});
146*38e8c45fSAndroid Build Coastguard Worker }
147*38e8c45fSAndroid Build Coastguard Worker
waitMessage()148*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::waitMessage() {
149*38e8c45fSAndroid Build Coastguard Worker do {
150*38e8c45fSAndroid Build Coastguard Worker IPCThreadState::self()->flushCommands();
151*38e8c45fSAndroid Build Coastguard Worker int32_t ret = mLooper->pollOnce(-1);
152*38e8c45fSAndroid Build Coastguard Worker switch (ret) {
153*38e8c45fSAndroid Build Coastguard Worker case Looper::POLL_WAKE:
154*38e8c45fSAndroid Build Coastguard Worker case Looper::POLL_CALLBACK:
155*38e8c45fSAndroid Build Coastguard Worker continue;
156*38e8c45fSAndroid Build Coastguard Worker case Looper::POLL_ERROR:
157*38e8c45fSAndroid Build Coastguard Worker ALOGE("Looper::POLL_ERROR");
158*38e8c45fSAndroid Build Coastguard Worker continue;
159*38e8c45fSAndroid Build Coastguard Worker case Looper::POLL_TIMEOUT:
160*38e8c45fSAndroid Build Coastguard Worker // timeout (should not happen)
161*38e8c45fSAndroid Build Coastguard Worker continue;
162*38e8c45fSAndroid Build Coastguard Worker default:
163*38e8c45fSAndroid Build Coastguard Worker // should not happen
164*38e8c45fSAndroid Build Coastguard Worker ALOGE("Looper::pollOnce() returned unknown status %d", ret);
165*38e8c45fSAndroid Build Coastguard Worker continue;
166*38e8c45fSAndroid Build Coastguard Worker }
167*38e8c45fSAndroid Build Coastguard Worker } while (true);
168*38e8c45fSAndroid Build Coastguard Worker }
169*38e8c45fSAndroid Build Coastguard Worker
postMessage(sp<MessageHandler> && handler)170*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::postMessage(sp<MessageHandler>&& handler) {
171*38e8c45fSAndroid Build Coastguard Worker mLooper->sendMessage(handler, Message());
172*38e8c45fSAndroid Build Coastguard Worker }
173*38e8c45fSAndroid Build Coastguard Worker
postMessageDelayed(sp<MessageHandler> && handler,nsecs_t uptimeDelay)174*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::postMessageDelayed(sp<MessageHandler>&& handler, nsecs_t uptimeDelay) {
175*38e8c45fSAndroid Build Coastguard Worker mLooper->sendMessageDelayed(uptimeDelay, handler, Message());
176*38e8c45fSAndroid Build Coastguard Worker }
177*38e8c45fSAndroid Build Coastguard Worker
scheduleConfigure()178*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::scheduleConfigure() {
179*38e8c45fSAndroid Build Coastguard Worker struct ConfigureHandler : MessageHandler {
180*38e8c45fSAndroid Build Coastguard Worker explicit ConfigureHandler(ICompositor& compositor) : compositor(compositor) {}
181*38e8c45fSAndroid Build Coastguard Worker
182*38e8c45fSAndroid Build Coastguard Worker void handleMessage(const Message&) override { compositor.configure(); }
183*38e8c45fSAndroid Build Coastguard Worker
184*38e8c45fSAndroid Build Coastguard Worker ICompositor& compositor;
185*38e8c45fSAndroid Build Coastguard Worker };
186*38e8c45fSAndroid Build Coastguard Worker
187*38e8c45fSAndroid Build Coastguard Worker // TODO(b/241285876): Batch configure tasks that happen within some duration.
188*38e8c45fSAndroid Build Coastguard Worker postMessage(sp<ConfigureHandler>::make(mCompositor));
189*38e8c45fSAndroid Build Coastguard Worker }
190*38e8c45fSAndroid Build Coastguard Worker
scheduleFrame(Duration workDurationSlack)191*38e8c45fSAndroid Build Coastguard Worker void MessageQueue::scheduleFrame(Duration workDurationSlack) {
192*38e8c45fSAndroid Build Coastguard Worker SFTRACE_CALL();
193*38e8c45fSAndroid Build Coastguard Worker
194*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mVsync.mutex);
195*38e8c45fSAndroid Build Coastguard Worker const auto workDuration = Duration(mVsync.workDuration.get() - workDurationSlack);
196*38e8c45fSAndroid Build Coastguard Worker mVsync.scheduledFrameTimeOpt =
197*38e8c45fSAndroid Build Coastguard Worker mVsync.registration->schedule({.workDuration = workDuration.ns(),
198*38e8c45fSAndroid Build Coastguard Worker .readyDuration = 0,
199*38e8c45fSAndroid Build Coastguard Worker .lastVsync = mVsync.lastCallbackTime.ns()});
200*38e8c45fSAndroid Build Coastguard Worker }
201*38e8c45fSAndroid Build Coastguard Worker
getScheduledFrameResult() const202*38e8c45fSAndroid Build Coastguard Worker std::optional<scheduler::ScheduleResult> MessageQueue::getScheduledFrameResult() const {
203*38e8c45fSAndroid Build Coastguard Worker if (mHandler->isFramePending()) {
204*38e8c45fSAndroid Build Coastguard Worker return scheduler::ScheduleResult{TimePoint::now(), mHandler->getExpectedVsyncTime()};
205*38e8c45fSAndroid Build Coastguard Worker }
206*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mVsync.mutex);
207*38e8c45fSAndroid Build Coastguard Worker if (const auto scheduledFrameTimeline = mVsync.scheduledFrameTimeOpt) {
208*38e8c45fSAndroid Build Coastguard Worker return scheduledFrameTimeline;
209*38e8c45fSAndroid Build Coastguard Worker }
210*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
211*38e8c45fSAndroid Build Coastguard Worker }
212*38e8c45fSAndroid Build Coastguard Worker
213*38e8c45fSAndroid Build Coastguard Worker } // namespace android::impl
214