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