1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | // FLUTTER_NOLINT |
5 | |
6 | #define FML_USED_ON_EMBEDDER |
7 | |
8 | #include <functional> |
9 | #include <future> |
10 | #include <memory> |
11 | |
12 | #include "flutter/shell/common/animator.h" |
13 | #include "flutter/shell/common/shell_test.h" |
14 | #include "flutter/shell/common/shell_test_platform_view.h" |
15 | #include "flutter/testing/testing.h" |
16 | #include "gtest/gtest.h" |
17 | |
18 | namespace flutter { |
19 | namespace testing { |
20 | |
21 | TEST_F(ShellTest, VSyncTargetTime) { |
22 | // Add native callbacks to listen for window.onBeginFrame |
23 | int64_t target_time; |
24 | fml::AutoResetWaitableEvent on_target_time_latch; |
25 | auto nativeOnBeginFrame = [&on_target_time_latch, |
26 | &target_time](Dart_NativeArguments args) { |
27 | Dart_Handle exception = nullptr; |
28 | target_time = |
29 | tonic::DartConverter<int64_t>::FromArguments(args, 0, exception); |
30 | on_target_time_latch.Signal(); |
31 | }; |
32 | AddNativeCallback("NativeOnBeginFrame" , |
33 | CREATE_NATIVE_ENTRY(nativeOnBeginFrame)); |
34 | |
35 | // Create all te prerequisites for a shell. |
36 | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); |
37 | auto settings = CreateSettingsForFixture(); |
38 | |
39 | std::unique_ptr<Shell> shell; |
40 | |
41 | TaskRunners task_runners = GetTaskRunnersForFixture(); |
42 | // this is not used as we are not using simulated events. |
43 | const auto vsync_clock = std::make_shared<ShellTestVsyncClock>(); |
44 | CreateVsyncWaiter create_vsync_waiter = [&]() { |
45 | return static_cast<std::unique_ptr<VsyncWaiter>>( |
46 | std::make_unique<ConstantFiringVsyncWaiter>(task_runners)); |
47 | }; |
48 | |
49 | // create a shell with a constant firing vsync waiter. |
50 | auto platform_task = std::async(std::launch::async, [&]() { |
51 | fml::MessageLoop::EnsureInitializedForCurrentThread(); |
52 | |
53 | shell = Shell::Create( |
54 | task_runners, settings, |
55 | [vsync_clock, &create_vsync_waiter](Shell& shell) { |
56 | return ShellTestPlatformView::Create( |
57 | shell, shell.GetTaskRunners(), vsync_clock, |
58 | std::move(create_vsync_waiter), |
59 | ShellTestPlatformView::BackendType::kDefaultBackend, nullptr); |
60 | }, |
61 | [](Shell& shell) { return std::make_unique<Rasterizer>(shell); }); |
62 | ASSERT_TRUE(DartVMRef::IsInstanceRunning()); |
63 | |
64 | auto configuration = RunConfiguration::InferFromSettings(settings); |
65 | ASSERT_TRUE(configuration.IsValid()); |
66 | configuration.SetEntrypoint("onBeginFrameMain" ); |
67 | |
68 | RunEngine(shell.get(), std::move(configuration)); |
69 | }); |
70 | platform_task.wait(); |
71 | |
72 | // schedule a frame to trigger window.onBeginFrame |
73 | fml::TaskRunner::RunNowOrPostTask(shell->GetTaskRunners().GetUITaskRunner(), |
74 | [engine = shell->GetEngine()]() { |
75 | if (engine) { |
76 | // this implies we can re-use the last |
77 | // frame to trigger begin frame rather |
78 | // than re-generating the layer tree. |
79 | engine->ScheduleFrame(true); |
80 | } |
81 | }); |
82 | |
83 | on_target_time_latch.Wait(); |
84 | const auto vsync_waiter_target_time = |
85 | ConstantFiringVsyncWaiter::frame_target_time; |
86 | ASSERT_EQ(vsync_waiter_target_time.ToEpochDelta().ToMicroseconds(), |
87 | target_time); |
88 | |
89 | // validate that the latest target time has also been updated. |
90 | ASSERT_EQ(GetLatestFrameTargetTime(shell.get()), vsync_waiter_target_time); |
91 | |
92 | // teardown. |
93 | DestroyShell(std::move(shell), std::move(task_runners)); |
94 | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); |
95 | } |
96 | |
97 | } // namespace testing |
98 | } // namespace flutter |
99 | |