1313#include " flutter/fml/platform/android/scoped_java_ref.h"
1414#include " flutter/fml/size.h"
1515#include " flutter/fml/trace_event.h"
16+ #include " flutter/shell/platform/android/android_choreographer.h"
1617
1718namespace flutter {
1819
1920static fml::jni::ScopedJavaGlobalRef<jclass>* g_vsync_waiter_class = nullptr ;
2021static jmethodID g_async_wait_for_vsync_method_ = nullptr ;
22+ static std::atomic_uint g_refresh_rate_ = 60 ;
2123
2224VsyncWaiterAndroid::VsyncWaiterAndroid (flutter::TaskRunners task_runners)
23- : VsyncWaiter(std::move(task_runners)) {}
25+ : VsyncWaiter(std::move(task_runners)),
26+ use_ndk_choreographer_ (
27+ AndroidChoreographer::ShouldUseNDKChoreographer ()) {}
2428
2529VsyncWaiterAndroid::~VsyncWaiterAndroid () = default ;
2630
2731// |VsyncWaiter|
2832void VsyncWaiterAndroid::AwaitVSync () {
29- auto * weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this ());
30- jlong java_baton = reinterpret_cast <jlong>(weak_this);
31-
32- task_runners_.GetPlatformTaskRunner ()->PostTask ([java_baton]() {
33- JNIEnv* env = fml::jni::AttachCurrentThread ();
34- env->CallStaticVoidMethod (g_vsync_waiter_class->obj (), //
35- g_async_wait_for_vsync_method_, //
36- java_baton //
37- );
38- });
33+ if (use_ndk_choreographer_) {
34+ auto * weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this ());
35+ fml::TaskRunner::RunNowOrPostTask (
36+ task_runners_.GetUITaskRunner (), [weak_this]() {
37+ AndroidChoreographer::PostFrameCallback (&OnVsyncFromNDK, weak_this);
38+ });
39+ } else {
40+ // TODO(99798): Remove it when we drop support for API level < 29.
41+ auto * weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this ());
42+ jlong java_baton = reinterpret_cast <jlong>(weak_this);
43+ task_runners_.GetPlatformTaskRunner ()->PostTask ([java_baton]() {
44+ JNIEnv* env = fml::jni::AttachCurrentThread ();
45+ env->CallStaticVoidMethod (g_vsync_waiter_class->obj (), //
46+ g_async_wait_for_vsync_method_, //
47+ java_baton //
48+ );
49+ });
50+ }
51+ }
52+
53+ // static
54+ void VsyncWaiterAndroid::OnVsyncFromNDK (int64_t frame_nanos, void * data) {
55+ TRACE_EVENT0 (" flutter" , " VSYNC" );
56+
57+ auto frame_time = fml::TimePoint::FromEpochDelta (
58+ fml::TimeDelta::FromNanoseconds (frame_nanos));
59+ auto now = fml::TimePoint::Now ();
60+ if (frame_time > now) {
61+ frame_time = now;
62+ }
63+ auto target_time = frame_time + fml::TimeDelta::FromNanoseconds (
64+ 1000000000.0 / g_refresh_rate_);
65+ auto * weak_this = reinterpret_cast <std::weak_ptr<VsyncWaiter>*>(data);
66+ ConsumePendingCallback (weak_this, frame_time, target_time);
3967}
4068
4169// static
42- void VsyncWaiterAndroid::OnNativeVsync (JNIEnv* env,
43- jclass jcaller,
44- jlong frameDelayNanos,
45- jlong refreshPeriodNanos,
46- jlong java_baton) {
70+ void VsyncWaiterAndroid::OnVsyncFromJava (JNIEnv* env,
71+ jclass jcaller,
72+ jlong frameDelayNanos,
73+ jlong refreshPeriodNanos,
74+ jlong java_baton) {
4775 TRACE_EVENT0 (" flutter" , " VSYNC" );
4876
4977 auto frame_time =
5078 fml::TimePoint::Now () - fml::TimeDelta::FromNanoseconds (frameDelayNanos);
5179 auto target_time =
5280 frame_time + fml::TimeDelta::FromNanoseconds (refreshPeriodNanos);
5381
54- ConsumePendingCallback (java_baton, frame_time, target_time);
82+ auto * weak_this = reinterpret_cast <std::weak_ptr<VsyncWaiter>*>(java_baton);
83+ ConsumePendingCallback (weak_this, frame_time, target_time);
5584}
5685
5786// static
5887void VsyncWaiterAndroid::ConsumePendingCallback (
59- jlong java_baton ,
88+ std::weak_ptr<VsyncWaiter>* weak_this ,
6089 fml::TimePoint frame_start_time,
6190 fml::TimePoint frame_target_time) {
62- auto * weak_this = reinterpret_cast <std::weak_ptr<VsyncWaiter>*>(java_baton);
6391 auto shared_this = weak_this->lock ();
6492 delete weak_this;
6593
@@ -68,13 +96,27 @@ void VsyncWaiterAndroid::ConsumePendingCallback(
6896 }
6997}
7098
99+ // static
100+ void VsyncWaiterAndroid::OnUpdateRefreshRate (JNIEnv* env,
101+ jclass jcaller,
102+ jfloat refresh_rate) {
103+ FML_DCHECK (refresh_rate > 0 );
104+ g_refresh_rate_ = static_cast <uint>(refresh_rate);
105+ }
106+
71107// static
72108bool VsyncWaiterAndroid::Register (JNIEnv* env) {
73- static const JNINativeMethod methods[] = {{
74- .name = " nativeOnVsync" ,
75- .signature = " (JJJ)V" ,
76- .fnPtr = reinterpret_cast <void *>(&OnNativeVsync),
77- }};
109+ static const JNINativeMethod methods[] = {
110+ {
111+ .name = " nativeOnVsync" ,
112+ .signature = " (JJJ)V" ,
113+ .fnPtr = reinterpret_cast <void *>(&OnVsyncFromJava),
114+ },
115+ {
116+ .name = " nativeUpdateRefreshRate" ,
117+ .signature = " (F)V" ,
118+ .fnPtr = reinterpret_cast <void *>(&OnUpdateRefreshRate),
119+ }};
78120
79121 jclass clazz = env->FindClass (" io/flutter/embedding/engine/FlutterJNI" );
80122
@@ -83,12 +125,10 @@ bool VsyncWaiterAndroid::Register(JNIEnv* env) {
83125 }
84126
85127 g_vsync_waiter_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz);
86-
87128 FML_CHECK (!g_vsync_waiter_class->is_null ());
88129
89130 g_async_wait_for_vsync_method_ = env->GetStaticMethodID (
90131 g_vsync_waiter_class->obj (), " asyncWaitForVsync" , " (J)V" );
91-
92132 FML_CHECK (g_async_wait_for_vsync_method_ != nullptr );
93133
94134 return env->RegisterNatives (clazz, methods, fml::size (methods)) == 0 ;
0 commit comments