From 3b950c7e4e84d55bde82875c8fd240214948637e Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 15 Nov 2021 20:45:53 -0800 Subject: [PATCH 1/2] Use AChoreographer methods to get refresh rate updates when available --- .../flutter/embedding/engine/FlutterJNI.java | 36 +++++++--- .../android/io/flutter/view/VsyncWaiter.java | 2 - .../platform/android/vsync_waiter_android.cc | 72 ++++++++++++++++++- 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index ac484f21f4601..824869c1f0824 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -216,17 +216,21 @@ public static String getObservatoryUri() { return observatoryUri; } + /** + * Notifies the engine about the refresh rate of the display when the API level is below 30. + * + *

For API 30 and above, this value is ignored. + * + *

Calling this method multiple times will update the refresh rate for the next vsync period. + * However, callers should avoid calling {@link android.view.Display#getRefreshRate} frequently, + * since it is expensive on some vendor implementations. + * + * @param refreshRateFPS The refresh rate in nanoseconds. + */ public static void setRefreshRateFPS(float refreshRateFPS) { - if (FlutterJNI.setRefreshRateFPSCalled) { - Log.w(TAG, "FlutterJNI.setRefreshRateFPS called more than once"); - } - FlutterJNI.refreshRateFPS = refreshRateFPS; - FlutterJNI.setRefreshRateFPSCalled = true; } - private static boolean setRefreshRateFPSCalled = false; - // TODO(mattcarroll): add javadocs public static void setAsyncWaitForVsyncDelegate(@Nullable AsyncWaitForVsyncDelegate delegate) { asyncWaitForVsyncDelegate = delegate; @@ -243,9 +247,20 @@ private static void asyncWaitForVsync(final long cookie) { } } - // TODO(mattcarroll): add javadocs + /** + * Notifies the engine that the Choreographer has signaled a vsync. + * + * @param frameDelayNanos The time in nanoseconds when the frame started being rendered, + * subtracted from the {@link System#nanoTime} timebase. + * @param fallbackRefreshPeriodNanos The display refresh period in nanoseconds. On API30 and + * above, this parameter will be ignored. For other API levels, a best estimate must be + * provided, e.g. the refresh rate at initialization of the application. Callers should avoid + * calling {@link android.view.Display#getRefreshRate} frequently, since it is expensive on + * some vendor implementations. + * @param cookie An opaque handle to the C++ VSyncWaiter object. + */ public static native void nativeOnVsync( - long frameDelayNanos, long refreshPeriodNanos, long cookie); + long frameDelayNanos, long fallbackRefreshPeriodNanos, long cookie); // TODO(mattcarroll): add javadocs @NonNull @@ -337,8 +352,7 @@ public long performNativeAttach(@NonNull FlutterJNI flutterJNI) { * #attachToNative()}. * *

