VSyncWaiter on Fuchsia will defer firing until frame start time (#29287) (#30250)
* VSyncWaiter on Fuchsia will defer firing until frame start time
The common vsync waiter implementation expects this invariant to be
held.
* Add a test for vsync_waiter
Co-authored-by: Kaushik Iska <iska.kaushik@gmail.com>
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index bec85aa..bf78589 100755
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -1495,6 +1495,7 @@
FILE: ../../../flutter/shell/platform/fuchsia/flutter/unique_fdio_ns.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.h
+FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter_unittest.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc
diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn
index eb8cf30..e35739f 100644
--- a/shell/platform/fuchsia/flutter/BUILD.gn
+++ b/shell/platform/fuchsia/flutter/BUILD.gn
@@ -482,6 +482,7 @@
"tests/gfx_session_connection_unittests.cc",
"tests/pointer_event_utility.cc",
"tests/pointer_event_utility.h",
+ "vsync_waiter_unittest.cc",
]
# This is needed for //third_party/googletest for linking zircon symbols.
diff --git a/shell/platform/fuchsia/flutter/vsync_waiter.cc b/shell/platform/fuchsia/flutter/vsync_waiter.cc
index c66e126..aa7d3c2 100644
--- a/shell/platform/fuchsia/flutter/vsync_waiter.cc
+++ b/shell/platform/fuchsia/flutter/vsync_waiter.cc
@@ -30,10 +30,17 @@
weak_factory_(this) {
fire_callback_callback_ = [this](fml::TimePoint frame_start,
fml::TimePoint frame_end) {
- // Note: It is VERY important to set |pause_secondary_tasks| to false, else
- // Animator will almost immediately crash on Fuchsia.
- // FML_LOG(INFO) << "CRASH:: VsyncWaiter about to FireCallback";
- FireCallback(frame_start, frame_end, /*pause_secondary_tasks=*/false);
+ task_runners_.GetUITaskRunner()->PostTaskForTime(
+ [frame_start, frame_end, weak_this = weak_ui_]() {
+ if (weak_this) {
+ // Note: It is VERY important to set |pause_secondary_tasks| to
+ // false, else Animator will almost immediately crash on Fuchsia.
+ // FML_LOG(INFO) << "CRASH:: VsyncWaiter about to FireCallback";
+ weak_this->FireCallback(frame_start, frame_end,
+ /*pause_secondary_tasks*/ false);
+ }
+ },
+ frame_start);
};
// Generate a WeakPtrFactory for use with the UI thread. This does not need
@@ -41,8 +48,9 @@
// thread so we have ordering guarantees (see ::AwaitVSync())
fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetUITaskRunner(), fml::MakeCopyable([this]() mutable {
- this->weak_factory_ui_ =
+ weak_factory_ui_ =
std::make_unique<fml::WeakPtrFactory<VsyncWaiter>>(this);
+ weak_ui_ = weak_factory_ui_->GetWeakPtr();
}));
}
diff --git a/shell/platform/fuchsia/flutter/vsync_waiter.h b/shell/platform/fuchsia/flutter/vsync_waiter.h
index 1e92064..ce46b90 100644
--- a/shell/platform/fuchsia/flutter/vsync_waiter.h
+++ b/shell/platform/fuchsia/flutter/vsync_waiter.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_VSYNC_WAITER_H_
-#define FLUTTER_SHELL_PLATFORM_FUCHSIA_VSYNC_WAITER_H_
+#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_VSYNC_WAITER_H_
+#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_VSYNC_WAITER_H_
#include <lib/async/cpp/wait.h>
@@ -46,6 +46,7 @@
AwaitVsyncForSecondaryCallbackCallback
await_vsync_for_secondary_callback_callback_;
+ fml::WeakPtr<VsyncWaiter> weak_ui_;
std::unique_ptr<fml::WeakPtrFactory<VsyncWaiter>> weak_factory_ui_;
fml::WeakPtrFactory<VsyncWaiter> weak_factory_;
@@ -54,4 +55,4 @@
} // namespace flutter_runner
-#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_VSYNC_WAITER_H_
+#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_VSYNC_WAITER_H_
diff --git a/shell/platform/fuchsia/flutter/vsync_waiter_unittest.cc b/shell/platform/fuchsia/flutter/vsync_waiter_unittest.cc
new file mode 100644
index 0000000..f01a2a0
--- /dev/null
+++ b/shell/platform/fuchsia/flutter/vsync_waiter_unittest.cc
@@ -0,0 +1,63 @@
+// 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 <gtest/gtest.h>
+
+#include <string>
+
+#include "flutter/fml/task_runner.h"
+#include "flutter/shell/common/thread_host.h"
+#include "fml/make_copyable.h"
+#include "fml/message_loop.h"
+#include "fml/synchronization/waitable_event.h"
+#include "fml/time/time_delta.h"
+#include "fml/time/time_point.h"
+#include "vsync_waiter.h"
+
+namespace flutter_runner {
+
+TEST(VSyncWaiterFuchsia, FrameScheduledForStartTime) {
+ using flutter::ThreadHost;
+ std::string prefix = "vsync_waiter_test";
+
+ fml::MessageLoop::EnsureInitializedForCurrentThread();
+ auto platform_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
+
+ ThreadHost thread_host =
+ ThreadHost(prefix, flutter::ThreadHost::Type::RASTER |
+ flutter::ThreadHost::Type::UI |
+ flutter::ThreadHost::Type::IO);
+ const flutter::TaskRunners task_runners(
+ prefix, // Dart thread labels
+ platform_task_runner, // platform
+ thread_host.raster_thread->GetTaskRunner(), // raster
+ thread_host.ui_thread->GetTaskRunner(), // ui
+ thread_host.io_thread->GetTaskRunner() // io
+ );
+
+ // await vsync will invoke the callback right away, but vsync waiter will post
+ // the task for frame_start time.
+ VsyncWaiter vsync_waiter(
+ [](FireCallbackCallback callback) {
+ const auto now = fml::TimePoint::Now();
+ const auto frame_start = now + fml::TimeDelta::FromMilliseconds(20);
+ const auto frame_end = now + fml::TimeDelta::FromMilliseconds(36);
+ callback(frame_start, frame_end);
+ },
+ /*secondary callback*/ nullptr, task_runners);
+
+ fml::AutoResetWaitableEvent latch;
+ task_runners.GetUITaskRunner()->PostTask([&]() {
+ vsync_waiter.AsyncWaitForVsync(
+ [&](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
+ const auto now = fml::TimePoint::Now();
+ EXPECT_GT(now, recorder->GetVsyncStartTime());
+ latch.Signal();
+ });
+ });
+
+ latch.Wait();
+}
+
+} // namespace flutter_runner