diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 9a2ccfceda885..abc2ea64321fb 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -568,6 +568,8 @@ FILE: ../../../flutter/shell/common/surface.cc FILE: ../../../flutter/shell/common/surface.h FILE: ../../../flutter/shell/common/switches.cc FILE: ../../../flutter/shell/common/switches.h +FILE: ../../../flutter/shell/common/test_vsync_waiters.cc +FILE: ../../../flutter/shell/common/test_vsync_waiters.h FILE: ../../../flutter/shell/common/thread_host.cc FILE: ../../../flutter/shell/common/thread_host.h FILE: ../../../flutter/shell/common/vsync_waiter.cc diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 1564547bd34d1..fcf9ce280bd8c 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -166,6 +166,8 @@ if (current_toolchain == host_toolchain) { "shell_test.cc", "shell_test.h", "shell_unittests.cc", + "test_vsync_waiters.cc", + "test_vsync_waiters.h", ] deps = [ diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 3066fa0f1c015..1cfd393f086f2 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -289,46 +289,6 @@ void ShellTest::AddNativeCallback(std::string name, native_resolver_->AddNativeCallback(std::move(name), callback); } -void ShellTestVsyncClock::SimulateVSync() { - std::scoped_lock lock(mutex_); - if (vsync_issued_ >= vsync_promised_.size()) { - vsync_promised_.emplace_back(); - } - FML_CHECK(vsync_issued_ < vsync_promised_.size()); - vsync_promised_[vsync_issued_].set_value(vsync_issued_); - vsync_issued_ += 1; -} - -std::future ShellTestVsyncClock::NextVSync() { - std::scoped_lock lock(mutex_); - vsync_promised_.emplace_back(); - return vsync_promised_.back().get_future(); -} - -void ShellTestVsyncWaiter::AwaitVSync() { - FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - auto vsync_future = clock_.NextVSync(); - - auto async_wait = std::async([&vsync_future, this]() { - vsync_future.wait(); - - // Post the `FireCallback` to the Platform thread so earlier Platform tasks - // (specifically, the `VSyncFlush` call) will be finished before - // `FireCallback` is executed. This is only needed for our unit tests. - // - // Without this, the repeated VSYNC signals in `VSyncFlush` may start both - // the current frame in the UI thread and the next frame in the secondary - // callback (both of them are waiting for VSYNCs). That breaks the unit - // test's assumption that each frame's VSYNC must be issued by different - // `VSyncFlush` call (which resets the `will_draw_new_frame` bit). - // - // For example, HandlesActualIphoneXsInputEvents will fail without this. - task_runners_.GetPlatformTaskRunner()->PostTask([this]() { - FireCallback(fml::TimePoint::Now(), fml::TimePoint::Now()); - }); - }); -} - ShellTestPlatformView::ShellTestPlatformView(PlatformView::Delegate& delegate, TaskRunners task_runners, bool simulate_vsync) diff --git a/shell/common/shell_test.h b/shell/common/shell_test.h index ebf9283378707..7368eb4f2d4d2 100644 --- a/shell/common/shell_test.h +++ b/shell/common/shell_test.h @@ -13,6 +13,7 @@ #include "flutter/lib/ui/window/platform_message.h" #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/common/shell.h" +#include "flutter/shell/common/test_vsync_waiters.h" #include "flutter/shell/common/thread_host.h" #include "flutter/shell/gpu/gpu_surface_gl_delegate.h" #include "flutter/testing/test_dart_native_resolver.h" @@ -88,32 +89,6 @@ class ShellTest : public ThreadTest { FML_DISALLOW_COPY_AND_ASSIGN(ShellTest); }; -class ShellTestVsyncClock { - public: - /// Simulate that a vsync signal is triggered. - void SimulateVSync(); - - /// A future that will return the index the next vsync signal. - std::future NextVSync(); - - private: - std::mutex mutex_; - std::vector> vsync_promised_; - size_t vsync_issued_ = 0; -}; - -class ShellTestVsyncWaiter : public VsyncWaiter { - public: - ShellTestVsyncWaiter(TaskRunners task_runners, ShellTestVsyncClock& clock) - : VsyncWaiter(std::move(task_runners)), clock_(clock) {} - - protected: - void AwaitVSync() override; - - private: - ShellTestVsyncClock& clock_; -}; - class ShellTestPlatformView : public PlatformView, public GPUSurfaceGLDelegate { public: ShellTestPlatformView(PlatformView::Delegate& delegate, diff --git a/shell/common/test_vsync_waiters.cc b/shell/common/test_vsync_waiters.cc new file mode 100644 index 0000000000000..af80d76380b94 --- /dev/null +++ b/shell/common/test_vsync_waiters.cc @@ -0,0 +1,61 @@ +// 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. + +#define FML_USED_ON_EMBEDDER + +#include "flutter/shell/common/shell_test.h" + +#include "flutter/flow/layers/layer_tree.h" +#include "flutter/flow/layers/transform_layer.h" +#include "flutter/fml/make_copyable.h" +#include "flutter/fml/mapping.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/testing/testing.h" + +namespace flutter { +namespace testing { + +void ShellTestVsyncClock::SimulateVSync() { + std::scoped_lock lock(mutex_); + if (vsync_issued_ >= vsync_promised_.size()) { + vsync_promised_.emplace_back(); + } + FML_CHECK(vsync_issued_ < vsync_promised_.size()); + vsync_promised_[vsync_issued_].set_value(vsync_issued_); + vsync_issued_ += 1; +} + +std::future ShellTestVsyncClock::NextVSync() { + std::scoped_lock lock(mutex_); + vsync_promised_.emplace_back(); + return vsync_promised_.back().get_future(); +} + +void ShellTestVsyncWaiter::AwaitVSync() { + FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); + auto vsync_future = clock_.NextVSync(); + + auto async_wait = std::async([&vsync_future, this]() { + vsync_future.wait(); + + // Post the `FireCallback` to the Platform thread so earlier Platform tasks + // (specifically, the `VSyncFlush` call) will be finished before + // `FireCallback` is executed. This is only needed for our unit tests. + // + // Without this, the repeated VSYNC signals in `VSyncFlush` may start both + // the current frame in the UI thread and the next frame in the secondary + // callback (both of them are waiting for VSYNCs). That breaks the unit + // test's assumption that each frame's VSYNC must be issued by different + // `VSyncFlush` call (which resets the `will_draw_new_frame` bit). + // + // For example, HandlesActualIphoneXsInputEvents will fail without this. + task_runners_.GetPlatformTaskRunner()->PostTask([this]() { + FireCallback(fml::TimePoint::Now(), fml::TimePoint::Now()); + }); + }); +} + +} // namespace testing +} // namespace flutter diff --git a/shell/common/test_vsync_waiters.h b/shell/common/test_vsync_waiters.h new file mode 100644 index 0000000000000..f2ac486df907e --- /dev/null +++ b/shell/common/test_vsync_waiters.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. + +#define FML_USED_ON_EMBEDDER + +#ifndef FLUTTER_SHELL_COMMON_TEST_VSYNC_WAITERS_H_ +#define FLUTTER_SHELL_COMMON_TEST_VSYNC_WAITERS_H_ + +#include "flutter/shell/common/shell.h" + +namespace flutter { +namespace testing { + +class ShellTestVsyncClock { + public: + /// Simulate that a vsync signal is triggered. + void SimulateVSync(); + + /// A future that will return the index the next vsync signal. + std::future NextVSync(); + + private: + std::mutex mutex_; + std::vector> vsync_promised_; + size_t vsync_issued_ = 0; +}; + +class ShellTestVsyncWaiter : public VsyncWaiter { + public: + ShellTestVsyncWaiter(TaskRunners task_runners, ShellTestVsyncClock& clock) + : VsyncWaiter(std::move(task_runners)), clock_(clock) {} + + protected: + void AwaitVSync() override; + + private: + ShellTestVsyncClock& clock_; +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_COMMON_TEST_VSYNC_WAITERS_H_