Static methods that should be only called once such as {@link #init(Context, String[], - * String, String, String, long)} or {@link #setRefreshRateFPS(float)} shouldn't be called again - * on the spawned FlutterJNI instance. + * String, String, String, long)} shouldn't be called again on the spawned FlutterJNI instance. */ @UiThread @NonNull diff --git a/shell/platform/android/io/flutter/view/VsyncWaiter.java b/shell/platform/android/io/flutter/view/VsyncWaiter.java index 714511f5bb3fa..0578d0ca22740 100644 --- a/shell/platform/android/io/flutter/view/VsyncWaiter.java +++ b/shell/platform/android/io/flutter/view/VsyncWaiter.java @@ -49,8 +49,6 @@ private VsyncWaiter(float fps) { public void init() { FlutterJNI.setAsyncWaitForVsyncDelegate(asyncWaitForVsyncDelegate); - - // TODO(mattcarroll): look into moving FPS reporting to a plugin FlutterJNI.setRefreshRateFPS(fps); } } diff --git a/shell/platform/android/vsync_waiter_android.cc b/shell/platform/android/vsync_waiter_android.cc index 1a69705f634d4..0ea109f5c3d26 100644 --- a/shell/platform/android/vsync_waiter_android.cc +++ b/shell/platform/android/vsync_waiter_android.cc @@ -9,6 +9,7 @@ #include "flutter/common/task_runners.h" #include "flutter/fml/logging.h" +#include "flutter/fml/native_library.h" #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/size.h" @@ -18,11 +19,75 @@ namespace flutter { static fml::jni::ScopedJavaGlobalRef* g_vsync_waiter_class = nullptr; static jmethodID g_async_wait_for_vsync_method_ = nullptr; +static std::optional g_vsync_period_nanos_ = std::nullopt; + +namespace { +// Only avialalbe on API 24+ +typedef void AChoreographer; + +// Must be called from the Platform thread. +AChoreographer* GetAChoreographer() { + auto libandroid = fml::NativeLibrary::Create("libandroid.so"); + FML_CHECK(libandroid); + auto get_instance_fn = libandroid->ResolveFunction( + "AChoreographer_getInstance"); + if (get_instance_fn) { + return get_instance_fn.value()(); + } + return nullptr; +} + +// Only available on API 30+ +typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, + void* data); +void HandleRefreshRateChanged(int64_t vsyncPeriodNanos, void* data) { + g_vsync_period_nanos_ = vsyncPeriodNanos; +} + +// The data parameter will not be accessed, but will serve as an identifier for +// unregistering. +void ListenToRefreshRateChanges(void* data) { + auto libandroid = fml::NativeLibrary::Create("libandroid.so"); + FML_CHECK(libandroid); + auto register_refresh_rate_callback_fn = libandroid->ResolveFunction( + "AChoreographer_registerRefreshRateCallback"); + + if (register_refresh_rate_callback_fn) { + auto choreographer = GetAChoreographer(); + FML_CHECK(choreographer); + register_refresh_rate_callback_fn.value()(choreographer, + &HandleRefreshRateChanged, data); + } +} + +// The data parmaeter must be the same as the pointer passed to +// ListenToRefreshRateChanges. +void StopListeningToRefreshRateChanges(void* data) { + auto libandroid = fml::NativeLibrary::Create("libandroid.so"); + FML_CHECK(libandroid); + auto unregister_refresh_rate_callback_fn = + libandroid->ResolveFunction( + "AChoreographer_unregisterRefreshRateCallback"); + + if (unregister_refresh_rate_callback_fn) { + auto choreographer = GetAChoreographer(); + FML_CHECK(choreographer); + unregister_refresh_rate_callback_fn.value()( + choreographer, &HandleRefreshRateChanged, data); + } +} +} // namespace VsyncWaiterAndroid::VsyncWaiterAndroid(flutter::TaskRunners task_runners) - : VsyncWaiter(std::move(task_runners)) {} + : VsyncWaiter(std::move(task_runners)) { + ListenToRefreshRateChanges(this); +} -VsyncWaiterAndroid::~VsyncWaiterAndroid() = default; +VsyncWaiterAndroid::~VsyncWaiterAndroid() { + StopListeningToRefreshRateChanges(this); +} // |VsyncWaiter| void VsyncWaiterAndroid::AwaitVSync() { @@ -49,7 +114,8 @@ void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env, auto frame_time = fml::TimePoint::Now() - fml::TimeDelta::FromNanoseconds(frameDelayNanos); auto target_time = - frame_time + fml::TimeDelta::FromNanoseconds(refreshPeriodNanos); + frame_time + fml::TimeDelta::FromNanoseconds( + g_vsync_period_nanos_.value_or(refreshPeriodNanos)); ConsumePendingCallback(java_baton, frame_time, target_time); } From 5a75414ced6e123ea8a0dddfc07168c87732c762 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 16 Nov 2021 20:39:35 -0800 Subject: [PATCH 2/2] Refactor, make sure Android displays correctly report refresh rates --- ci/licenses_golden/licenses_flutter | 4 + shell/common/display.h | 4 +- shell/platform/android/BUILD.gn | 4 + shell/platform/android/android_display.cc | 16 ++++ shell/platform/android/android_display.h | 37 +++++++++ .../platform/android/android_shell_holder.cc | 5 +- .../android/display_refresh_listener.cc | 79 ++++++++++++++++++ .../android/display_refresh_listener.h | 44 ++++++++++ .../platform/android/vsync_waiter_android.cc | 80 +++---------------- shell/platform/android/vsync_waiter_android.h | 15 +++- 10 files changed, 215 insertions(+), 73 deletions(-) create mode 100644 shell/platform/android/android_display.cc create mode 100644 shell/platform/android/android_display.h create mode 100644 shell/platform/android/display_refresh_listener.cc create mode 100644 shell/platform/android/display_refresh_listener.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 92e593af6f793..a8dd390e6c79e 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -773,6 +773,8 @@ FILE: ../../../flutter/shell/platform/android/AndroidManifest.xml FILE: ../../../flutter/shell/platform/android/android_context_gl.cc FILE: ../../../flutter/shell/platform/android/android_context_gl.h FILE: ../../../flutter/shell/platform/android/android_context_gl_unittests.cc +FILE: ../../../flutter/shell/platform/android/android_display.cc +FILE: ../../../flutter/shell/platform/android/android_display.h FILE: ../../../flutter/shell/platform/android/android_environment_gl.cc FILE: ../../../flutter/shell/platform/android/android_environment_gl.h FILE: ../../../flutter/shell/platform/android/android_exports.lst @@ -791,6 +793,8 @@ FILE: ../../../flutter/shell/platform/android/apk_asset_provider.cc FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h FILE: ../../../flutter/shell/platform/android/context/android_context.cc FILE: ../../../flutter/shell/platform/android/context/android_context.h +FILE: ../../../flutter/shell/platform/android/display_refresh_listener.cc +FILE: ../../../flutter/shell/platform/android/display_refresh_listener.h FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.h FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc diff --git a/shell/common/display.h b/shell/common/display.h index 2c7e0fa88ff73..68b7995fba5ac 100644 --- a/shell/common/display.h +++ b/shell/common/display.h @@ -36,11 +36,11 @@ class Display { explicit Display(double refresh_rate) : display_id_({}), refresh_rate_(refresh_rate) {} - ~Display() = default; + virtual ~Display() = default; // Get the display's maximum refresh rate in the unit of frame per second. // Return `kUnknownDisplayRefreshRate` if the refresh rate is unknown. - double GetRefreshRate() const { return refresh_rate_; } + virtual double GetRefreshRate() const { return refresh_rate_; } /// Returns the `DisplayId` of the display. std::optional GetDisplayId() const { return display_id_; } diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 46b6d148a12d9..4ad5ffc211c0a 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -64,6 +64,8 @@ source_set("flutter_shell_native_src") { "$root_build_dir/flutter_icu/icudtl.o", "android_context_gl.cc", "android_context_gl.h", + "android_display.cc", + "android_display.h", "android_environment_gl.cc", "android_environment_gl.h", "android_external_texture_gl.cc", @@ -76,6 +78,8 @@ source_set("flutter_shell_native_src") { "android_surface_software.h", "apk_asset_provider.cc", "apk_asset_provider.h", + "display_refresh_listener.cc", + "display_refresh_listener.h", "flutter_main.cc", "flutter_main.h", "library_loader.cc", diff --git a/shell/platform/android/android_display.cc b/shell/platform/android/android_display.cc new file mode 100644 index 0000000000000..5002832ecf35a --- /dev/null +++ b/shell/platform/android/android_display.cc @@ -0,0 +1,16 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/android/android_display.h" + +namespace flutter { + +AndroidDisplay::AndroidDisplay(double refresh_rate) + : Display(refresh_rate), listener_(*this), refresh_rate_(refresh_rate) {} + +void AndroidDisplay::OnDisplayRefreshUpdated(int64_t vsync_period_nanos) { + refresh_rate_ = 1000000000 / vsync_period_nanos; +} + +} // namespace flutter diff --git a/shell/platform/android/android_display.h b/shell/platform/android/android_display.h new file mode 100644 index 0000000000000..401dea745ac4f --- /dev/null +++ b/shell/platform/android/android_display.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_DISPLAY_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_DISPLAY_H_ + +#include + +#include "flutter/fml/macros.h" +#include "flutter/shell/common/display.h" +#include "flutter/shell/platform/android/display_refresh_listener.h" + +namespace flutter { + +/// A |Display| that listens to refresh rate changes. +class AndroidDisplay : public Display, public DisplayRefreshListener::Delegate { + public: + explicit AndroidDisplay(double refresh_rate); + ~AndroidDisplay() = default; + + // |Display| + double GetRefreshRate() const override { return refresh_rate_; }; + + private: + // |DisplayRefreshListener::Delegate| + void OnDisplayRefreshUpdated(int64_t vsync_period_nanos) override; + + DisplayRefreshListener listener_; + double refresh_rate_; + + FML_DISALLOW_COPY_AND_ASSIGN(AndroidDisplay); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_DISPLAY_H_ diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index b85db32a6d1cc..48447294e5b72 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -25,6 +25,7 @@ #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/android/android_display.h" #include "flutter/shell/platform/android/android_image_generator.h" #include "flutter/shell/platform/android/context/android_context.h" #include "flutter/shell/platform/android/platform_view_android.h" @@ -61,7 +62,7 @@ AndroidShellHolder::AndroidShellHolder( .enable_software_rendering // use software rendering ); weak_platform_view = platform_view_android->GetWeakPtr(); - auto display = Display(jni_facade->GetDisplayRefreshRate()); + auto display = AndroidDisplay(jni_facade->GetDisplayRefreshRate()); shell.OnDisplayUpdates(DisplayUpdateType::kStartup, {display}); return platform_view_android; }; @@ -209,7 +210,7 @@ std::unique_ptr AndroidShellHolder::Spawn( android_context // Android context ); weak_platform_view = platform_view_android->GetWeakPtr(); - auto display = Display(jni_facade->GetDisplayRefreshRate()); + auto display = AndroidDisplay(jni_facade->GetDisplayRefreshRate()); shell.OnDisplayUpdates(DisplayUpdateType::kStartup, {display}); return platform_view_android; }; diff --git a/shell/platform/android/display_refresh_listener.cc b/shell/platform/android/display_refresh_listener.cc new file mode 100644 index 0000000000000..2b501221fbe1e --- /dev/null +++ b/shell/platform/android/display_refresh_listener.cc @@ -0,0 +1,79 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "display_refresh_listener.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/native_library.h" + +namespace flutter { +namespace { +// Only avialalbe on API 24+ +typedef void AChoreographer; + +// Must be called from the Platform thread. +AChoreographer* GetAChoreographer() { + auto libandroid = fml::NativeLibrary::Create("libandroid.so"); + FML_CHECK(libandroid); + auto get_instance_fn = libandroid->ResolveFunction( + "AChoreographer_getInstance"); + if (get_instance_fn) { + return get_instance_fn.value()(); + } + return nullptr; +} + +// Only available on API 30+ +typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, + void* data); +void OnDisplayRefreshUpdated(int64_t vsyncPeriodNanos, void* data) { + auto* delegate = reinterpret_cast(data); + delegate->OnDisplayRefreshUpdated(vsyncPeriodNanos); +} + +// The data parameter will not be accessed, but will serve as an identifier for +// unregistering. +void ListenToRefreshRateChanges(DisplayRefreshListener::Delegate* delegate) { + auto libandroid = fml::NativeLibrary::Create("libandroid.so"); + FML_CHECK(libandroid); + auto register_refresh_rate_callback_fn = libandroid->ResolveFunction( + "AChoreographer_registerRefreshRateCallback"); + + if (register_refresh_rate_callback_fn) { + auto choreographer = GetAChoreographer(); + FML_CHECK(choreographer); + register_refresh_rate_callback_fn.value()( + choreographer, &OnDisplayRefreshUpdated, delegate); + } +} + +// The data parmaeter must be the same as the pointer passed to +// ListenToRefreshRateChanges. +void StopListeningToRefreshRateChanges( + DisplayRefreshListener::Delegate* delegate) { + auto libandroid = fml::NativeLibrary::Create("libandroid.so"); + FML_CHECK(libandroid); + auto unregister_refresh_rate_callback_fn = + libandroid->ResolveFunction( + "AChoreographer_unregisterRefreshRateCallback"); + + if (unregister_refresh_rate_callback_fn) { + auto choreographer = GetAChoreographer(); + FML_CHECK(choreographer); + unregister_refresh_rate_callback_fn.value()( + choreographer, &OnDisplayRefreshUpdated, delegate); + } +} +} // namespace + +DisplayRefreshListener::DisplayRefreshListener(Delegate& delegate) + : delegate_(delegate) { + ListenToRefreshRateChanges(&delegate_); +} + +DisplayRefreshListener::~DisplayRefreshListener() { + StopListeningToRefreshRateChanges(&delegate_); +} +} // namespace flutter diff --git a/shell/platform/android/display_refresh_listener.h b/shell/platform/android/display_refresh_listener.h new file mode 100644 index 0000000000000..0c82e4fd6ebe4 --- /dev/null +++ b/shell/platform/android/display_refresh_listener.h @@ -0,0 +1,44 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_DISPLAY_REFRESH_LISTENER_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_DISPLAY_REFRESH_LISTENER_H_ + +#include + +#include "flutter/fml/macros.h" + +namespace flutter { + +/// A means to recieve updates when the display refresh rate updates on Android. +/// +/// This class only works on API30+. On older versions, the +/// Delegate::OnDisplayRefreshUpdated will never be called. Instead, the +/// FlutterJNI#refreshRateFPS should be used for lower API versions. That field +/// has the disadvantage being out of sync with the current refresh rate, as it +/// is typically only updated on initialization. +/// +/// This class must be constructed on the Platform task runner. Callbacks on the +/// delegate are safe to recieve on any task runner. +class DisplayRefreshListener { + public: + class Delegate { + public: + /// This method may be called on any task runner. + virtual void OnDisplayRefreshUpdated(int64_t vsync_period_nanos) = 0; + }; + + /// This class must be constructed on the Platform task runner. + explicit DisplayRefreshListener(Delegate& delegate); + ~DisplayRefreshListener(); + + private: + Delegate& delegate_; + + FML_DISALLOW_COPY_AND_ASSIGN(DisplayRefreshListener); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_DISPLAY_REFRESH_LISTENER_H_ diff --git a/shell/platform/android/vsync_waiter_android.cc b/shell/platform/android/vsync_waiter_android.cc index 0ea109f5c3d26..47bb9c8df4a8f 100644 --- a/shell/platform/android/vsync_waiter_android.cc +++ b/shell/platform/android/vsync_waiter_android.cc @@ -14,80 +14,20 @@ #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/size.h" #include "flutter/fml/trace_event.h" +#include "vsync_waiter_android.h" namespace flutter { static fml::jni::ScopedJavaGlobalRef* g_vsync_waiter_class = nullptr; static jmethodID g_async_wait_for_vsync_method_ = nullptr; -static std::optional g_vsync_period_nanos_ = std::nullopt; - -namespace { -// Only avialalbe on API 24+ -typedef void AChoreographer; - -// Must be called from the Platform thread. -AChoreographer* GetAChoreographer() { - auto libandroid = fml::NativeLibrary::Create("libandroid.so"); - FML_CHECK(libandroid); - auto get_instance_fn = libandroid->ResolveFunction( - "AChoreographer_getInstance"); - if (get_instance_fn) { - return get_instance_fn.value()(); - } - return nullptr; -} - -// Only available on API 30+ -typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, - void* data); -void HandleRefreshRateChanged(int64_t vsyncPeriodNanos, void* data) { - g_vsync_period_nanos_ = vsyncPeriodNanos; -} - -// The data parameter will not be accessed, but will serve as an identifier for -// unregistering. -void ListenToRefreshRateChanges(void* data) { - auto libandroid = fml::NativeLibrary::Create("libandroid.so"); - FML_CHECK(libandroid); - auto register_refresh_rate_callback_fn = libandroid->ResolveFunction( - "AChoreographer_registerRefreshRateCallback"); - - if (register_refresh_rate_callback_fn) { - auto choreographer = GetAChoreographer(); - FML_CHECK(choreographer); - register_refresh_rate_callback_fn.value()(choreographer, - &HandleRefreshRateChanged, data); - } -} -// The data parmaeter must be the same as the pointer passed to -// ListenToRefreshRateChanges. -void StopListeningToRefreshRateChanges(void* data) { - auto libandroid = fml::NativeLibrary::Create("libandroid.so"); - FML_CHECK(libandroid); - auto unregister_refresh_rate_callback_fn = - libandroid->ResolveFunction( - "AChoreographer_unregisterRefreshRateCallback"); - - if (unregister_refresh_rate_callback_fn) { - auto choreographer = GetAChoreographer(); - FML_CHECK(choreographer); - unregister_refresh_rate_callback_fn.value()( - choreographer, &HandleRefreshRateChanged, data); - } -} -} // namespace +// static +std::optional VsyncWaiterAndroid::current_vsync_period_nanos_ = {}; VsyncWaiterAndroid::VsyncWaiterAndroid(flutter::TaskRunners task_runners) - : VsyncWaiter(std::move(task_runners)) { - ListenToRefreshRateChanges(this); -} + : VsyncWaiter(std::move(task_runners)), display_refresh_listener_(*this) {} -VsyncWaiterAndroid::~VsyncWaiterAndroid() { - StopListeningToRefreshRateChanges(this); -} +VsyncWaiterAndroid::~VsyncWaiterAndroid() = default; // |VsyncWaiter| void VsyncWaiterAndroid::AwaitVSync() { @@ -103,6 +43,11 @@ void VsyncWaiterAndroid::AwaitVSync() { }); } +// |DisplayRefreshListener::Delegate| +void VsyncWaiterAndroid::OnDisplayRefreshUpdated(int64_t vsync_period_nanos) { + current_vsync_period_nanos_ = vsync_period_nanos; +} + // static void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env, jclass jcaller, @@ -114,8 +59,9 @@ void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env, auto frame_time = fml::TimePoint::Now() - fml::TimeDelta::FromNanoseconds(frameDelayNanos); auto target_time = - frame_time + fml::TimeDelta::FromNanoseconds( - g_vsync_period_nanos_.value_or(refreshPeriodNanos)); + frame_time + + fml::TimeDelta::FromNanoseconds( + current_vsync_period_nanos_.value_or(refreshPeriodNanos)); ConsumePendingCallback(java_baton, frame_time, target_time); } diff --git a/shell/platform/android/vsync_waiter_android.h b/shell/platform/android/vsync_waiter_android.h index 03bc415e3ae99..1732a4a0fc5ce 100644 --- a/shell/platform/android/vsync_waiter_android.h +++ b/shell/platform/android/vsync_waiter_android.h @@ -9,16 +9,19 @@ #include +#include "display_refresh_listener.h" #include "flutter/fml/macros.h" #include "flutter/shell/common/vsync_waiter.h" +#include "flutter/shell/platform/android/display_refresh_listener.h" namespace flutter { -class VsyncWaiterAndroid final : public VsyncWaiter { +class VsyncWaiterAndroid final : public VsyncWaiter, + DisplayRefreshListener::Delegate { public: static bool Register(JNIEnv* env); - VsyncWaiterAndroid(flutter::TaskRunners task_runners); + explicit VsyncWaiterAndroid(flutter::TaskRunners task_runners); ~VsyncWaiterAndroid() override; @@ -26,6 +29,9 @@ class VsyncWaiterAndroid final : public VsyncWaiter { // |VsyncWaiter| void AwaitVSync() override; + // |DisplayRefreshListener::Delegate| + void OnDisplayRefreshUpdated(int64_t vsync_period_nanos) override; + static void OnNativeVsync(JNIEnv* env, jclass jcaller, jlong frameDelayNanos, @@ -36,6 +42,11 @@ class VsyncWaiterAndroid final : public VsyncWaiter { fml::TimePoint frame_start_time, fml::TimePoint frame_target_time); + DisplayRefreshListener display_refresh_listener_; + // Accessed from static functions. Luckily, there is only ever one VSync + // waiter. + static std::optional current_vsync_period_nanos_; + FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterAndroid); };