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