Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
engine_animator_unittests.cc
Go to the documentation of this file.
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
6
7// #include <cstring>
8
13#include "gmock/gmock.h"
15
16// CREATE_NATIVE_ENTRY is leaky by design
17// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
18
19namespace flutter {
20
21namespace {
22
23using ::testing::ReturnRef;
24
26
27void PostSync(const fml::RefPtr<fml::TaskRunner>& task_runner,
28 const fml::closure& task) {
30 fml::TaskRunner::RunNowOrPostTask(task_runner, [&latch, &task] {
31 task();
32 latch.Signal();
33 });
34 latch.Wait();
35}
36
37// Sort the argument list of `LayerTreeTask` into a new list that is sorted by
38// their view IDs. `FrameItem::layer_tree_tasks` might not come sorted.
39std::vector<const LayerTreeTask*> Sorted(
40 const std::vector<std::unique_ptr<LayerTreeTask>>& layer_tree_tasks) {
41 std::vector<const LayerTreeTask*> result;
42 result.reserve(layer_tree_tasks.size());
43 for (auto& task_ptr : layer_tree_tasks) {
44 result.push_back(task_ptr.get());
45 }
46 std::sort(result.begin(), result.end(),
47 [](const LayerTreeTask* a, const LayerTreeTask* b) {
48 return a->view_id < b->view_id;
49 });
50 return result;
51}
52
53class MockDelegate : public Engine::Delegate {
54 public:
55 MOCK_METHOD(void,
56 OnEngineUpdateSemantics,
58 (override));
59 MOCK_METHOD(void,
60 OnEngineSetApplicationLocale,
61 (const std::string),
62 (override));
63 MOCK_METHOD(void, OnEngineSetSemanticsTreeEnabled, (bool), (override));
64 MOCK_METHOD(void,
65 OnEngineHandlePlatformMessage,
66 (std::unique_ptr<PlatformMessage>),
67 (override));
68 MOCK_METHOD(void, OnPreEngineRestart, (), (override));
69 MOCK_METHOD(void, OnRootIsolateCreated, (), (override));
70 MOCK_METHOD(void,
71 UpdateIsolateDescription,
72 (const std::string, int64_t),
73 (override));
74 MOCK_METHOD(void, SetNeedsReportTimings, (bool), (override));
75 MOCK_METHOD(std::unique_ptr<std::vector<std::string>>,
76 ComputePlatformResolvedLocale,
77 (const std::vector<std::string>&),
78 (override));
79 MOCK_METHOD(void, RequestDartDeferredLibrary, (intptr_t), (override));
80 MOCK_METHOD(fml::TimePoint, GetCurrentTimePoint, (), (override));
81 MOCK_METHOD(const std::shared_ptr<PlatformMessageHandler>&,
82 GetPlatformMessageHandler,
83 (),
84 (const, override));
85 MOCK_METHOD(void, OnEngineChannelUpdate, (std::string, bool), (override));
86 MOCK_METHOD(double,
87 GetScaledFontSize,
88 (double font_size, int configuration_id),
89 (const, override));
90 MOCK_METHOD(void,
91 RequestViewFocusChange,
92 (const ViewFocusChangeRequest&),
93 (override));
94};
95
96class MockAnimatorDelegate : public Animator::Delegate {
97 public:
98 /* Animator::Delegate */
99 MOCK_METHOD(void,
100 OnAnimatorBeginFrame,
101 (fml::TimePoint frame_target_time, uint64_t frame_number),
102 (override));
103 MOCK_METHOD(void,
104 OnAnimatorNotifyIdle,
105 (fml::TimeDelta deadline),
106 (override));
107 MOCK_METHOD(void,
108 OnAnimatorUpdateLatestFrameTargetTime,
109 (fml::TimePoint frame_target_time),
110 (override));
111 MOCK_METHOD(void,
112 OnAnimatorDraw,
113 (std::shared_ptr<FramePipeline> pipeline),
114 (override));
115 MOCK_METHOD(void,
116 OnAnimatorDrawLastLayerTrees,
117 (std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder),
118 (override));
119};
120
121class MockPlatformMessageHandler : public PlatformMessageHandler {
122 public:
123 MOCK_METHOD(void,
124 HandlePlatformMessage,
125 (std::unique_ptr<PlatformMessage> message),
126 (override));
127 MOCK_METHOD(bool,
128 DoesHandlePlatformMessageOnPlatformThread,
129 (),
130 (const, override));
131 MOCK_METHOD(void,
133 (int response_id, std::unique_ptr<fml::Mapping> mapping),
134 (override));
135 MOCK_METHOD(void,
137 (int response_id),
138 (override));
139};
140
141class EngineAnimatorTest : public testing::FixtureTest {
142 public:
143 EngineAnimatorTest()
144 : thread_host_("EngineAnimatorTest",
145 ThreadHost::Type::kPlatform | ThreadHost::Type::kIo |
146 ThreadHost::Type::kUi | ThreadHost::Type::kRaster),
148 "EngineAnimatorTest",
149 thread_host_.platform_thread->GetTaskRunner(), // platform
150 thread_host_.raster_thread->GetTaskRunner(), // raster
151 thread_host_.ui_thread->GetTaskRunner(), // ui
152 thread_host_.io_thread->GetTaskRunner() // io
153 }) {}
154
155 void PostUITaskSync(const std::function<void()>& function) {
157 task_runners_.GetUITaskRunner()->PostTask([&] {
158 function();
159 latch.Signal();
160 });
161 latch.Wait();
162 }
163
164 protected:
165 void SetUp() override {
166 settings_ = CreateSettingsForFixture();
167 dispatcher_maker_ = [](PointerDataDispatcher::Delegate&) {
168 return nullptr;
169 };
170 }
171
172 MockDelegate delegate_;
174 ThreadHost thread_host_;
175 TaskRunners task_runners_;
176 Settings settings_;
177 std::unique_ptr<Animator> animator_;
179 std::unique_ptr<RuntimeController> runtime_controller_;
180 std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner_;
182};
183
184// A class that can launch an Engine with the specified Engine::Delegate.
185//
186// To use this class, contruct this class with Create, call Run, and use the
187// engine with EngineTaskSync().
188class EngineContext {
189 public:
190 using EngineCallback = std::function<void(Engine&)>;
191
192 [[nodiscard]] static std::unique_ptr<EngineContext> Create(
193 Engine::Delegate& delegate, //
194 Settings settings, //
195 const TaskRunners& task_runners, //
196 std::unique_ptr<Animator> animator) {
197 auto [vm, isolate_snapshot] = Shell::InferVmInitDataFromSettings(settings);
198 FML_CHECK(vm) << "Must be able to initialize the VM.";
199 // Construct the class with `new` because `make_unique` has no access to the
200 // private constructor.
201 EngineContext* raw_pointer =
202 new EngineContext(delegate, settings, task_runners, std::move(animator),
203 vm, isolate_snapshot);
204 return std::unique_ptr<EngineContext>(raw_pointer);
205 }
206
207 void Run(RunConfiguration configuration) {
208 PostSync(task_runners_.GetUITaskRunner(), [this, &configuration] {
209 Engine::RunStatus run_status = engine_->Run(std::move(configuration));
210 FML_CHECK(run_status == Engine::RunStatus::Success)
211 << "Engine failed to run.";
212 (void)run_status; // Suppress unused-variable warning
213 });
214 }
215
216 // Run a task that operates the Engine on the UI thread, and wait for the
217 // task to end.
218 //
219 // If called on the UI thread, the task is executed synchronously.
220 void EngineTaskSync(EngineCallback task) {
221 ASSERT_TRUE(engine_);
222 ASSERT_TRUE(task);
223 auto runner = task_runners_.GetUITaskRunner();
224 if (runner->RunsTasksOnCurrentThread()) {
225 task(*engine_);
226 } else {
227 PostSync(task_runners_.GetUITaskRunner(), [&]() { task(*engine_); });
228 }
229 }
230
231 ~EngineContext() {
232 PostSync(task_runners_.GetUITaskRunner(), [this] { engine_.reset(); });
233 }
234
235 private:
236 EngineContext(Engine::Delegate& delegate, //
237 Settings settings, //
238 const TaskRunners& task_runners, //
239 std::unique_ptr<Animator> animator, //
240 const DartVMRef& vm, //
241 fml::RefPtr<const DartSnapshot> isolate_snapshot)
242 : task_runners_(task_runners), vm_(vm) {
243 PostSync(task_runners.GetUITaskRunner(), [this, &settings, &animator,
244 &delegate, &isolate_snapshot] {
245 auto dispatcher_maker =
246 [](DefaultPointerDataDispatcher::Delegate& delegate) {
247 return std::make_unique<DefaultPointerDataDispatcher>(delegate);
248 };
249 std::promise<impeller::RuntimeStageBackend> rsb;
251 engine_ = std::make_unique<Engine>(
252 /*delegate=*/delegate,
253 /*dispatcher_maker=*/dispatcher_maker,
254 /*vm=*/*&vm_,
255 /*isolate_snapshot=*/std::move(isolate_snapshot),
256 /*task_runners=*/task_runners_,
257 /*platform_data=*/PlatformData(),
258 /*settings=*/settings,
259 /*animator=*/std::move(animator),
260 /*io_manager=*/io_manager_,
261 /*unref_queue=*/nullptr,
262 /*snapshot_delegate=*/snapshot_delegate_,
263 /*gpu_disabled_switch=*/std::make_shared<fml::SyncSwitch>(),
264 /*runtime_stage_backend=*/rsb.get_future());
265 });
266 }
267
268 TaskRunners task_runners_;
269 DartVMRef vm_;
270 std::unique_ptr<Engine> engine_;
271
274};
275} // namespace
276
277TEST_F(EngineAnimatorTest, AnimatorAcceptsMultipleRenders) {
278 MockAnimatorDelegate animator_delegate;
279 std::unique_ptr<EngineContext> engine_context;
280
281 std::shared_ptr<PlatformMessageHandler> platform_message_handler =
282 std::make_shared<MockPlatformMessageHandler>();
283 EXPECT_CALL(delegate_, GetPlatformMessageHandler)
284 .WillOnce(ReturnRef(platform_message_handler));
286 EXPECT_CALL(animator_delegate, OnAnimatorDraw)
287 .WillOnce([&draw_latch](const std::shared_ptr<FramePipeline>& pipeline) {
288 auto status = pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
289 auto tasks = Sorted(item->layer_tree_tasks);
290 EXPECT_EQ(tasks.size(), 2u);
291 EXPECT_EQ(tasks[0]->view_id, 1);
292 EXPECT_EQ(tasks[1]->view_id, 2);
293 });
294 EXPECT_EQ(status, PipelineConsumeResult::Done);
295 draw_latch.Signal();
296 });
297 EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
298 .WillOnce([&engine_context](fml::TimePoint frame_target_time,
299 uint64_t frame_number) {
300 engine_context->EngineTaskSync([&](Engine& engine) {
301 engine.BeginFrame(frame_target_time, frame_number);
302 });
303 });
304
305 native_latch.Reset();
306 AddNativeCallback("NotifyNative", [](auto args) { native_latch.Signal(); });
307
308 std::unique_ptr<Animator> animator;
309 PostSync(task_runners_.GetUITaskRunner(),
310 [&animator, &animator_delegate, &task_runners = task_runners_] {
311 animator = std::make_unique<Animator>(
312 animator_delegate, task_runners,
313 static_cast<std::unique_ptr<VsyncWaiter>>(
314 std::make_unique<testing::ConstantFiringVsyncWaiter>(
315 task_runners)));
316 });
317
318 engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
319 std::move(animator));
320 auto configuration = RunConfiguration::InferFromSettings(settings_);
321 configuration.SetEntrypoint("onDrawFrameRenderAllViews");
322 engine_context->Run(std::move(configuration));
323
324 engine_context->EngineTaskSync([](Engine& engine) {
325 engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0},
326 [](bool added) { ASSERT_TRUE(added); });
327 engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0},
328 [](bool added) { ASSERT_TRUE(added); });
329 });
330
331 native_latch.Wait();
332
333 engine_context->EngineTaskSync(
334 [](Engine& engine) { engine.ScheduleFrame(); });
335 draw_latch.Wait();
336}
337
338TEST_F(EngineAnimatorTest, IgnoresOutOfFrameRenders) {
339 MockAnimatorDelegate animator_delegate;
340 std::unique_ptr<EngineContext> engine_context;
341
342 std::shared_ptr<PlatformMessageHandler> platform_message_handler =
343 std::make_shared<MockPlatformMessageHandler>();
344 EXPECT_CALL(delegate_, GetPlatformMessageHandler)
345 .WillOnce(ReturnRef(platform_message_handler));
347 EXPECT_CALL(animator_delegate, OnAnimatorDraw)
348 .WillOnce([&draw_latch](const std::shared_ptr<FramePipeline>& pipeline) {
349 auto status = pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
350 // View 1 is rendered before the frame, and is ignored.
351 // View 2 is rendered within the frame, and is accepted.
352 EXPECT_EQ(item->layer_tree_tasks.size(), 1u);
353 EXPECT_EQ(item->layer_tree_tasks[0]->view_id, 2);
354 });
355 EXPECT_EQ(status, PipelineConsumeResult::Done);
356 draw_latch.Signal();
357 });
358 EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
359 .WillOnce([&engine_context](fml::TimePoint frame_target_time,
360 uint64_t frame_number) {
361 engine_context->EngineTaskSync([&](Engine& engine) {
362 engine.BeginFrame(frame_target_time, frame_number);
363 });
364 });
365
366 std::unique_ptr<Animator> animator;
367 PostSync(task_runners_.GetUITaskRunner(),
368 [&animator, &animator_delegate, &task_runners = task_runners_] {
369 animator = std::make_unique<Animator>(
370 animator_delegate, task_runners,
371 static_cast<std::unique_ptr<VsyncWaiter>>(
372 std::make_unique<testing::ConstantFiringVsyncWaiter>(
373 task_runners)));
374 });
375
376 engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
377 std::move(animator));
378
379 engine_context->EngineTaskSync([](Engine& engine) {
380 engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0},
381 [](bool added) { ASSERT_TRUE(added); });
382 engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0},
383 [](bool added) { ASSERT_TRUE(added); });
384 });
385
386 auto configuration = RunConfiguration::InferFromSettings(settings_);
387 configuration.SetEntrypoint("renderViewsInFrameAndOutOfFrame");
388 engine_context->Run(std::move(configuration));
389
390 draw_latch.Wait();
391}
392
393TEST_F(EngineAnimatorTest, IgnoresDuplicateRenders) {
394 MockAnimatorDelegate animator_delegate;
395 std::unique_ptr<EngineContext> engine_context;
396
397 std::vector<std::shared_ptr<Layer>> benchmark_layers;
398 auto capture_root_layer = [&benchmark_layers](Dart_NativeArguments args) {
399 auto handle = Dart_GetNativeArgument(args, 0);
400 intptr_t peer = 0;
401 Dart_Handle result = Dart_GetNativeInstanceField(
402 handle, tonic::DartWrappable::kPeerIndex, &peer);
403 ASSERT_FALSE(Dart_IsError(result));
404 SceneBuilder* scene_builder = reinterpret_cast<SceneBuilder*>(peer);
405 ASSERT_TRUE(scene_builder);
406 std::shared_ptr<ContainerLayer> root_layer =
407 scene_builder->layer_stack()[0];
408 ASSERT_TRUE(root_layer);
409 benchmark_layers = root_layer->layers();
410 };
411
412 std::shared_ptr<PlatformMessageHandler> platform_message_handler =
413 std::make_shared<MockPlatformMessageHandler>();
414 EXPECT_CALL(delegate_, GetPlatformMessageHandler)
415 .WillOnce(ReturnRef(platform_message_handler));
417 EXPECT_CALL(animator_delegate, OnAnimatorDraw)
418 .WillOnce([&draw_latch, &benchmark_layers](
419 const std::shared_ptr<FramePipeline>& pipeline) {
420 auto status = pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
421 EXPECT_EQ(item->layer_tree_tasks.size(), 1u);
422 EXPECT_EQ(item->layer_tree_tasks[0]->view_id, kFlutterImplicitViewId);
423 ContainerLayer* root_layer = reinterpret_cast<ContainerLayer*>(
424 item->layer_tree_tasks[0]->layer_tree->root_layer());
425 std::vector<std::shared_ptr<Layer>> result_layers =
426 root_layer->layers();
427 EXPECT_EQ(result_layers.size(), benchmark_layers.size());
428 EXPECT_EQ(result_layers[0], benchmark_layers[0]);
429 });
430 EXPECT_EQ(status, PipelineConsumeResult::Done);
431 draw_latch.Signal();
432 });
433 EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
434 .WillOnce([&engine_context](fml::TimePoint frame_target_time,
435 uint64_t frame_number) {
436 engine_context->EngineTaskSync([&](Engine& engine) {
437 engine.BeginFrame(frame_target_time, frame_number);
438 });
439 });
440
441 AddNativeCallback("CaptureRootLayer",
442 CREATE_NATIVE_ENTRY(capture_root_layer));
443
444 std::unique_ptr<Animator> animator;
445 PostSync(task_runners_.GetUITaskRunner(),
446 [&animator, &animator_delegate, &task_runners = task_runners_] {
447 animator = std::make_unique<Animator>(
448 animator_delegate, task_runners,
449 static_cast<std::unique_ptr<VsyncWaiter>>(
450 std::make_unique<testing::ConstantFiringVsyncWaiter>(
451 task_runners)));
452 });
453
454 engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
455 std::move(animator));
456
457 engine_context->EngineTaskSync([](Engine& engine) {
458 engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1, 10, 10, 22, 0},
459 [](bool added) { ASSERT_TRUE(added); });
460 });
461
462 auto configuration = RunConfiguration::InferFromSettings(settings_);
463 configuration.SetEntrypoint("renderTwiceForOneView");
464 engine_context->Run(std::move(configuration));
465
466 draw_latch.Wait();
467}
468
469TEST_F(EngineAnimatorTest, AnimatorSubmitsImplicitViewBeforeDrawFrameEnds) {
470 MockAnimatorDelegate animator_delegate;
471 std::unique_ptr<EngineContext> engine_context;
472
473 std::shared_ptr<PlatformMessageHandler> platform_message_handler =
474 std::make_shared<MockPlatformMessageHandler>();
475 EXPECT_CALL(delegate_, GetPlatformMessageHandler)
476 .WillOnce(ReturnRef(platform_message_handler));
477
478 bool rasterization_started = false;
479 EXPECT_CALL(animator_delegate, OnAnimatorDraw)
480 .WillOnce([&rasterization_started](
481 const std::shared_ptr<FramePipeline>& pipeline) {
482 rasterization_started = true;
483 auto status = pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
484 EXPECT_EQ(item->layer_tree_tasks.size(), 1u);
485 EXPECT_EQ(item->layer_tree_tasks[0]->view_id, kFlutterImplicitViewId);
486 });
487 EXPECT_EQ(status, PipelineConsumeResult::Done);
488 });
489 EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
490 .WillRepeatedly([&engine_context](fml::TimePoint frame_target_time,
491 uint64_t frame_number) {
492 engine_context->EngineTaskSync([&](Engine& engine) {
493 engine.BeginFrame(frame_target_time, frame_number);
494 });
495 });
496
497 std::unique_ptr<Animator> animator;
498 PostSync(task_runners_.GetUITaskRunner(),
499 [&animator, &animator_delegate, &task_runners = task_runners_] {
500 animator = std::make_unique<Animator>(
501 animator_delegate, task_runners,
502 static_cast<std::unique_ptr<VsyncWaiter>>(
503 std::make_unique<testing::ConstantFiringVsyncWaiter>(
504 task_runners)));
505 });
506
507 native_latch.Reset();
508 // The native_latch is signaled at the end of handleDrawFrame.
509 AddNativeCallback("NotifyNative",
510 CREATE_NATIVE_ENTRY([&rasterization_started](auto args) {
511 EXPECT_EQ(rasterization_started, true);
512 native_latch.Signal();
513 }));
514
515 engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
516 std::move(animator));
517
518 engine_context->EngineTaskSync([](Engine& engine) {
519 engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0},
520 [](bool added) { ASSERT_TRUE(added); });
521 });
522
523 auto configuration = RunConfiguration::InferFromSettings(settings_);
524 configuration.SetEntrypoint("renderSingleViewAndCallAfterOnDrawFrame");
525 engine_context->Run(std::move(configuration));
526
527 native_latch.Wait();
528}
529
530// The animator should submit to the pipeline the implicit view rendered in a
531// warm up frame if there's already a continuation (i.e. Animator::BeginFrame
532// has been called)
533TEST_F(EngineAnimatorTest, AnimatorSubmitWarmUpImplicitView) {
534 MockAnimatorDelegate animator_delegate;
535 std::unique_ptr<EngineContext> engine_context;
536
537 std::shared_ptr<PlatformMessageHandler> platform_message_handler =
538 std::make_shared<MockPlatformMessageHandler>();
539 EXPECT_CALL(delegate_, GetPlatformMessageHandler)
540 .WillOnce(ReturnRef(platform_message_handler));
541
542 fml::AutoResetWaitableEvent continuation_ready_latch;
544 EXPECT_CALL(animator_delegate, OnAnimatorDraw)
545 .WillOnce([&draw_latch](const std::shared_ptr<FramePipeline>& pipeline) {
546 auto status = pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
547 EXPECT_EQ(item->layer_tree_tasks.size(), 1u);
548 EXPECT_EQ(item->layer_tree_tasks[0]->view_id, kFlutterImplicitViewId);
549 });
550 EXPECT_EQ(status, PipelineConsumeResult::Done);
551 draw_latch.Signal();
552 });
553 EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
554 .WillRepeatedly(
555 [&engine_context, &continuation_ready_latch](
556 fml::TimePoint frame_target_time, uint64_t frame_number) {
557 continuation_ready_latch.Signal();
558 engine_context->EngineTaskSync([&](Engine& engine) {
559 engine.BeginFrame(frame_target_time, frame_number);
560 });
561 });
562
563 std::unique_ptr<Animator> animator;
564 PostSync(task_runners_.GetUITaskRunner(),
565 [&animator, &animator_delegate, &task_runners = task_runners_] {
566 animator = std::make_unique<Animator>(
567 animator_delegate, task_runners,
568 static_cast<std::unique_ptr<VsyncWaiter>>(
569 std::make_unique<testing::ConstantFiringVsyncWaiter>(
570 task_runners)));
571 });
572
573 engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
574 std::move(animator));
575
576 engine_context->EngineTaskSync([](Engine& engine) {
577 // Schedule a frame to trigger Animator::BeginFrame to create a
578 // continuation. The continuation needs to be available before `Engine::Run`
579 // since the Dart program immediately schedules a warm up frame.
580 engine.ScheduleFrame(true);
581 // Add the implicit view so that the engine recognizes it and that its
582 // metrics is not empty.
583 engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0},
584 [](bool added) { ASSERT_TRUE(added); });
585 });
586 continuation_ready_latch.Wait();
587
588 auto configuration = RunConfiguration::InferFromSettings(settings_);
589 configuration.SetEntrypoint("renderWarmUpImplicitView");
590 engine_context->Run(std::move(configuration));
591
592 draw_latch.Wait();
593}
594
595// The warm up frame should work if only some of the registered views are
596// included.
597//
598// This test also verifies that the warm up frame can render multiple views.
599TEST_F(EngineAnimatorTest, AnimatorSubmitPartialViewsForWarmUp) {
600 MockAnimatorDelegate animator_delegate;
601 std::unique_ptr<EngineContext> engine_context;
602
603 std::shared_ptr<PlatformMessageHandler> platform_message_handler =
604 std::make_shared<MockPlatformMessageHandler>();
605 EXPECT_CALL(delegate_, GetPlatformMessageHandler)
606 .WillOnce(ReturnRef(platform_message_handler));
607
608 fml::AutoResetWaitableEvent continuation_ready_latch;
610 EXPECT_CALL(animator_delegate, OnAnimatorDraw)
611 .WillOnce([&draw_latch](const std::shared_ptr<FramePipeline>& pipeline) {
612 auto status = pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
613 auto tasks = Sorted(item->layer_tree_tasks);
614 EXPECT_EQ(tasks.size(), 2u);
615 EXPECT_EQ(tasks[0]->view_id, 1);
616 EXPECT_EQ(tasks[1]->view_id, 2);
617 });
618 EXPECT_EQ(status, PipelineConsumeResult::Done);
619 draw_latch.Signal();
620 });
621 EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
622 .WillRepeatedly(
623 [&engine_context, &continuation_ready_latch](
624 fml::TimePoint frame_target_time, uint64_t frame_number) {
625 continuation_ready_latch.Signal();
626 engine_context->EngineTaskSync([&](Engine& engine) {
627 engine.BeginFrame(frame_target_time, frame_number);
628 });
629 });
630
631 std::unique_ptr<Animator> animator;
632 PostSync(task_runners_.GetUITaskRunner(),
633 [&animator, &animator_delegate, &task_runners = task_runners_] {
634 animator = std::make_unique<Animator>(
635 animator_delegate, task_runners,
636 static_cast<std::unique_ptr<VsyncWaiter>>(
637 std::make_unique<testing::ConstantFiringVsyncWaiter>(
638 task_runners)));
639 });
640
641 engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
642 std::move(animator));
643
644 engine_context->EngineTaskSync([](Engine& engine) {
645 // Schedule a frame to make the animator create a continuation.
646 engine.ScheduleFrame(true);
647 // Add multiple views.
648 engine.AddView(0, ViewportMetrics{1, 10, 10, 22, 0},
649 [](bool added) { ASSERT_TRUE(added); });
650 engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0},
651 [](bool added) { ASSERT_TRUE(added); });
652 engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0},
653 [](bool added) { ASSERT_TRUE(added); });
654 });
655
656 continuation_ready_latch.Wait();
657
658 auto configuration = RunConfiguration::InferFromSettings(settings_);
659 configuration.SetEntrypoint("renderWarmUpView1and2");
660 engine_context->Run(std::move(configuration));
661
662 draw_latch.Wait();
663}
664
665} // namespace flutter
666
667// NOLINTEND(clang-analyzer-core.StackAddressEscape)
const std::vector< std::shared_ptr< Layer > > & layers() const
const std::vector< std::shared_ptr< ContainerLayer > > & layer_stack()
static std::pair< DartVMRef, fml::RefPtr< const DartSnapshot > > InferVmInitDataFromSettings(Settings &settings)
Definition shell.cc:206
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
@ kRaster
Suitable for thread which raster data.
Definition embedder.h:384
Settings settings_
std::shared_ptr< fml::ConcurrentTaskRunner > image_decoder_task_runner_
std::unique_ptr< RuntimeController > runtime_controller_
TaskRunners task_runners_
fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > snapshot_delegate_
std::unique_ptr< Animator > animator_
PointerDataDispatcherMaker dispatcher_maker_
ThreadHost thread_host_
MockDelegate delegate_
fml::WeakPtr< IOManager > io_manager_
FlutterEngine engine
Definition main.cc:84
const char * message
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_BEGIN_DECLS FlutterViewId view_id
#define FML_CHECK(condition)
Definition logging.h:104
Dart_NativeFunction function
Definition fuchsia.cc:51
constexpr int64_t kFlutterImplicitViewId
Definition constants.h:35
static void InvokePlatformMessageResponseCallback(JNIEnv *env, jobject jcaller, jlong shell_holder, jint responseId, jobject message, jint position)
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
static void InvokePlatformMessageEmptyResponseCallback(JNIEnv *env, jobject jcaller, jlong shell_holder, jint responseId)
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
std::function< std::unique_ptr< PointerDataDispatcher >(PointerDataDispatcher::Delegate &)> PointerDataDispatcherMaker
Signature for constructing PointerDataDispatcher.
std::function< void()> closure
Definition closure.h:14
ScopedObject< Object > Create(CtorArgs &&... args)
Definition object.h:161
#define CREATE_NATIVE_ENTRY(native_entry)
Scalar font_size