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