|
12 | 12 | #include <future> |
13 | 13 | #include <vector> |
14 | 14 |
|
| 15 | +#include "flutter/fml/synchronization/waitable_event.h" |
15 | 16 | #include "flutter/shell/platform/common/json_message_codec.h" |
16 | 17 | #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" |
17 | 18 | #include "flutter/shell/platform/windows/flutter_window.h" |
|
27 | 28 | namespace flutter { |
28 | 29 | namespace testing { |
29 | 30 |
|
| 31 | +using ::testing::_; |
30 | 32 | using ::testing::InSequence; |
31 | 33 | using ::testing::NiceMock; |
| 34 | +using ::testing::Return; |
32 | 35 |
|
33 | 36 | constexpr uint64_t kScanCodeKeyA = 0x1e; |
34 | 37 | constexpr uint64_t kVirtualKeyA = 0x41; |
@@ -117,8 +120,12 @@ class MockAngleSurfaceManager : public AngleSurfaceManager { |
117 | 120 | public: |
118 | 121 | MockAngleSurfaceManager() {} |
119 | 122 |
|
| 123 | + MOCK_METHOD4(CreateSurface, bool(WindowsRenderTarget*, EGLint, EGLint, bool)); |
| 124 | + MOCK_METHOD4(ResizeSurface, void(WindowsRenderTarget*, EGLint, EGLint, bool)); |
120 | 125 | MOCK_METHOD0(DestroySurface, void()); |
121 | 126 |
|
| 127 | + MOCK_METHOD1(SetVSyncEnabled, void(bool)); |
| 128 | + |
122 | 129 | private: |
123 | 130 | FML_DISALLOW_COPY_AND_ASSIGN(MockAngleSurfaceManager); |
124 | 131 | }; |
@@ -714,28 +721,44 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) { |
714 | 721 |
|
715 | 722 | auto window_binding_handler = |
716 | 723 | std::make_unique<NiceMock<MockWindowBindingHandler>>(); |
| 724 | + std::unique_ptr<MockAngleSurfaceManager> surface_manager = |
| 725 | + std::make_unique<MockAngleSurfaceManager>(); |
| 726 | + |
| 727 | + EXPECT_CALL(*window_binding_handler.get(), NeedsVSync) |
| 728 | + .WillOnce(Return(false)); |
| 729 | + EXPECT_CALL( |
| 730 | + *surface_manager.get(), |
| 731 | + ResizeSurface(_, /*width=*/500, /*height=*/500, /*enable_vsync=*/false)) |
| 732 | + .Times(1); |
| 733 | + EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1); |
717 | 734 |
|
718 | 735 | FlutterWindowsView view(std::move(window_binding_handler)); |
| 736 | + modifier.SetSurfaceManager(surface_manager.release()); |
719 | 737 | view.SetEngine(std::move(engine)); |
720 | 738 |
|
721 | | - bool send_window_metrics_event_called = false; |
| 739 | + fml::AutoResetWaitableEvent metrics_sent_latch; |
722 | 740 | modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC( |
723 | 741 | SendWindowMetricsEvent, |
724 | | - ([&send_window_metrics_event_called]( |
725 | | - auto engine, const FlutterWindowMetricsEvent* even) { |
726 | | - send_window_metrics_event_called = true; |
| 742 | + ([&metrics_sent_latch](auto engine, |
| 743 | + const FlutterWindowMetricsEvent* event) { |
| 744 | + metrics_sent_latch.Signal(); |
727 | 745 | return kSuccess; |
728 | 746 | })); |
729 | 747 |
|
730 | | - std::promise<bool> resize_completed; |
731 | | - std::thread([&resize_completed, &view]() { |
| 748 | + fml::AutoResetWaitableEvent resized_latch; |
| 749 | + std::thread([&resized_latch, &view]() { |
| 750 | + // Start the window resize. This sends the new window metrics |
| 751 | + // and then blocks until another thread completes the window resize. |
732 | 752 | view.OnWindowSizeChanged(500, 500); |
733 | | - resize_completed.set_value(true); |
| 753 | + resized_latch.Signal(); |
734 | 754 | }).detach(); |
735 | 755 |
|
736 | | - auto result = resize_completed.get_future().wait_for(std::chrono::seconds(1)); |
737 | | - EXPECT_EQ(std::future_status::ready, result); |
738 | | - EXPECT_TRUE(send_window_metrics_event_called); |
| 756 | + // Wait until the platform thread has started the window resize. |
| 757 | + metrics_sent_latch.Wait(); |
| 758 | + |
| 759 | + // Complete the window resize by requesting a buffer with the new window size. |
| 760 | + view.GetFrameBufferId(500, 500); |
| 761 | + resized_latch.Wait(); |
739 | 762 | } |
740 | 763 |
|
741 | 764 | TEST(FlutterWindowsViewTest, WindowRepaintTests) { |
@@ -1083,5 +1106,96 @@ TEST(FlutterWindowsViewTest, TooltipNodeData) { |
1083 | 1106 | EXPECT_EQ(uia_tooltip, "tooltip"); |
1084 | 1107 | } |
1085 | 1108 |
|
| 1109 | +// Don't block until the v-blank if it is disabled by the window. |
| 1110 | +TEST(FlutterWindowsViewTest, DisablesVSync) { |
| 1111 | + std::unique_ptr<MockFlutterWindowsEngine> engine = |
| 1112 | + std::make_unique<MockFlutterWindowsEngine>(); |
| 1113 | + auto window_binding_handler = |
| 1114 | + std::make_unique<NiceMock<MockWindowBindingHandler>>(); |
| 1115 | + std::unique_ptr<MockAngleSurfaceManager> surface_manager = |
| 1116 | + std::make_unique<MockAngleSurfaceManager>(); |
| 1117 | + |
| 1118 | + EXPECT_CALL(*window_binding_handler.get(), NeedsVSync) |
| 1119 | + .WillOnce(Return(false)); |
| 1120 | + |
| 1121 | + EngineModifier modifier(engine.get()); |
| 1122 | + FlutterWindowsView view(std::move(window_binding_handler)); |
| 1123 | + |
| 1124 | + InSequence s; |
| 1125 | + EXPECT_CALL(*surface_manager.get(), |
| 1126 | + CreateSurface(_, _, _, /*vsync_enabled=*/false)) |
| 1127 | + .Times(1) |
| 1128 | + .WillOnce(Return(true)); |
| 1129 | + |
| 1130 | + EXPECT_CALL(*engine.get(), Stop).Times(1); |
| 1131 | + EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1); |
| 1132 | + |
| 1133 | + modifier.SetSurfaceManager(surface_manager.release()); |
| 1134 | + view.SetEngine(std::move(engine)); |
| 1135 | + |
| 1136 | + view.CreateRenderSurface(); |
| 1137 | +} |
| 1138 | + |
| 1139 | +// Blocks until the v-blank if it is enabled by the window. |
| 1140 | +TEST(FlutterWindowsViewTest, EnablesVSync) { |
| 1141 | + std::unique_ptr<MockFlutterWindowsEngine> engine = |
| 1142 | + std::make_unique<MockFlutterWindowsEngine>(); |
| 1143 | + auto window_binding_handler = |
| 1144 | + std::make_unique<NiceMock<MockWindowBindingHandler>>(); |
| 1145 | + std::unique_ptr<MockAngleSurfaceManager> surface_manager = |
| 1146 | + std::make_unique<MockAngleSurfaceManager>(); |
| 1147 | + |
| 1148 | + EXPECT_CALL(*window_binding_handler.get(), NeedsVSync).WillOnce(Return(true)); |
| 1149 | + |
| 1150 | + EngineModifier modifier(engine.get()); |
| 1151 | + FlutterWindowsView view(std::move(window_binding_handler)); |
| 1152 | + |
| 1153 | + InSequence s; |
| 1154 | + EXPECT_CALL(*surface_manager.get(), |
| 1155 | + CreateSurface(_, _, _, /*vsync_enabled=*/true)) |
| 1156 | + .Times(1) |
| 1157 | + .WillOnce(Return(true)); |
| 1158 | + |
| 1159 | + EXPECT_CALL(*engine.get(), Stop).Times(1); |
| 1160 | + EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1); |
| 1161 | + |
| 1162 | + modifier.SetSurfaceManager(surface_manager.release()); |
| 1163 | + view.SetEngine(std::move(engine)); |
| 1164 | + |
| 1165 | + view.CreateRenderSurface(); |
| 1166 | +} |
| 1167 | + |
| 1168 | +// Desktop Window Manager composition can be disabled on Windows 7. |
| 1169 | +// If this happens, the app must synchronize with the vsync to prevent |
| 1170 | +// screen tearing. |
| 1171 | +TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) { |
| 1172 | + std::unique_ptr<MockFlutterWindowsEngine> engine = |
| 1173 | + std::make_unique<MockFlutterWindowsEngine>(); |
| 1174 | + auto window_binding_handler = |
| 1175 | + std::make_unique<NiceMock<MockWindowBindingHandler>>(); |
| 1176 | + std::unique_ptr<MockAngleSurfaceManager> surface_manager = |
| 1177 | + std::make_unique<MockAngleSurfaceManager>(); |
| 1178 | + |
| 1179 | + EXPECT_CALL(*window_binding_handler.get(), NeedsVSync) |
| 1180 | + .WillOnce(Return(true)) |
| 1181 | + .WillOnce(Return(false)); |
| 1182 | + |
| 1183 | + EngineModifier modifier(engine.get()); |
| 1184 | + FlutterWindowsView view(std::move(window_binding_handler)); |
| 1185 | + |
| 1186 | + InSequence s; |
| 1187 | + EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(true)).Times(1); |
| 1188 | + EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(false)).Times(1); |
| 1189 | + |
| 1190 | + EXPECT_CALL(*engine.get(), Stop).Times(1); |
| 1191 | + EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1); |
| 1192 | + |
| 1193 | + modifier.SetSurfaceManager(surface_manager.release()); |
| 1194 | + view.SetEngine(std::move(engine)); |
| 1195 | + |
| 1196 | + view.GetEngine()->OnDwmCompositionChanged(); |
| 1197 | + view.GetEngine()->OnDwmCompositionChanged(); |
| 1198 | +} |
| 1199 | + |
1086 | 1200 | } // namespace testing |
1087 | 1201 | } // namespace flutter |
0 commit comments