blob: b7c5b2a3d4a378972b8c3edee0f6fab180eeac8d [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 Mouri271de042020-04-27 22:38:19 -070020#include <android-base/thread_annotations.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>
Alec Mouri271de042020-04-27 22:38:19 -070024#include <nativehelper/JNIHelp.h>
25#include <private/android/choreographer.h>
Alec Mouricc445222019-10-22 10:19:17 -070026#include <utils/Looper.h>
Alec Mouricc445222019-10-22 10:19:17 -070027#include <utils/Timers.h>
28
Alec Mouri60aee1c2019-10-28 16:18:59 -070029#include <cinttypes>
Alec Mouri271de042020-04-27 22:38:19 -070030#include <mutex>
Alec Mouri60aee1c2019-10-28 16:18:59 -070031#include <optional>
32#include <queue>
33#include <thread>
34
Alec Mouri271de042020-04-27 22:38:19 -070035namespace {
36struct {
37 // Global JVM that is provided by zygote
38 JavaVM* jvm = nullptr;
39 struct {
40 jclass clazz;
41 jmethodID getInstance;
42 jmethodID registerNativeChoreographerForRefreshRateCallbacks;
43 jmethodID unregisterNativeChoreographerForRefreshRateCallbacks;
44 } displayManagerGlobal;
45} gJni;
Alec Mouricc445222019-10-22 10:19:17 -070046
Alec Mouri271de042020-04-27 22:38:19 -070047// Gets the JNIEnv* for this thread, and performs one-off initialization if we
48// have never retrieved a JNIEnv* pointer before.
49JNIEnv* getJniEnv() {
50 if (gJni.jvm == nullptr) {
51 ALOGW("AChoreographer: No JVM provided!");
52 return nullptr;
53 }
54
55 JNIEnv* env = nullptr;
56 if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
57 ALOGD("Attaching thread to JVM for AChoreographer");
58 JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL};
59 jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
60 if (attachResult != JNI_OK) {
61 ALOGE("Unable to attach thread. Error: %d", attachResult);
62 return nullptr;
63 }
64 }
65 if (env == nullptr) {
66 ALOGW("AChoreographer: No JNI env available!");
67 }
68 return env;
69}
70
71inline const char* toString(bool value) {
Alec Mouricc445222019-10-22 10:19:17 -070072 return value ? "true" : "false";
73}
Alec Mouri271de042020-04-27 22:38:19 -070074} // namespace
75
76namespace android {
Alec Mouricc445222019-10-22 10:19:17 -070077
78struct FrameCallback {
79 AChoreographer_frameCallback callback;
80 AChoreographer_frameCallback64 callback64;
81 void* data;
82 nsecs_t dueTime;
83
84 inline bool operator<(const FrameCallback& rhs) const {
85 // Note that this is intentionally flipped because we want callbacks due sooner to be at
86 // the head of the queue
87 return dueTime > rhs.dueTime;
88 }
89};
90
Alec Mouri60aee1c2019-10-28 16:18:59 -070091struct RefreshRateCallback {
92 AChoreographer_refreshRateCallback callback;
93 void* data;
Alec Mouri271de042020-04-27 22:38:19 -070094 bool firstCallbackFired = false;
Alec Mouri60aee1c2019-10-28 16:18:59 -070095};
Alec Mouricc445222019-10-22 10:19:17 -070096
Alec Mouri271de042020-04-27 22:38:19 -070097class Choreographer;
98
99struct {
100 std::mutex lock;
101 std::vector<Choreographer*> ptrs GUARDED_BY(lock);
102 bool registeredToDisplayManager GUARDED_BY(lock) = false;
103
104 std::atomic<nsecs_t> mLastKnownVsync = -1;
105} gChoreographers;
106
Alec Mouricc445222019-10-22 10:19:17 -0700107class Choreographer : public DisplayEventDispatcher, public MessageHandler {
108public:
Alec Mouri271de042020-04-27 22:38:19 -0700109 explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
Alec Mouricc445222019-10-22 10:19:17 -0700110 void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
111 AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
Alec Mouri271de042020-04-27 22:38:19 -0700112 void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
113 EXCLUDES(gChoreographers.lock);
Alec Mouri33682e92020-01-10 15:11:15 -0800114 void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
Alec Mouri271de042020-04-27 22:38:19 -0700115 // Drains the queue of pending vsync periods and dispatches refresh rate
116 // updates to callbacks.
117 // The assumption is that this method is only called on a single
118 // processing thread, either by looper or by AChoreographer_handleEvents
119 void handleRefreshRateUpdates();
120 void scheduleLatestConfigRequest();
Alec Mouricc445222019-10-22 10:19:17 -0700121
122 enum {
123 MSG_SCHEDULE_CALLBACKS = 0,
Alec Mouri271de042020-04-27 22:38:19 -0700124 MSG_SCHEDULE_VSYNC = 1,
125 MSG_HANDLE_REFRESH_RATE_UPDATES = 2,
Alec Mouricc445222019-10-22 10:19:17 -0700126 };
127 virtual void handleMessage(const Message& message) override;
128
129 static Choreographer* getForThread();
Alec Mouri271de042020-04-27 22:38:19 -0700130 virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
Ady Abraham74e17562020-08-24 18:18:19 -0700131 int64_t getVsyncId() const;
132
Alec Mouricc445222019-10-22 10:19:17 -0700133
134private:
Alec Mouricc445222019-10-22 10:19:17 -0700135 Choreographer(const Choreographer&) = delete;
136
Ady Abraham74e17562020-08-24 18:18:19 -0700137 void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
138 int64_t vsyncId) override;
Alec Mouricc445222019-10-22 10:19:17 -0700139 void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
Alec Mouri60aee1c2019-10-28 16:18:59 -0700140 void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
141 nsecs_t vsyncPeriod) override;
Alec Mouri967d5d72020-08-05 12:50:03 -0700142 void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
Alec Mouricc445222019-10-22 10:19:17 -0700143
144 void scheduleCallbacks();
145
Alec Mouri271de042020-04-27 22:38:19 -0700146 std::mutex mLock;
Alec Mouricc445222019-10-22 10:19:17 -0700147 // Protected by mLock
Alec Mouri60aee1c2019-10-28 16:18:59 -0700148 std::priority_queue<FrameCallback> mFrameCallbacks;
Alec Mouri60aee1c2019-10-28 16:18:59 -0700149 std::vector<RefreshRateCallback> mRefreshRateCallbacks;
Alec Mouricc445222019-10-22 10:19:17 -0700150
Alec Mouri271de042020-04-27 22:38:19 -0700151 nsecs_t mLatestVsyncPeriod = -1;
Ady Abraham74e17562020-08-24 18:18:19 -0700152 int64_t mLastVsyncId = -1;
Alec Mouricc445222019-10-22 10:19:17 -0700153
154 const sp<Looper> mLooper;
155 const std::thread::id mThreadId;
156};
157
Alec Mouricc445222019-10-22 10:19:17 -0700158static thread_local Choreographer* gChoreographer;
159Choreographer* Choreographer::getForThread() {
160 if (gChoreographer == nullptr) {
161 sp<Looper> looper = Looper::getForThread();
162 if (!looper.get()) {
163 ALOGW("No looper prepared for thread");
164 return nullptr;
165 }
166 gChoreographer = new Choreographer(looper);
167 status_t result = gChoreographer->initialize();
168 if (result != OK) {
169 ALOGW("Failed to initialize");
170 return nullptr;
171 }
172 }
173 return gChoreographer;
174}
175
Alec Mouri60aee1c2019-10-28 16:18:59 -0700176Choreographer::Choreographer(const sp<Looper>& looper)
Alec Mouri271de042020-04-27 22:38:19 -0700177 : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp,
Alec Mouri967d5d72020-08-05 12:50:03 -0700178 ISurfaceComposer::ConfigChanged::eConfigChangedSuppress),
Alec Mouri60aee1c2019-10-28 16:18:59 -0700179 mLooper(looper),
Alec Mouri271de042020-04-27 22:38:19 -0700180 mThreadId(std::this_thread::get_id()) {
181 std::lock_guard<std::mutex> _l(gChoreographers.lock);
182 gChoreographers.ptrs.push_back(this);
183}
184
185Choreographer::~Choreographer() {
186 std::lock_guard<std::mutex> _l(gChoreographers.lock);
187 gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(),
188 gChoreographers.ptrs.end(),
189 [=](Choreographer* c) { return c == this; }),
190 gChoreographers.ptrs.end());
191 // Only poke DisplayManagerGlobal to unregister if we previously registered
192 // callbacks.
193 if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) {
194 JNIEnv* env = getJniEnv();
195 if (env == nullptr) {
196 ALOGW("JNI environment is unavailable, skipping choreographer cleanup");
197 return;
198 }
199 jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
200 gJni.displayManagerGlobal.getInstance);
201 if (dmg == nullptr) {
202 ALOGW("DMS is not initialized yet, skipping choreographer cleanup");
203 } else {
204 env->CallVoidMethod(dmg,
205 gJni.displayManagerGlobal
206 .unregisterNativeChoreographerForRefreshRateCallbacks);
207 env->DeleteLocalRef(dmg);
208 }
209 }
210}
Alec Mouricc445222019-10-22 10:19:17 -0700211
212void Choreographer::postFrameCallbackDelayed(
213 AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
214 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
215 FrameCallback callback{cb, cb64, data, now + delay};
216 {
Alec Mouri271de042020-04-27 22:38:19 -0700217 std::lock_guard<std::mutex> _l{mLock};
Alec Mouri60aee1c2019-10-28 16:18:59 -0700218 mFrameCallbacks.push(callback);
Alec Mouricc445222019-10-22 10:19:17 -0700219 }
220 if (callback.dueTime <= now) {
221 if (std::this_thread::get_id() != mThreadId) {
Alec Mouri50a931d2019-11-19 16:23:59 -0800222 if (mLooper != nullptr) {
223 Message m{MSG_SCHEDULE_VSYNC};
224 mLooper->sendMessage(this, m);
225 } else {
226 scheduleVsync();
227 }
Alec Mouricc445222019-10-22 10:19:17 -0700228 } else {
229 scheduleVsync();
230 }
231 } else {
Alec Mouri50a931d2019-11-19 16:23:59 -0800232 if (mLooper != nullptr) {
233 Message m{MSG_SCHEDULE_CALLBACKS};
234 mLooper->sendMessageDelayed(delay, this, m);
235 } else {
236 scheduleCallbacks();
237 }
Alec Mouricc445222019-10-22 10:19:17 -0700238 }
239}
240
Alec Mouri60aee1c2019-10-28 16:18:59 -0700241void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
Alec Mouri271de042020-04-27 22:38:19 -0700242 std::lock_guard<std::mutex> _l{mLock};
243 for (const auto& callback : mRefreshRateCallbacks) {
244 // Don't re-add callbacks.
245 if (cb == callback.callback && data == callback.data) {
246 return;
247 }
248 }
249 mRefreshRateCallbacks.emplace_back(
250 RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false});
251 bool needsRegistration = false;
Alec Mouri60aee1c2019-10-28 16:18:59 -0700252 {
Alec Mouri271de042020-04-27 22:38:19 -0700253 std::lock_guard<std::mutex> _l2(gChoreographers.lock);
254 needsRegistration = !gChoreographers.registeredToDisplayManager;
255 }
256 if (needsRegistration) {
257 JNIEnv* env = getJniEnv();
Alec Mouri271de042020-04-27 22:38:19 -0700258 if (env == nullptr) {
Greg Kaiserb66d04b2020-05-11 06:52:15 -0700259 ALOGW("JNI environment is unavailable, skipping registration");
Alec Mouri271de042020-04-27 22:38:19 -0700260 return;
261 }
Greg Kaiserb66d04b2020-05-11 06:52:15 -0700262 jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
263 gJni.displayManagerGlobal.getInstance);
Alec Mouri271de042020-04-27 22:38:19 -0700264 if (dmg == nullptr) {
265 ALOGW("DMS is not initialized yet: skipping registration");
266 return;
267 } else {
268 env->CallVoidMethod(dmg,
269 gJni.displayManagerGlobal
270 .registerNativeChoreographerForRefreshRateCallbacks,
271 reinterpret_cast<int64_t>(this));
272 env->DeleteLocalRef(dmg);
273 {
274 std::lock_guard<std::mutex> _l2(gChoreographers.lock);
275 gChoreographers.registeredToDisplayManager = true;
Alec Mouri33682e92020-01-10 15:11:15 -0800276 }
277 }
Alec Mouri271de042020-04-27 22:38:19 -0700278 } else {
279 scheduleLatestConfigRequest();
Alec Mouri60aee1c2019-10-28 16:18:59 -0700280 }
281}
282
Alec Mouri33682e92020-01-10 15:11:15 -0800283void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb,
284 void* data) {
Alec Mouri271de042020-04-27 22:38:19 -0700285 std::lock_guard<std::mutex> _l{mLock};
286 mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
287 mRefreshRateCallbacks.end(),
288 [&](const RefreshRateCallback& callback) {
289 return cb == callback.callback &&
290 data == callback.data;
291 }),
292 mRefreshRateCallbacks.end());
293}
294
295void Choreographer::scheduleLatestConfigRequest() {
296 if (mLooper != nullptr) {
297 Message m{MSG_HANDLE_REFRESH_RATE_UPDATES};
298 mLooper->sendMessage(this, m);
299 } else {
300 // If the looper thread is detached from Choreographer, then refresh rate
301 // changes will be handled in AChoreographer_handlePendingEvents, so we
Alec Mouri967d5d72020-08-05 12:50:03 -0700302 // need to wake up the looper thread by writing to the write-end of the
303 // socket the looper is listening on.
304 // Fortunately, these events are small so sending packets across the
305 // socket should be atomic across processes.
306 DisplayEventReceiver::Event event;
307 event.header = DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
308 PhysicalDisplayId(0), systemTime()};
309 injectEvent(event);
Alec Mouri60aee1c2019-10-28 16:18:59 -0700310 }
311}
312
Alec Mouricc445222019-10-22 10:19:17 -0700313void Choreographer::scheduleCallbacks() {
Alec Mouri134266b2020-03-03 19:22:29 -0800314 const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
315 nsecs_t dueTime;
316 {
Alec Mouri271de042020-04-27 22:38:19 -0700317 std::lock_guard<std::mutex> _l{mLock};
Alec Mouri134266b2020-03-03 19:22:29 -0800318 // If there are no pending callbacks then don't schedule a vsync
319 if (mFrameCallbacks.empty()) {
320 return;
321 }
322 dueTime = mFrameCallbacks.top().dueTime;
323 }
324
325 if (dueTime <= now) {
Alec Mouricc445222019-10-22 10:19:17 -0700326 ALOGV("choreographer %p ~ scheduling vsync", this);
327 scheduleVsync();
328 return;
329 }
330}
331
Alec Mouri271de042020-04-27 22:38:19 -0700332void Choreographer::handleRefreshRateUpdates() {
333 std::vector<RefreshRateCallback> callbacks{};
334 const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load();
335 const nsecs_t lastPeriod = mLatestVsyncPeriod;
336 if (pendingPeriod > 0) {
337 mLatestVsyncPeriod = pendingPeriod;
338 }
339 {
340 std::lock_guard<std::mutex> _l{mLock};
341 for (auto& cb : mRefreshRateCallbacks) {
342 callbacks.push_back(cb);
343 cb.firstCallbackFired = true;
344 }
345 }
346
347 for (auto& cb : callbacks) {
348 if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) {
349 cb.callback(pendingPeriod, cb.data);
350 }
351 }
352}
353
Alec Mouricc445222019-10-22 10:19:17 -0700354// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
355// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
356// the internal display implicitly.
Ady Abraham74e17562020-08-24 18:18:19 -0700357void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, int64_t vsyncId) {
Alec Mouricc445222019-10-22 10:19:17 -0700358 std::vector<FrameCallback> callbacks{};
359 {
Alec Mouri271de042020-04-27 22:38:19 -0700360 std::lock_guard<std::mutex> _l{mLock};
Alec Mouricc445222019-10-22 10:19:17 -0700361 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
Alec Mouri60aee1c2019-10-28 16:18:59 -0700362 while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
363 callbacks.push_back(mFrameCallbacks.top());
364 mFrameCallbacks.pop();
Alec Mouricc445222019-10-22 10:19:17 -0700365 }
366 }
Ady Abraham74e17562020-08-24 18:18:19 -0700367 mLastVsyncId = vsyncId;
Alec Mouricc445222019-10-22 10:19:17 -0700368 for (const auto& cb : callbacks) {
369 if (cb.callback64 != nullptr) {
370 cb.callback64(timestamp, cb.data);
371 } else if (cb.callback != nullptr) {
372 cb.callback(timestamp, cb.data);
373 }
374 }
375}
376
377void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
Marin Shalamanova524a092020-07-27 21:39:55 +0200378 ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.",
379 this, to_string(displayId).c_str(), toString(connected));
Alec Mouricc445222019-10-22 10:19:17 -0700380}
381
Alec Mouri60aee1c2019-10-28 16:18:59 -0700382// TODO(b/74619554): The PhysicalDisplayId is ignored because currently
383// Choreographer only supports dispatching VSYNC events for the internal
384// display, so as such Choreographer does not support the notion of multiple
385// displays. When multi-display choreographer is properly supported, then
386// PhysicalDisplayId should no longer be ignored.
Alec Mouri271de042020-04-27 22:38:19 -0700387void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, int32_t configId,
Alec Mouri967d5d72020-08-05 12:50:03 -0700388 nsecs_t) {
Marin Shalamanova524a092020-07-27 21:39:55 +0200389 ALOGV("choreographer %p ~ received config change event (displayId=%s, configId=%d).",
390 this, to_string(displayId).c_str(), configId);
Alec Mouri967d5d72020-08-05 12:50:03 -0700391}
Alec Mouri271de042020-04-27 22:38:19 -0700392
Alec Mouri967d5d72020-08-05 12:50:03 -0700393void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) {
394 ALOGV("choreographer %p ~ received null event.", this);
395 handleRefreshRateUpdates();
Alec Mouricc445222019-10-22 10:19:17 -0700396}
397
398void Choreographer::handleMessage(const Message& message) {
399 switch (message.what) {
400 case MSG_SCHEDULE_CALLBACKS:
401 scheduleCallbacks();
402 break;
403 case MSG_SCHEDULE_VSYNC:
404 scheduleVsync();
405 break;
Alec Mouri271de042020-04-27 22:38:19 -0700406 case MSG_HANDLE_REFRESH_RATE_UPDATES:
407 handleRefreshRateUpdates();
408 break;
Alec Mouricc445222019-10-22 10:19:17 -0700409 }
410}
411
Ady Abraham74e17562020-08-24 18:18:19 -0700412int64_t Choreographer::getVsyncId() const {
413 return mLastVsyncId;
414}
415
Alec Mouri271de042020-04-27 22:38:19 -0700416} // namespace android
Alec Mouri50a931d2019-11-19 16:23:59 -0800417using namespace android;
Alec Mouricc445222019-10-22 10:19:17 -0700418
419static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
420 return reinterpret_cast<Choreographer*>(choreographer);
421}
422
Ady Abraham74e17562020-08-24 18:18:19 -0700423static inline const Choreographer* AChoreographer_to_Choreographer(
424 const AChoreographer* choreographer) {
425 return reinterpret_cast<const Choreographer*>(choreographer);
426}
427
Alec Mouri271de042020-04-27 22:38:19 -0700428// Glue for private C api
429namespace android {
430void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
431 std::lock_guard<std::mutex> _l(gChoreographers.lock);
432 gChoreographers.mLastKnownVsync.store(vsyncPeriod);
433 for (auto c : gChoreographers.ptrs) {
434 c->scheduleLatestConfigRequest();
435 }
436}
437
438void AChoreographer_initJVM(JNIEnv* env) {
439 env->GetJavaVM(&gJni.jvm);
440 // Now we need to find the java classes.
441 jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal");
442 gJni.displayManagerGlobal.clazz = static_cast<jclass>(env->NewGlobalRef(dmgClass));
443 gJni.displayManagerGlobal.getInstance =
444 env->GetStaticMethodID(dmgClass, "getInstance",
445 "()Landroid/hardware/display/DisplayManagerGlobal;");
446 gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks =
447 env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V");
448 gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks =
449 env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks",
450 "()V");
451}
452
453AChoreographer* AChoreographer_routeGetInstance() {
454 return AChoreographer_getInstance();
455}
456void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
457 AChoreographer_frameCallback callback, void* data) {
458 return AChoreographer_postFrameCallback(choreographer, callback, data);
459}
460void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
461 AChoreographer_frameCallback callback, void* data,
462 long delayMillis) {
463 return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis);
464}
465void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
466 AChoreographer_frameCallback64 callback, void* data) {
467 return AChoreographer_postFrameCallback64(choreographer, callback, data);
468}
469void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
470 AChoreographer_frameCallback64 callback,
471 void* data, uint32_t delayMillis) {
472 return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
473}
474void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
475 AChoreographer_refreshRateCallback callback,
476 void* data) {
477 return AChoreographer_registerRefreshRateCallback(choreographer, callback, data);
478}
479void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
480 AChoreographer_refreshRateCallback callback,
481 void* data) {
482 return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
483}
484
Ady Abraham74e17562020-08-24 18:18:19 -0700485int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) {
486 return AChoreographer_to_Choreographer(choreographer)->getVsyncId();
487}
488
Alec Mouri271de042020-04-27 22:38:19 -0700489} // namespace android
490
491/* Glue for the NDK interface */
492
Alec Mouricc445222019-10-22 10:19:17 -0700493static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
494 return reinterpret_cast<AChoreographer*>(choreographer);
495}
496
497AChoreographer* AChoreographer_getInstance() {
498 return Choreographer_to_AChoreographer(Choreographer::getForThread());
499}
500
501void AChoreographer_postFrameCallback(AChoreographer* choreographer,
502 AChoreographer_frameCallback callback, void* data) {
503 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
504 callback, nullptr, data, 0);
505}
506void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
507 AChoreographer_frameCallback callback, void* data, long delayMillis) {
508 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
509 callback, nullptr, data, ms2ns(delayMillis));
510}
511void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
512 AChoreographer_frameCallback64 callback, void* data) {
513 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
514 nullptr, callback, data, 0);
515}
516void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
517 AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
518 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
519 nullptr, callback, data, ms2ns(delayMillis));
520}
Alec Mouri60aee1c2019-10-28 16:18:59 -0700521void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
522 AChoreographer_refreshRateCallback callback,
523 void* data) {
524 AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
525}
526void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
Alec Mouri33682e92020-01-10 15:11:15 -0800527 AChoreographer_refreshRateCallback callback,
528 void* data) {
529 AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data);
Alec Mouri60aee1c2019-10-28 16:18:59 -0700530}
Alec Mouri50a931d2019-11-19 16:23:59 -0800531
532AChoreographer* AChoreographer_create() {
533 Choreographer* choreographer = new Choreographer(nullptr);
534 status_t result = choreographer->initialize();
535 if (result != OK) {
536 ALOGW("Failed to initialize");
537 return nullptr;
538 }
539 return Choreographer_to_AChoreographer(choreographer);
540}
541
542void AChoreographer_destroy(AChoreographer* choreographer) {
543 if (choreographer == nullptr) {
544 return;
545 }
546
547 delete AChoreographer_to_Choreographer(choreographer);
548}
549
Alec Mouri921b2772020-02-05 19:03:28 -0800550int AChoreographer_getFd(const AChoreographer* choreographer) {
Alec Mouri50a931d2019-11-19 16:23:59 -0800551 return AChoreographer_to_Choreographer(choreographer)->getFd();
552}
553
554void AChoreographer_handlePendingEvents(AChoreographer* choreographer, void* data) {
555 // Pass dummy fd and events args to handleEvent, since the underlying
556 // DisplayEventDispatcher doesn't need them outside of validating that a
557 // Looper instance didn't break, but these args circumvent those checks.
Alec Mouri271de042020-04-27 22:38:19 -0700558 Choreographer* impl = AChoreographer_to_Choreographer(choreographer);
559 impl->handleEvent(-1, Looper::EVENT_INPUT, data);
Alec Mouri50a931d2019-11-19 16:23:59 -0800560}