xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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