blob: cfed58373a74771e1522f2a753d16b075d4dd2a1 [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};
Alec Mourib7ebad62020-01-08 08:12:01 -0800157 mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
158 mRefreshRateCallbacks.end(),
159 [&](const RefreshRateCallback& callback) {
160 return cb == callback.callback;
161 }));
Alec Mouri60aee1c2019-10-28 16:18:59 -0700162 if (mRefreshRateCallbacks.empty()) {
163 toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
164 }
165 }
166}
167
Alec Mouricc445222019-10-22 10:19:17 -0700168void Choreographer::scheduleCallbacks() {
169 AutoMutex _{mLock};
170 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
Alec Mouri60aee1c2019-10-28 16:18:59 -0700171 if (mFrameCallbacks.top().dueTime <= now) {
Alec Mouricc445222019-10-22 10:19:17 -0700172 ALOGV("choreographer %p ~ scheduling vsync", this);
173 scheduleVsync();
174 return;
175 }
176}
177
178// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
179// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
180// the internal display implicitly.
181void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
182 std::vector<FrameCallback> callbacks{};
183 {
184 AutoMutex _l{mLock};
185 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
Alec Mouri60aee1c2019-10-28 16:18:59 -0700186 while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
187 callbacks.push_back(mFrameCallbacks.top());
188 mFrameCallbacks.pop();
Alec Mouricc445222019-10-22 10:19:17 -0700189 }
190 }
191 for (const auto& cb : callbacks) {
192 if (cb.callback64 != nullptr) {
193 cb.callback64(timestamp, cb.data);
194 } else if (cb.callback != nullptr) {
195 cb.callback(timestamp, cb.data);
196 }
197 }
198}
199
200void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
201 ALOGV("choreographer %p ~ received hotplug event (displayId=%"
202 ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", connected=%s), ignoring.",
203 this, displayId, toString(connected));
204}
205
Alec Mouri60aee1c2019-10-28 16:18:59 -0700206// TODO(b/74619554): The PhysicalDisplayId is ignored because currently
207// Choreographer only supports dispatching VSYNC events for the internal
208// display, so as such Choreographer does not support the notion of multiple
209// displays. When multi-display choreographer is properly supported, then
210// PhysicalDisplayId should no longer be ignored.
211void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t,
212 nsecs_t vsyncPeriod) {
213 {
214 AutoMutex _l{mLock};
215 for (const auto& cb : mRefreshRateCallbacks) {
216 // Only perform the callback when the old refresh rate is different
217 // from the new refresh rate, so that we don't dispatch the callback
218 // on every single configuration change.
219 if (mVsyncPeriod != vsyncPeriod) {
220 cb.callback(vsyncPeriod, cb.data);
221 mVsyncPeriod = vsyncPeriod;
222 }
223 }
224 }
Alec Mouricc445222019-10-22 10:19:17 -0700225}
226
227void Choreographer::handleMessage(const Message& message) {
228 switch (message.what) {
229 case MSG_SCHEDULE_CALLBACKS:
230 scheduleCallbacks();
231 break;
232 case MSG_SCHEDULE_VSYNC:
233 scheduleVsync();
234 break;
235 }
236}
237
238}
239
240/* Glue for the NDK interface */
241
242using android::Choreographer;
243
244static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
245 return reinterpret_cast<Choreographer*>(choreographer);
246}
247
248static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
249 return reinterpret_cast<AChoreographer*>(choreographer);
250}
251
252AChoreographer* AChoreographer_getInstance() {
253 return Choreographer_to_AChoreographer(Choreographer::getForThread());
254}
255
256void AChoreographer_postFrameCallback(AChoreographer* choreographer,
257 AChoreographer_frameCallback callback, void* data) {
258 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
259 callback, nullptr, data, 0);
260}
261void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
262 AChoreographer_frameCallback callback, void* data, long delayMillis) {
263 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
264 callback, nullptr, data, ms2ns(delayMillis));
265}
266void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
267 AChoreographer_frameCallback64 callback, void* data) {
268 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
269 nullptr, callback, data, 0);
270}
271void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
272 AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
273 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
274 nullptr, callback, data, ms2ns(delayMillis));
275}
Alec Mouri60aee1c2019-10-28 16:18:59 -0700276void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
277 AChoreographer_refreshRateCallback callback,
278 void* data) {
279 AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
280}
281void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
282 AChoreographer_refreshRateCallback callback) {
283 AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback);
284}