blob: 7e71ede419f0ab6cb0e98e070483ba4e0c8482de [file] [log] [blame]
Alec Mouricc445222019-10-22 10:19:17 -07001/*
2 * Copyright (C) 2015 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 LOG_TAG "Choreographer"
18//#define LOG_NDEBUG 0
19
Alec Mouri60aee1c2019-10-28 16:18:59 -070020#include <apex/choreographer.h>
Alec Mouri77a53872019-10-28 16:44:36 -070021#include <gui/DisplayEventDispatcher.h>
Alec Mouricc445222019-10-22 10:19:17 -070022#include <gui/ISurfaceComposer.h>
23#include <gui/SurfaceComposerClient.h>
24#include <utils/Looper.h>
25#include <utils/Mutex.h>
26#include <utils/Timers.h>
27
Alec Mouri60aee1c2019-10-28 16:18:59 -070028#include <cinttypes>
29#include <optional>
30#include <queue>
31#include <thread>
32
Alec Mouricc445222019-10-22 10:19:17 -070033namespace android {
34
35static inline const char* toString(bool value) {
36 return value ? "true" : "false";
37}
38
39struct FrameCallback {
40 AChoreographer_frameCallback callback;
41 AChoreographer_frameCallback64 callback64;
42 void* data;
43 nsecs_t dueTime;
44
45 inline bool operator<(const FrameCallback& rhs) const {
46 // Note that this is intentionally flipped because we want callbacks due sooner to be at
47 // the head of the queue
48 return dueTime > rhs.dueTime;
49 }
50};
51
Alec Mouri60aee1c2019-10-28 16:18:59 -070052struct RefreshRateCallback {
53 AChoreographer_refreshRateCallback callback;
54 void* data;
55};
Alec Mouricc445222019-10-22 10:19:17 -070056
57class Choreographer : public DisplayEventDispatcher, public MessageHandler {
58public:
59 void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
60 AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
Alec Mouri60aee1c2019-10-28 16:18:59 -070061 void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
62 void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb);
Alec Mouricc445222019-10-22 10:19:17 -070063
64 enum {
65 MSG_SCHEDULE_CALLBACKS = 0,
66 MSG_SCHEDULE_VSYNC = 1
67 };
68 virtual void handleMessage(const Message& message) override;
69
70 static Choreographer* getForThread();
71
72protected:
73 virtual ~Choreographer() = default;
74
75private:
76 explicit Choreographer(const sp<Looper>& looper);
77 Choreographer(const Choreographer&) = delete;
78
79 void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
80 void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
Alec Mouri60aee1c2019-10-28 16:18:59 -070081 void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
82 nsecs_t vsyncPeriod) override;
Alec Mouricc445222019-10-22 10:19:17 -070083
84 void scheduleCallbacks();
85
86 // Protected by mLock
Alec Mouri60aee1c2019-10-28 16:18:59 -070087 std::priority_queue<FrameCallback> mFrameCallbacks;
88
89 // Protected by mLock
90 std::vector<RefreshRateCallback> mRefreshRateCallbacks;
91 nsecs_t mVsyncPeriod = 0;
Alec Mouricc445222019-10-22 10:19:17 -070092
93 mutable Mutex mLock;
94
95 const sp<Looper> mLooper;
96 const std::thread::id mThreadId;
Alec Mouri60aee1c2019-10-28 16:18:59 -070097 const std::optional<PhysicalDisplayId> mInternalDisplayId;
Alec Mouricc445222019-10-22 10:19:17 -070098};
99
100
101static thread_local Choreographer* gChoreographer;
102Choreographer* Choreographer::getForThread() {
103 if (gChoreographer == nullptr) {
104 sp<Looper> looper = Looper::getForThread();
105 if (!looper.get()) {
106 ALOGW("No looper prepared for thread");
107 return nullptr;
108 }
109 gChoreographer = new Choreographer(looper);
110 status_t result = gChoreographer->initialize();
111 if (result != OK) {
112 ALOGW("Failed to initialize");
113 return nullptr;
114 }
115 }
116 return gChoreographer;
117}
118
Alec Mouri60aee1c2019-10-28 16:18:59 -0700119Choreographer::Choreographer(const sp<Looper>& looper)
120 : DisplayEventDispatcher(looper),
121 mLooper(looper),
122 mThreadId(std::this_thread::get_id()),
123 mInternalDisplayId(SurfaceComposerClient::getInternalDisplayId()) {}
Alec Mouricc445222019-10-22 10:19:17 -0700124
125void Choreographer::postFrameCallbackDelayed(
126 AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
127 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
128 FrameCallback callback{cb, cb64, data, now + delay};
129 {
130 AutoMutex _l{mLock};
Alec Mouri60aee1c2019-10-28 16:18:59 -0700131 mFrameCallbacks.push(callback);
Alec Mouricc445222019-10-22 10:19:17 -0700132 }
133 if (callback.dueTime <= now) {
134 if (std::this_thread::get_id() != mThreadId) {
135 Message m{MSG_SCHEDULE_VSYNC};
136 mLooper->sendMessage(this, m);
137 } else {
138 scheduleVsync();
139 }
140 } else {
141 Message m{MSG_SCHEDULE_CALLBACKS};
142 mLooper->sendMessageDelayed(delay, this, m);
143 }
144}
145
Alec Mouri60aee1c2019-10-28 16:18:59 -0700146void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
147 {
148 AutoMutex _l{mLock};
149 mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
150 toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
151 }
152}
153
154void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb) {
155 {
156 AutoMutex _l{mLock};
157 std::remove_if(mRefreshRateCallbacks.begin(), mRefreshRateCallbacks.end(),
158 [&](const RefreshRateCallback& callback) {
159 return cb == callback.callback;
160 });
161 if (mRefreshRateCallbacks.empty()) {
162 toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
163 }
164 }
165}
166
Alec Mouricc445222019-10-22 10:19:17 -0700167void Choreographer::scheduleCallbacks() {
168 AutoMutex _{mLock};
169 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
Alec Mouri60aee1c2019-10-28 16:18:59 -0700170 if (mFrameCallbacks.top().dueTime <= now) {
Alec Mouricc445222019-10-22 10:19:17 -0700171 ALOGV("choreographer %p ~ scheduling vsync", this);
172 scheduleVsync();
173 return;
174 }
175}
176
177// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
178// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
179// the internal display implicitly.
180void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
181 std::vector<FrameCallback> callbacks{};
182 {
183 AutoMutex _l{mLock};
184 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
Alec Mouri60aee1c2019-10-28 16:18:59 -0700185 while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
186 callbacks.push_back(mFrameCallbacks.top());
187 mFrameCallbacks.pop();
Alec Mouricc445222019-10-22 10:19:17 -0700188 }
189 }
190 for (const auto& cb : callbacks) {
191 if (cb.callback64 != nullptr) {
192 cb.callback64(timestamp, cb.data);
193 } else if (cb.callback != nullptr) {
194 cb.callback(timestamp, cb.data);
195 }
196 }
197}
198
199void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
200 ALOGV("choreographer %p ~ received hotplug event (displayId=%"
201 ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", connected=%s), ignoring.",
202 this, displayId, toString(connected));
203}
204
Alec Mouri60aee1c2019-10-28 16:18:59 -0700205// TODO(b/74619554): The PhysicalDisplayId is ignored because currently
206// Choreographer only supports dispatching VSYNC events for the internal
207// display, so as such Choreographer does not support the notion of multiple
208// displays. When multi-display choreographer is properly supported, then
209// PhysicalDisplayId should no longer be ignored.
210void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t,
211 nsecs_t vsyncPeriod) {
212 {
213 AutoMutex _l{mLock};
214 for (const auto& cb : mRefreshRateCallbacks) {
215 // Only perform the callback when the old refresh rate is different
216 // from the new refresh rate, so that we don't dispatch the callback
217 // on every single configuration change.
218 if (mVsyncPeriod != vsyncPeriod) {
219 cb.callback(vsyncPeriod, cb.data);
220 mVsyncPeriod = vsyncPeriod;
221 }
222 }
223 }
Alec Mouricc445222019-10-22 10:19:17 -0700224}
225
226void Choreographer::handleMessage(const Message& message) {
227 switch (message.what) {
228 case MSG_SCHEDULE_CALLBACKS:
229 scheduleCallbacks();
230 break;
231 case MSG_SCHEDULE_VSYNC:
232 scheduleVsync();
233 break;
234 }
235}
236
237}
238
239/* Glue for the NDK interface */
240
241using android::Choreographer;
242
243static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
244 return reinterpret_cast<Choreographer*>(choreographer);
245}
246
247static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
248 return reinterpret_cast<AChoreographer*>(choreographer);
249}
250
251AChoreographer* AChoreographer_getInstance() {
252 return Choreographer_to_AChoreographer(Choreographer::getForThread());
253}
254
255void AChoreographer_postFrameCallback(AChoreographer* choreographer,
256 AChoreographer_frameCallback callback, void* data) {
257 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
258 callback, nullptr, data, 0);
259}
260void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
261 AChoreographer_frameCallback callback, void* data, long delayMillis) {
262 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
263 callback, nullptr, data, ms2ns(delayMillis));
264}
265void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
266 AChoreographer_frameCallback64 callback, void* data) {
267 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
268 nullptr, callback, data, 0);
269}
270void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
271 AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
272 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
273 nullptr, callback, data, ms2ns(delayMillis));
274}
Alec Mouri60aee1c2019-10-28 16:18:59 -0700275void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
276 AChoreographer_refreshRateCallback callback,
277 void* data) {
278 AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
279}
280void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
281 AChoreographer_refreshRateCallback callback) {
282 AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback);
283}