Flutter Engine
 
Loading...
Searching...
No Matches
embedder_gl_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#define FML_USED_ON_EMBEDDER
7
8#include <atomic>
9#include <string>
10#include <vector>
11
12#include "GLES3/gl3.h"
14#include "flutter/fml/file.h"
16#include "flutter/fml/mapping.h"
20#include "flutter/fml/paths.h"
24#include "flutter/fml/thread.h"
36#include "third_party/skia/include/core/SkSurface.h"
38
39// CREATE_NATIVE_ENTRY is leaky by design
40// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
41
42namespace flutter::testing {
43
45
46TEST_F(EmbedderTest, CanCreateOpenGLRenderingEngine) {
47 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
48 EmbedderConfigBuilder builder(context);
49 builder.SetSurface(DlISize(1, 1));
50 auto engine = builder.LaunchEngine();
51 ASSERT_TRUE(engine.is_valid());
52}
53
54//------------------------------------------------------------------------------
55/// If an incorrectly configured compositor is set on the engine, the engine
56/// must fail to launch instead of failing to render a frame at a later point in
57/// time.
58///
60 MustPreventEngineLaunchWhenRequiredCompositorArgsAreAbsent) {
61 auto& context = GetEmbedderContext<EmbedderTestContextSoftware>();
62 EmbedderConfigBuilder builder(context);
63 builder.SetSurface(DlISize(1, 1));
64 builder.SetCompositor();
65 builder.GetCompositor().create_backing_store_callback = nullptr;
66 builder.GetCompositor().collect_backing_store_callback = nullptr;
67 builder.GetCompositor().present_layers_callback = nullptr;
68 builder.GetCompositor().present_view_callback = nullptr;
69 auto engine = builder.LaunchEngine();
70 ASSERT_FALSE(engine.is_valid());
71}
72
73//------------------------------------------------------------------------------
74/// Either present_layers_callback or present_view_callback must be provided,
75/// but not both, otherwise the engine must fail to launch instead of failing to
76/// render a frame at a later point in time.
77///
78TEST_F(EmbedderTest, LaunchFailsWhenMultiplePresentCallbacks) {
79 auto& context = GetEmbedderContext<EmbedderTestContextSoftware>();
80 EmbedderConfigBuilder builder(context);
81 builder.SetSurface(DlISize(1, 1));
82 builder.SetCompositor();
83 builder.GetCompositor().present_layers_callback =
84 [](const FlutterLayer** layers, size_t layers_count, void* user_data) {
85 return true;
86 };
87 builder.GetCompositor().present_view_callback =
88 [](const FlutterPresentViewInfo* info) { return true; };
89 auto engine = builder.LaunchEngine();
90 ASSERT_FALSE(engine.is_valid());
91}
92
93//------------------------------------------------------------------------------
94/// Must be able to render to a custom compositor whose render targets are fully
95/// complete OpenGL textures.
96///
97TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) {
98 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
99
100 EmbedderConfigBuilder builder(context);
101 builder.SetSurface(DlISize(800, 600));
102 builder.SetCompositor();
103 builder.SetDartEntrypoint("can_composite_platform_views");
104
105 builder.SetRenderTargetType(
107
108 fml::CountDownLatch latch(3);
109 context.GetCompositor().SetNextPresentCallback(
111 size_t layers_count) {
112 ASSERT_EQ(layers_count, 3u);
113
114 {
115 FlutterBackingStore backing_store = *layers[0]->backing_store;
116 backing_store.struct_size = sizeof(backing_store);
117 backing_store.type = kFlutterBackingStoreTypeOpenGL;
118 backing_store.did_update = true;
120
121 FlutterRect paint_region_rects[] = {
122 FlutterRectMakeLTRB(0, 0, 800, 600),
123 };
124 FlutterRegion paint_region = {
125 .struct_size = sizeof(FlutterRegion),
126 .rects_count = 1,
127 .rects = paint_region_rects,
128 };
129 FlutterBackingStorePresentInfo present_info = {
131 .paint_region = &paint_region,
132 };
133
134 FlutterLayer layer = {};
135 layer.struct_size = sizeof(layer);
137 layer.backing_store = &backing_store;
138 layer.size = FlutterSizeMake(800.0, 600.0);
139 layer.offset = FlutterPointMake(0, 0);
140 layer.backing_store_present_info = &present_info;
141
142 ASSERT_EQ(*layers[0], layer);
143 }
144
145 {
148 platform_view.identifier = 42;
149
150 FlutterLayer layer = {};
151 layer.struct_size = sizeof(layer);
154 layer.size = FlutterSizeMake(123.0, 456.0);
155 layer.offset = FlutterPointMake(1.0, 2.0);
156
157 ASSERT_EQ(*layers[1], layer);
158 }
159
160 {
161 FlutterBackingStore backing_store = *layers[2]->backing_store;
162 backing_store.struct_size = sizeof(backing_store);
163 backing_store.type = kFlutterBackingStoreTypeOpenGL;
164 backing_store.did_update = true;
166
167 FlutterRect paint_region_rects[] = {
168 FlutterRectMakeLTRB(2, 3, 800, 600),
169 };
170 FlutterRegion paint_region = {
171 .struct_size = sizeof(FlutterRegion),
172 .rects_count = 1,
173 .rects = paint_region_rects,
174 };
175 FlutterBackingStorePresentInfo present_info = {
177 .paint_region = &paint_region,
178 };
179
180 FlutterLayer layer = {};
181 layer.struct_size = sizeof(layer);
183 layer.backing_store = &backing_store;
184 layer.size = FlutterSizeMake(800.0, 600.0);
185 layer.offset = FlutterPointMake(0.0, 0.0);
186 layer.backing_store_present_info = &present_info;
187
188 ASSERT_EQ(*layers[2], layer);
189 }
190
191 latch.CountDown();
192 });
193
194 context.AddNativeCallback(
195 "SignalNativeTest",
197 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
198
199 auto engine = builder.LaunchEngine();
200
201 // Send a window metrics events so frames may be scheduled.
202 FlutterWindowMetricsEvent event = {};
203 event.struct_size = sizeof(event);
204 event.width = 800;
205 event.height = 600;
206 event.pixel_ratio = 1.0;
207 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
208 kSuccess);
209 ASSERT_TRUE(engine.is_valid());
210
211 latch.Wait();
212}
213
214//------------------------------------------------------------------------------
215/// Layers in a hierarchy containing a platform view should not be cached. The
216/// other layers in the hierarchy should be, however.
217TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) {
218 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
219
220 EmbedderConfigBuilder builder(context);
221 builder.SetSurface(DlISize(800, 600));
222 builder.SetCompositor();
223 builder.SetDartEntrypoint("can_composite_platform_views_with_opacity");
224
225 builder.SetRenderTargetType(
227
228 fml::CountDownLatch setup(3);
229 fml::CountDownLatch verify(1);
230
231 context.GetCompositor().SetNextPresentCallback(
233 size_t layers_count) {
234 ASSERT_EQ(layers_count, 3u);
235
236 {
237 FlutterBackingStore backing_store = *layers[0]->backing_store;
238 backing_store.struct_size = sizeof(backing_store);
239 backing_store.type = kFlutterBackingStoreTypeOpenGL;
240 backing_store.did_update = true;
242
243 FlutterRect paint_region_rects[] = {
244 FlutterRectMakeLTRB(0, 0, 800, 600),
245 };
246 FlutterRegion paint_region = {
247 .struct_size = sizeof(FlutterRegion),
248 .rects_count = 1,
249 .rects = paint_region_rects,
250 };
251 FlutterBackingStorePresentInfo present_info = {
253 .paint_region = &paint_region,
254 };
255
256 FlutterLayer layer = {};
257 layer.struct_size = sizeof(layer);
259 layer.backing_store = &backing_store;
260 layer.size = FlutterSizeMake(800.0, 600.0);
261 layer.offset = FlutterPointMake(0, 0);
262 layer.backing_store_present_info = &present_info;
263
264 ASSERT_EQ(*layers[0], layer);
265 }
266
267 {
270 platform_view.identifier = 42;
271
272 FlutterLayer layer = {};
273 layer.struct_size = sizeof(layer);
276 layer.size = FlutterSizeMake(123.0, 456.0);
277 layer.offset = FlutterPointMake(1.0, 2.0);
278
279 ASSERT_EQ(*layers[1], layer);
280 }
281
282 {
283 FlutterBackingStore backing_store = *layers[2]->backing_store;
284 backing_store.struct_size = sizeof(backing_store);
285 backing_store.type = kFlutterBackingStoreTypeOpenGL;
286 backing_store.did_update = true;
288
289 FlutterRect paint_region_rects[] = {
290 FlutterRectMakeLTRB(3, 3, 800, 600),
291 };
292 FlutterRegion paint_region = {
293 .struct_size = sizeof(FlutterRegion),
294 .rects_count = 1,
295 .rects = paint_region_rects,
296 };
297 FlutterBackingStorePresentInfo present_info = {
299 .paint_region = &paint_region,
300 };
301
302 FlutterLayer layer = {};
303 layer.struct_size = sizeof(layer);
305 layer.backing_store = &backing_store;
306 layer.size = FlutterSizeMake(800.0, 600.0);
307 layer.offset = FlutterPointMake(0.0, 0.0);
308 layer.backing_store_present_info = &present_info;
309
310 ASSERT_EQ(*layers[2], layer);
311 }
312
313 setup.CountDown();
314 });
315
316 context.AddNativeCallback(
317 "SignalNativeTest",
319 [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
320
321 UniqueEngine engine = builder.LaunchEngine();
322
323 // Send a window metrics events so frames may be scheduled.
324 FlutterWindowMetricsEvent event = {};
325 event.struct_size = sizeof(event);
326 event.width = 800;
327 event.height = 600;
328 event.pixel_ratio = 1.0;
329 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
330 kSuccess);
331 ASSERT_TRUE(engine.is_valid());
332
333 setup.Wait();
334 const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
336 const flutter::RasterCache& raster_cache =
337 shell.GetRasterizer()->compositor_context()->raster_cache();
338 // 3 layers total, but one of them had the platform view. So the cache
339 // should only have 2 entries.
340 ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 2u);
341 verify.CountDown();
342 });
343
344 verify.Wait();
345}
346
347//------------------------------------------------------------------------------
348/// The RasterCache should normally be enabled.
349///
350TEST_F(EmbedderTest, RasterCacheEnabled) {
351 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
352
353 EmbedderConfigBuilder builder(context);
354 builder.SetSurface(DlISize(800, 600));
355 builder.SetCompositor();
356 builder.SetDartEntrypoint("can_composite_with_opacity");
357
358 builder.SetRenderTargetType(
360
361 fml::CountDownLatch setup(3);
362 fml::CountDownLatch verify(1);
363
364 context.GetCompositor().SetNextPresentCallback(
366 size_t layers_count) {
367 ASSERT_EQ(layers_count, 1u);
368
369 {
370 FlutterBackingStore backing_store = *layers[0]->backing_store;
371 backing_store.struct_size = sizeof(backing_store);
372 backing_store.type = kFlutterBackingStoreTypeOpenGL;
373 backing_store.did_update = true;
375
376 FlutterRect paint_region_rects[] = {
377 FlutterRectMakeLTRB(0, 0, 800, 600),
378 };
379 FlutterRegion paint_region = {
380 .struct_size = sizeof(FlutterRegion),
381 .rects_count = 1,
382 .rects = paint_region_rects,
383 };
384 FlutterBackingStorePresentInfo present_info = {
386 .paint_region = &paint_region,
387 };
388
389 FlutterLayer layer = {};
390 layer.struct_size = sizeof(layer);
392 layer.backing_store = &backing_store;
393 layer.size = FlutterSizeMake(800.0, 600.0);
394 layer.offset = FlutterPointMake(0, 0);
395 layer.backing_store_present_info = &present_info;
396
397 ASSERT_EQ(*layers[0], layer);
398 }
399
400 setup.CountDown();
401 });
402
403 context.AddNativeCallback(
404 "SignalNativeTest",
406 [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
407
408 UniqueEngine engine = builder.LaunchEngine();
409
410 // Send a window metrics events so frames may be scheduled.
411 FlutterWindowMetricsEvent event = {};
412 event.struct_size = sizeof(event);
413 event.width = 800;
414 event.height = 600;
415 event.pixel_ratio = 1.0;
416 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
417 kSuccess);
418 ASSERT_TRUE(engine.is_valid());
419
420 setup.Wait();
421 const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
423 const flutter::RasterCache& raster_cache =
424 shell.GetRasterizer()->compositor_context()->raster_cache();
425 ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 1u);
426 verify.CountDown();
427 });
428
429 verify.Wait();
430}
431
432//------------------------------------------------------------------------------
433/// Must be able to render using a custom compositor whose render targets for
434/// the individual layers are OpenGL textures.
435///
436TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) {
437 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
438
439 EmbedderConfigBuilder builder(context);
440 builder.SetSurface(DlISize(800, 600));
441 builder.SetCompositor();
442 builder.SetDartEntrypoint("can_composite_platform_views");
443
444 builder.SetRenderTargetType(
446
447 fml::CountDownLatch latch(3);
448 context.GetCompositor().SetNextPresentCallback(
450 size_t layers_count) {
451 ASSERT_EQ(layers_count, 3u);
452
453 {
454 FlutterBackingStore backing_store = *layers[0]->backing_store;
455 backing_store.struct_size = sizeof(backing_store);
456 backing_store.type = kFlutterBackingStoreTypeOpenGL;
457 backing_store.did_update = true;
459
460 FlutterRect paint_region_rects[] = {
461 FlutterRectMakeLTRB(0, 0, 800, 600),
462 };
463 FlutterRegion paint_region = {
464 .struct_size = sizeof(FlutterRegion),
465 .rects_count = 1,
466 .rects = paint_region_rects,
467 };
468 FlutterBackingStorePresentInfo present_info = {
470 .paint_region = &paint_region,
471 };
472
473 FlutterLayer layer = {};
474 layer.struct_size = sizeof(layer);
476 layer.backing_store = &backing_store;
477 layer.size = FlutterSizeMake(800.0, 600.0);
478 layer.offset = FlutterPointMake(0, 0);
479 layer.backing_store_present_info = &present_info;
480
481 ASSERT_EQ(*layers[0], layer);
482 }
483
484 {
487 platform_view.identifier = 42;
488
489 FlutterLayer layer = {};
490 layer.struct_size = sizeof(layer);
493 layer.size = FlutterSizeMake(123.0, 456.0);
494 layer.offset = FlutterPointMake(1.0, 2.0);
495
496 ASSERT_EQ(*layers[1], layer);
497 }
498
499 {
500 FlutterBackingStore backing_store = *layers[2]->backing_store;
501 backing_store.struct_size = sizeof(backing_store);
502 backing_store.type = kFlutterBackingStoreTypeOpenGL;
503 backing_store.did_update = true;
505
506 FlutterRect paint_region_rects[] = {
507 FlutterRectMakeLTRB(2, 3, 800, 600),
508 };
509 FlutterRegion paint_region = {
510 .struct_size = sizeof(FlutterRegion),
511 .rects_count = 1,
512 .rects = paint_region_rects,
513 };
514 FlutterBackingStorePresentInfo present_info = {
516 .paint_region = &paint_region,
517 };
518
519 FlutterLayer layer = {};
520 layer.struct_size = sizeof(layer);
522 layer.backing_store = &backing_store;
523 layer.size = FlutterSizeMake(800.0, 600.0);
524 layer.offset = FlutterPointMake(0.0, 0.0);
525 layer.backing_store_present_info = &present_info;
526
527 ASSERT_EQ(*layers[2], layer);
528 }
529
530 latch.CountDown();
531 });
532
533 context.AddNativeCallback(
534 "SignalNativeTest",
536 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
537
538 auto engine = builder.LaunchEngine();
539
540 // Send a window metrics events so frames may be scheduled.
541 FlutterWindowMetricsEvent event = {};
542 event.struct_size = sizeof(event);
543 event.width = 800;
544 event.height = 600;
545 event.pixel_ratio = 1.0;
546 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
547 kSuccess);
548 ASSERT_TRUE(engine.is_valid());
549
550 latch.Wait();
551}
552
553//------------------------------------------------------------------------------
554/// Must be able to render using a custom compositor whose render target for the
555/// individual layers are software buffers.
556///
557TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) {
558 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
559
560 EmbedderConfigBuilder builder(context);
561 builder.SetSurface(DlISize(800, 600));
562 builder.SetCompositor();
563 builder.SetDartEntrypoint("can_composite_platform_views");
564
565 builder.SetRenderTargetType(
567
568 fml::CountDownLatch latch(3);
569 context.GetCompositor().SetNextPresentCallback(
571 size_t layers_count) {
572 ASSERT_EQ(layers_count, 3u);
573
574 {
575 FlutterBackingStore backing_store = *layers[0]->backing_store;
576 backing_store.struct_size = sizeof(backing_store);
578 backing_store.did_update = true;
579 ASSERT_FLOAT_EQ(
580 backing_store.software.row_bytes * backing_store.software.height,
581 800 * 4 * 600.0);
582
583 FlutterRect paint_region_rects[] = {
584 FlutterRectMakeLTRB(0, 0, 800, 600),
585 };
586 FlutterRegion paint_region = {
587 .struct_size = sizeof(FlutterRegion),
588 .rects_count = 1,
589 .rects = paint_region_rects,
590 };
591 FlutterBackingStorePresentInfo present_info = {
593 .paint_region = &paint_region,
594 };
595
596 FlutterLayer layer = {};
597 layer.struct_size = sizeof(layer);
599 layer.backing_store = &backing_store;
600 layer.size = FlutterSizeMake(800.0, 600.0);
601 layer.offset = FlutterPointMake(0, 0);
602 layer.backing_store_present_info = &present_info;
603
604 ASSERT_EQ(*layers[0], layer);
605 }
606
607 {
610 platform_view.identifier = 42;
611
612 FlutterLayer layer = {};
613 layer.struct_size = sizeof(layer);
616 layer.size = FlutterSizeMake(123.0, 456.0);
617 layer.offset = FlutterPointMake(1.0, 2.0);
618
619 ASSERT_EQ(*layers[1], layer);
620 }
621
622 {
623 FlutterBackingStore backing_store = *layers[2]->backing_store;
624 backing_store.struct_size = sizeof(backing_store);
626 backing_store.did_update = true;
627
628 FlutterRect paint_region_rects[] = {
629 FlutterRectMakeLTRB(2, 3, 800, 600),
630 };
631 FlutterRegion paint_region = {
632 .struct_size = sizeof(FlutterRegion),
633 .rects_count = 1,
634 .rects = paint_region_rects,
635 };
636 FlutterBackingStorePresentInfo present_info = {
638 .paint_region = &paint_region,
639 };
640
641 FlutterLayer layer = {};
642 layer.struct_size = sizeof(layer);
644 layer.backing_store = &backing_store;
645 layer.size = FlutterSizeMake(800.0, 600.0);
646 layer.offset = FlutterPointMake(0.0, 0.0);
647 layer.backing_store_present_info = &present_info;
648
649 ASSERT_EQ(*layers[2], layer);
650 }
651
652 latch.CountDown();
653 });
654
655 context.AddNativeCallback(
656 "SignalNativeTest",
658 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
659
660 auto engine = builder.LaunchEngine();
661
662 // Send a window metrics events so frames may be scheduled.
663 FlutterWindowMetricsEvent event = {};
664 event.struct_size = sizeof(event);
665 event.width = 800;
666 event.height = 600;
667 event.pixel_ratio = 1.0;
668 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
669 kSuccess);
670 ASSERT_TRUE(engine.is_valid());
671
672 latch.Wait();
673}
674
675//------------------------------------------------------------------------------
676/// Test the layer structure and pixels rendered when using a custom compositor.
677///
678TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) {
679 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
680
681 EmbedderConfigBuilder builder(context);
682 builder.SetSurface(DlISize(800, 600));
683 builder.SetCompositor();
684 builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
685
686 builder.SetRenderTargetType(
688
689 fml::CountDownLatch latch(5);
690
691 auto scene_image = context.GetNextSceneImage();
692
693 context.GetCompositor().SetNextPresentCallback(
695 size_t layers_count) {
696 ASSERT_EQ(layers_count, 5u);
697
698 // Layer Root
699 {
700 FlutterBackingStore backing_store = *layers[0]->backing_store;
701 backing_store.type = kFlutterBackingStoreTypeOpenGL;
702 backing_store.did_update = true;
704
705 FlutterRect paint_region_rects[] = {
706 FlutterRectMakeLTRB(0, 0, 800, 600),
707 };
708 FlutterRegion paint_region = {
709 .struct_size = sizeof(FlutterRegion),
710 .rects_count = 1,
711 .rects = paint_region_rects,
712 };
713 FlutterBackingStorePresentInfo present_info = {
715 .paint_region = &paint_region,
716 };
717
718 FlutterLayer layer = {};
719 layer.struct_size = sizeof(layer);
721 layer.backing_store = &backing_store;
722 layer.size = FlutterSizeMake(800.0, 600.0);
723 layer.offset = FlutterPointMake(0.0, 0.0);
724 layer.backing_store_present_info = &present_info;
725
726 ASSERT_EQ(*layers[0], layer);
727 }
728
729 // Layer 1
730 {
733 platform_view.identifier = 1;
734
735 FlutterLayer layer = {};
736 layer.struct_size = sizeof(layer);
739 layer.size = FlutterSizeMake(50.0, 150.0);
740 layer.offset = FlutterPointMake(20.0, 20.0);
741
742 ASSERT_EQ(*layers[1], layer);
743 }
744
745 // Layer 2
746 {
747 FlutterBackingStore backing_store = *layers[2]->backing_store;
748 backing_store.type = kFlutterBackingStoreTypeOpenGL;
749 backing_store.did_update = true;
751
752 FlutterRect paint_region_rects[] = {
753 FlutterRectMakeLTRB(30, 30, 80, 180),
754 };
755 FlutterRegion paint_region = {
756 .struct_size = sizeof(FlutterRegion),
757 .rects_count = 1,
758 .rects = paint_region_rects,
759 };
760 FlutterBackingStorePresentInfo present_info = {
762 .paint_region = &paint_region,
763 };
764
765 FlutterLayer layer = {};
766 layer.struct_size = sizeof(layer);
768 layer.backing_store = &backing_store;
769 layer.size = FlutterSizeMake(800.0, 600.0);
770 layer.offset = FlutterPointMake(0.0, 0.0);
771 layer.backing_store_present_info = &present_info;
772
773 ASSERT_EQ(*layers[2], layer);
774 }
775
776 // Layer 3
777 {
780 platform_view.identifier = 2;
781
782 FlutterLayer layer = {};
783 layer.struct_size = sizeof(layer);
786 layer.size = FlutterSizeMake(50.0, 150.0);
787 layer.offset = FlutterPointMake(40.0, 40.0);
788
789 ASSERT_EQ(*layers[3], layer);
790 }
791
792 // Layer 4
793 {
794 FlutterBackingStore backing_store = *layers[4]->backing_store;
795 backing_store.type = kFlutterBackingStoreTypeOpenGL;
796 backing_store.did_update = true;
798
799 FlutterRect paint_region_rects[] = {
800 FlutterRectMakeLTRB(50, 50, 100, 200),
801 };
802 FlutterRegion paint_region = {
803 .struct_size = sizeof(FlutterRegion),
804 .rects_count = 1,
805 .rects = paint_region_rects,
806 };
807 FlutterBackingStorePresentInfo present_info = {
809 .paint_region = &paint_region,
810 };
811
812 FlutterLayer layer = {};
813 layer.struct_size = sizeof(layer);
815 layer.backing_store = &backing_store;
816 layer.size = FlutterSizeMake(800.0, 600.0);
817 layer.offset = FlutterPointMake(0.0, 0.0);
818 layer.backing_store_present_info = &present_info;
819
820 ASSERT_EQ(*layers[4], layer);
821 }
822
823 latch.CountDown();
824 });
825
826 context.GetCompositor().SetPlatformViewRendererCallback(
827 [&](const FlutterLayer& layer,
828 GrDirectContext* context) -> sk_sp<SkImage> {
829 auto surface = CreateRenderSurface(layer, context);
830 auto canvas = surface->getCanvas();
831 FML_CHECK(canvas != nullptr);
832
833 switch (layer.platform_view->identifier) {
834 case 1: {
835 SkPaint paint;
836 // See dart test for total order.
837 paint.setColor(SK_ColorGREEN);
838 paint.setAlpha(127);
839 const auto& rect =
840 SkRect::MakeWH(layer.size.width, layer.size.height);
841 canvas->drawRect(rect, paint);
842 latch.CountDown();
843 } break;
844 case 2: {
845 SkPaint paint;
846 // See dart test for total order.
847 paint.setColor(SK_ColorMAGENTA);
848 paint.setAlpha(127);
849 const auto& rect =
850 SkRect::MakeWH(layer.size.width, layer.size.height);
851 canvas->drawRect(rect, paint);
852 latch.CountDown();
853 } break;
854 default:
855 // Asked to render an unknown platform view.
856 FML_CHECK(false)
857 << "Test was asked to composite an unknown platform view.";
858 }
859
860 return surface->makeImageSnapshot();
861 });
862
863 context.AddNativeCallback(
864 "SignalNativeTest",
866 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
867
868 auto engine = builder.LaunchEngine();
869
870 // Send a window metrics events so frames may be scheduled.
871 FlutterWindowMetricsEvent event = {};
872 event.struct_size = sizeof(event);
873 event.width = 800;
874 event.height = 600;
875 event.pixel_ratio = 1.0;
876 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
877 kSuccess);
878 ASSERT_TRUE(engine.is_valid());
879
880 latch.Wait();
881
882 ASSERT_TRUE(ImageMatchesFixture("compositor.png", scene_image));
883
884 // There should no present calls on the root surface.
885 ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
886}
887
888//------------------------------------------------------------------------------
889/// Custom compositor must play nicely with a custom task runner. The raster
890/// thread merging mechanism must not interfere with the custom compositor.
891///
892TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) {
893 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
894
895 EmbedderConfigBuilder builder(context);
896
897 builder.SetSurface(DlISize(800, 600));
898 builder.SetCompositor();
899 builder.SetDartEntrypoint("can_composite_platform_views");
900
901 auto platform_task_runner = CreateNewThread("test_platform_thread");
902 static std::mutex engine_mutex;
905
906 EmbedderTestTaskRunner test_task_runner(
907 platform_task_runner, [&](FlutterTask task) {
908 std::scoped_lock lock(engine_mutex);
909 if (!engine.is_valid()) {
910 return;
911 }
912 ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
913 });
914
915 builder.SetRenderTargetType(
917
918 fml::CountDownLatch latch(3);
919 context.GetCompositor().SetNextPresentCallback(
921 size_t layers_count) {
922 ASSERT_EQ(layers_count, 3u);
923
924 {
925 FlutterBackingStore backing_store = *layers[0]->backing_store;
926 backing_store.struct_size = sizeof(backing_store);
927 backing_store.type = kFlutterBackingStoreTypeOpenGL;
928 backing_store.did_update = true;
930
931 FlutterRect paint_region_rects[] = {
932 FlutterRectMakeLTRB(0, 0, 800, 600),
933 };
934 FlutterRegion paint_region = {
935 .struct_size = sizeof(FlutterRegion),
936 .rects_count = 1,
937 .rects = paint_region_rects,
938 };
939 FlutterBackingStorePresentInfo present_info = {
941 .paint_region = &paint_region,
942 };
943
944 FlutterLayer layer = {};
945 layer.struct_size = sizeof(layer);
947 layer.backing_store = &backing_store;
948 layer.size = FlutterSizeMake(800.0, 600.0);
949 layer.offset = FlutterPointMake(0, 0);
950 layer.backing_store_present_info = &present_info;
951
952 ASSERT_EQ(*layers[0], layer);
953 }
954
955 {
958 platform_view.identifier = 42;
959
960 FlutterRect paint_region_rects[] = {
961 FlutterRectMakeLTRB(2, 3, 800, 600),
962 };
963 FlutterRegion paint_region = {
964 .struct_size = sizeof(FlutterRegion),
965 .rects_count = 1,
966 .rects = paint_region_rects,
967 };
968 FlutterBackingStorePresentInfo present_info = {
970 .paint_region = &paint_region,
971 };
972
973 FlutterLayer layer = {};
974 layer.struct_size = sizeof(layer);
977 layer.size = FlutterSizeMake(123.0, 456.0);
978 layer.offset = FlutterPointMake(1.0, 2.0);
979 layer.backing_store_present_info = &present_info;
980
981 ASSERT_EQ(*layers[1], layer);
982 }
983
984 {
985 FlutterBackingStore backing_store = *layers[2]->backing_store;
986 backing_store.struct_size = sizeof(backing_store);
987 backing_store.type = kFlutterBackingStoreTypeOpenGL;
988 backing_store.did_update = true;
990
991 FlutterRect paint_region_rects[] = {
992 FlutterRectMakeLTRB(2, 3, 800, 600),
993 };
994 FlutterRegion paint_region = {
995 .struct_size = sizeof(FlutterRegion),
996 .rects_count = 1,
997 .rects = paint_region_rects,
998 };
999 FlutterBackingStorePresentInfo present_info = {
1001 .paint_region = &paint_region,
1002 };
1003
1004 FlutterLayer layer = {};
1005 layer.struct_size = sizeof(layer);
1007 layer.backing_store = &backing_store;
1008 layer.size = FlutterSizeMake(800.0, 600.0);
1009 layer.offset = FlutterPointMake(0.0, 0.0);
1010 layer.backing_store_present_info = &present_info;
1011
1012 ASSERT_EQ(*layers[2], layer);
1013 }
1014
1015 latch.CountDown();
1016 });
1017
1018 const auto task_runner_description =
1019 test_task_runner.GetFlutterTaskRunnerDescription();
1020
1021 builder.SetPlatformTaskRunner(&task_runner_description);
1022
1023 context.AddNativeCallback(
1024 "SignalNativeTest",
1026 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1027
1028 platform_task_runner->PostTask([&]() {
1029 std::scoped_lock lock(engine_mutex);
1030 engine = builder.LaunchEngine();
1031 ASSERT_TRUE(engine.is_valid());
1032
1033 // Send a window metrics events so frames may be scheduled.
1034 FlutterWindowMetricsEvent event = {};
1035 event.struct_size = sizeof(event);
1036 event.width = 800;
1037 event.height = 600;
1038 event.pixel_ratio = 1.0;
1039 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1040 kSuccess);
1041 ASSERT_TRUE(engine.is_valid());
1042 sync_latch.Signal();
1043 });
1044 sync_latch.Wait();
1045
1046 latch.Wait();
1047
1048 platform_task_runner->PostTask([&]() {
1049 std::scoped_lock lock(engine_mutex);
1050 engine.reset();
1051 sync_latch.Signal();
1052 });
1053 sync_latch.Wait();
1054}
1055
1056//------------------------------------------------------------------------------
1057/// Test the layer structure and pixels rendered when using a custom compositor
1058/// and a single layer.
1059///
1060TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) {
1061 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1062
1063 EmbedderConfigBuilder builder(context);
1064 builder.SetSurface(DlISize(800, 600));
1065 builder.SetCompositor();
1066 builder.SetDartEntrypoint(
1067 "can_composite_platform_views_with_root_layer_only");
1068
1069 builder.SetRenderTargetType(
1071
1072 fml::CountDownLatch latch(3);
1073
1074 auto scene_image = context.GetNextSceneImage();
1075
1076 context.GetCompositor().SetNextPresentCallback(
1078 size_t layers_count) {
1079 ASSERT_EQ(layers_count, 1u);
1080
1081 // Layer Root
1082 {
1083 FlutterBackingStore backing_store = *layers[0]->backing_store;
1084 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1085 backing_store.did_update = true;
1087
1088 FlutterRect paint_region_rects[] = {
1089 FlutterRectMakeLTRB(0, 0, 800, 600),
1090 };
1091 FlutterRegion paint_region = {
1092 .struct_size = sizeof(FlutterRegion),
1093 .rects_count = 1,
1094 .rects = paint_region_rects,
1095 };
1096 FlutterBackingStorePresentInfo present_info = {
1098 .paint_region = &paint_region,
1099 };
1100
1101 FlutterLayer layer = {};
1102 layer.struct_size = sizeof(layer);
1104 layer.backing_store = &backing_store;
1105 layer.size = FlutterSizeMake(800.0, 600.0);
1106 layer.offset = FlutterPointMake(0.0, 0.0);
1107 layer.backing_store_present_info = &present_info;
1108
1109 ASSERT_EQ(*layers[0], layer);
1110 }
1111
1112 latch.CountDown();
1113 });
1114
1115 context.AddNativeCallback(
1116 "SignalNativeTest",
1118 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1119
1120 auto engine = builder.LaunchEngine();
1121
1122 // Send a window metrics events so frames may be scheduled.
1123 FlutterWindowMetricsEvent event = {};
1124 event.struct_size = sizeof(event);
1125 event.width = 800;
1126 event.height = 600;
1127 event.pixel_ratio = 1.0;
1128 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1129 kSuccess);
1130 ASSERT_TRUE(engine.is_valid());
1131
1132 latch.Wait();
1133
1134 ASSERT_TRUE(
1135 ImageMatchesFixture("compositor_with_root_layer_only.png", scene_image));
1136}
1137
1138//------------------------------------------------------------------------------
1139/// Test the layer structure and pixels rendered when using a custom compositor
1140/// and ensure that a redundant layer is not added.
1141///
1142TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) {
1143 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1144
1145 EmbedderConfigBuilder builder(context);
1146 builder.SetSurface(DlISize(800, 600));
1147 builder.SetCompositor();
1148 builder.SetDartEntrypoint(
1149 "can_composite_platform_views_with_platform_layer_on_bottom");
1150
1151 builder.SetRenderTargetType(
1153
1154 fml::CountDownLatch latch(3);
1155
1156 auto scene_image = context.GetNextSceneImage();
1157
1158 context.GetCompositor().SetNextPresentCallback(
1160 size_t layers_count) {
1161 ASSERT_EQ(layers_count, 2u);
1162
1163 // Layer Root
1164 {
1165 FlutterBackingStore backing_store = *layers[0]->backing_store;
1166 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1167 backing_store.did_update = true;
1169
1170 FlutterRect paint_region_rects[] = {
1171 FlutterRectMakeLTRB(0, 0, 800, 600),
1172 };
1173 FlutterRegion paint_region = {
1174 .struct_size = sizeof(FlutterRegion),
1175 .rects_count = 1,
1176 .rects = paint_region_rects,
1177 };
1178 FlutterBackingStorePresentInfo present_info = {
1180 .paint_region = &paint_region,
1181 };
1182
1183 FlutterLayer layer = {};
1184 layer.struct_size = sizeof(layer);
1186 layer.backing_store = &backing_store;
1187 layer.size = FlutterSizeMake(800.0, 600.0);
1188 layer.offset = FlutterPointMake(0.0, 0.0);
1189 layer.backing_store_present_info = &present_info;
1190
1191 ASSERT_EQ(*layers[0], layer);
1192 }
1193
1194 // Layer 1
1195 {
1198 platform_view.identifier = 1;
1199
1200 FlutterLayer layer = {};
1201 layer.struct_size = sizeof(layer);
1204 layer.size = FlutterSizeMake(50.0, 150.0);
1205 layer.offset = FlutterPointMake(20.0, 20.0);
1206
1207 ASSERT_EQ(*layers[1], layer);
1208 }
1209
1210 latch.CountDown();
1211 });
1212
1213 context.GetCompositor().SetPlatformViewRendererCallback(
1214 [&](const FlutterLayer& layer,
1215 GrDirectContext* context) -> sk_sp<SkImage> {
1216 auto surface = CreateRenderSurface(layer, context);
1217 auto canvas = surface->getCanvas();
1218 FML_CHECK(canvas != nullptr);
1219
1220 switch (layer.platform_view->identifier) {
1221 case 1: {
1222 SkPaint paint;
1223 // See dart test for total order.
1224 paint.setColor(SK_ColorGREEN);
1225 paint.setAlpha(127);
1226 const auto& rect =
1227 SkRect::MakeWH(layer.size.width, layer.size.height);
1228 canvas->drawRect(rect, paint);
1229 latch.CountDown();
1230 } break;
1231 default:
1232 // Asked to render an unknown platform view.
1233 FML_CHECK(false)
1234 << "Test was asked to composite an unknown platform view.";
1235 }
1236
1237 return surface->makeImageSnapshot();
1238 });
1239
1240 context.AddNativeCallback(
1241 "SignalNativeTest",
1243 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1244
1245 auto engine = builder.LaunchEngine();
1246
1247 // Send a window metrics events so frames may be scheduled.
1248 FlutterWindowMetricsEvent event = {};
1249 event.struct_size = sizeof(event);
1250 event.width = 800;
1251 event.height = 600;
1252 event.pixel_ratio = 1.0;
1253 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1254 kSuccess);
1255 ASSERT_TRUE(engine.is_valid());
1256
1257 latch.Wait();
1258
1259 ASSERT_TRUE(ImageMatchesFixture(
1260 "compositor_with_platform_layer_on_bottom.png", scene_image));
1261
1262 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 1u);
1263}
1264
1265//------------------------------------------------------------------------------
1266/// Test the layer structure and pixels rendered when using a custom compositor
1267/// with a root surface transformation.
1268///
1270 CompositorMustBeAbleToRenderKnownSceneWithRootSurfaceTransformation) {
1271 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1272
1273 EmbedderConfigBuilder builder(context);
1274 builder.SetSurface(DlISize(600, 800));
1275 builder.SetCompositor();
1276 builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
1277
1278 builder.SetRenderTargetType(
1280
1281 // This must match the transformation provided in the
1282 // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1283 // transforms are consistent respected.
1284 const auto root_surface_transformation =
1285 DlMatrix::MakeTranslation({0, 800}) *
1287
1288 context.SetRootSurfaceTransformation(root_surface_transformation);
1289
1290 fml::CountDownLatch latch(5);
1291
1292 auto scene_image = context.GetNextSceneImage();
1293
1294 context.GetCompositor().SetNextPresentCallback(
1296 size_t layers_count) {
1297 ASSERT_EQ(layers_count, 5u);
1298
1299 // Layer Root
1300 {
1301 FlutterBackingStore backing_store = *layers[0]->backing_store;
1302 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1303 backing_store.did_update = true;
1305
1306 FlutterRect paint_region_rects[] = {
1307 FlutterRectMakeLTRB(0, 0, 600, 800),
1308 };
1309 FlutterRegion paint_region = {
1310 .struct_size = sizeof(FlutterRegion),
1311 .rects_count = 1,
1312 .rects = paint_region_rects,
1313 };
1314 FlutterBackingStorePresentInfo present_info = {
1316 .paint_region = &paint_region,
1317 };
1318
1319 FlutterLayer layer = {};
1320 layer.struct_size = sizeof(layer);
1322 layer.backing_store = &backing_store;
1323 layer.size = FlutterSizeMake(600.0, 800.0);
1324 layer.offset = FlutterPointMake(0.0, 0.0);
1325 layer.backing_store_present_info = &present_info;
1326
1327 ASSERT_EQ(*layers[0], layer);
1328 }
1329
1330 // Layer 1
1331 {
1334 platform_view.identifier = 1;
1335
1336 FlutterLayer layer = {};
1337 layer.struct_size = sizeof(layer);
1340 layer.size = FlutterSizeMake(150.0, 50.0);
1341 layer.offset = FlutterPointMake(20.0, 730.0);
1342
1343 ASSERT_EQ(*layers[1], layer);
1344 }
1345
1346 // Layer 2
1347 {
1348 FlutterBackingStore backing_store = *layers[2]->backing_store;
1349 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1350 backing_store.did_update = true;
1352
1353 FlutterRect paint_region_rects[] = {
1354 FlutterRectMakeLTRB(30, 720, 180, 770),
1355 };
1356 FlutterRegion paint_region = {
1357 .struct_size = sizeof(FlutterRegion),
1358 .rects_count = 1,
1359 .rects = paint_region_rects,
1360 };
1361 FlutterBackingStorePresentInfo present_info = {
1363 .paint_region = &paint_region,
1364 };
1365
1366 FlutterLayer layer = {};
1367 layer.struct_size = sizeof(layer);
1369 layer.backing_store = &backing_store;
1370 layer.size = FlutterSizeMake(600.0, 800.0);
1371 layer.offset = FlutterPointMake(0.0, 0.0);
1372 layer.backing_store_present_info = &present_info;
1373
1374 ASSERT_EQ(*layers[2], layer);
1375 }
1376
1377 // Layer 3
1378 {
1381 platform_view.identifier = 2;
1382
1383 FlutterLayer layer = {};
1384 layer.struct_size = sizeof(layer);
1387 layer.size = FlutterSizeMake(150.0, 50.0);
1388 layer.offset = FlutterPointMake(40.0, 710.0);
1389
1390 ASSERT_EQ(*layers[3], layer);
1391 }
1392
1393 // Layer 4
1394 {
1395 FlutterBackingStore backing_store = *layers[4]->backing_store;
1396 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1397 backing_store.did_update = true;
1399
1400 FlutterRect paint_region_rects[] = {
1401 FlutterRectMakeLTRB(50, 700, 200, 750),
1402 };
1403 FlutterRegion paint_region = {
1404 .struct_size = sizeof(FlutterRegion),
1405 .rects_count = 1,
1406 .rects = paint_region_rects,
1407 };
1408 FlutterBackingStorePresentInfo present_info = {
1410 .paint_region = &paint_region,
1411 };
1412
1413 FlutterLayer layer = {};
1414 layer.struct_size = sizeof(layer);
1416 layer.backing_store = &backing_store;
1417 layer.size = FlutterSizeMake(600.0, 800.0);
1418 layer.offset = FlutterPointMake(0.0, 0.0);
1419 layer.backing_store_present_info = &present_info;
1420
1421 ASSERT_EQ(*layers[4], layer);
1422 }
1423
1424 latch.CountDown();
1425 });
1426
1427 context.GetCompositor().SetPlatformViewRendererCallback(
1428 [&](const FlutterLayer& layer,
1429 GrDirectContext* context) -> sk_sp<SkImage> {
1430 auto surface = CreateRenderSurface(layer, context);
1431 auto canvas = surface->getCanvas();
1432 FML_CHECK(canvas != nullptr);
1433
1434 switch (layer.platform_view->identifier) {
1435 case 1: {
1436 SkPaint paint;
1437 // See dart test for total order.
1438 paint.setColor(SK_ColorGREEN);
1439 paint.setAlpha(127);
1440 const auto& rect =
1441 SkRect::MakeWH(layer.size.width, layer.size.height);
1442 canvas->drawRect(rect, paint);
1443 latch.CountDown();
1444 } break;
1445 case 2: {
1446 SkPaint paint;
1447 // See dart test for total order.
1448 paint.setColor(SK_ColorMAGENTA);
1449 paint.setAlpha(127);
1450 const auto& rect =
1451 SkRect::MakeWH(layer.size.width, layer.size.height);
1452 canvas->drawRect(rect, paint);
1453 latch.CountDown();
1454 } break;
1455 default:
1456 // Asked to render an unknown platform view.
1457 FML_CHECK(false)
1458 << "Test was asked to composite an unknown platform view.";
1459 }
1460
1461 return surface->makeImageSnapshot();
1462 });
1463
1464 context.AddNativeCallback(
1465 "SignalNativeTest",
1467 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1468
1469 auto engine = builder.LaunchEngine();
1470
1471 // Send a window metrics events so frames may be scheduled.
1472 FlutterWindowMetricsEvent event = {};
1473 event.struct_size = sizeof(event);
1474 // Flutter still thinks it is 800 x 600. Only the root surface is rotated.
1475 event.width = 800;
1476 event.height = 600;
1477 event.pixel_ratio = 1.0;
1478 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1479 kSuccess);
1480 ASSERT_TRUE(engine.is_valid());
1481
1482 latch.Wait();
1483
1484 ASSERT_TRUE(ImageMatchesFixture("compositor_root_surface_xformation.png",
1485 scene_image));
1486}
1487
1488TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositor) {
1489 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1490
1491 EmbedderConfigBuilder builder(context);
1492
1493 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1494 builder.SetSurface(DlISize(800, 600));
1495
1496 auto rendered_scene = context.GetNextSceneImage();
1497
1498 auto engine = builder.LaunchEngine();
1499 ASSERT_TRUE(engine.is_valid());
1500
1501 // Send a window metrics events so frames may be scheduled.
1502 FlutterWindowMetricsEvent event = {};
1503 event.struct_size = sizeof(event);
1504 event.width = 800;
1505 event.height = 600;
1506 event.pixel_ratio = 1.0;
1507 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1508 kSuccess);
1509
1510 ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png",
1511 rendered_scene));
1512}
1513
1514TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositorWithTransformation) {
1515 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1516
1517 const auto root_surface_transformation =
1518 DlMatrix::MakeTranslation({0, 800}) *
1520
1521 context.SetRootSurfaceTransformation(root_surface_transformation);
1522
1523 EmbedderConfigBuilder builder(context);
1524
1525 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1526 builder.SetSurface(DlISize(600, 800));
1527
1528 auto rendered_scene = context.GetNextSceneImage();
1529
1530 auto engine = builder.LaunchEngine();
1531 ASSERT_TRUE(engine.is_valid());
1532
1533 // Send a window metrics events so frames may be scheduled.
1534 FlutterWindowMetricsEvent event = {};
1535 event.struct_size = sizeof(event);
1536
1537 // Flutter still thinks it is 800 x 600.
1538 event.width = 800;
1539 event.height = 600;
1540 event.pixel_ratio = 1.0;
1541 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1542 kSuccess);
1543
1544 ASSERT_TRUE(ImageMatchesFixture(
1545 "scene_without_custom_compositor_with_xform.png", rendered_scene));
1546}
1547
1548TEST_P(EmbedderTestMultiBackend, CanRenderGradientWithoutCompositor) {
1549 EmbedderTestContextType backend = GetParam();
1550 auto& context = GetEmbedderContext(backend);
1551 EmbedderConfigBuilder builder(context);
1552 builder.SetDartEntrypoint("render_gradient");
1553 builder.SetSurface(DlISize(800, 600));
1554
1555 auto rendered_scene = context.GetNextSceneImage();
1556
1557 auto engine = builder.LaunchEngine();
1558 ASSERT_TRUE(engine.is_valid());
1559
1560 // Send a window metrics events so frames may be scheduled.
1561 FlutterWindowMetricsEvent event = {};
1562 event.struct_size = sizeof(event);
1563 event.width = 800;
1564 event.height = 600;
1565 event.pixel_ratio = 1.0;
1566 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1567 kSuccess);
1568
1569 ASSERT_TRUE(ImageMatchesFixture(
1570 FixtureNameForBackend(backend, "gradient.png"), rendered_scene));
1571}
1572
1573TEST_F(EmbedderTest, CanRenderGradientWithoutCompositorWithXform) {
1574 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1575
1576 const auto root_surface_transformation =
1577 DlMatrix::MakeTranslation({0, 800}) *
1579
1580 context.SetRootSurfaceTransformation(root_surface_transformation);
1581
1582 EmbedderConfigBuilder builder(context);
1583
1584 const auto surface_size = DlISize(600, 800);
1585
1586 builder.SetDartEntrypoint("render_gradient");
1587 builder.SetSurface(surface_size);
1588
1589 auto rendered_scene = context.GetNextSceneImage();
1590
1591 auto engine = builder.LaunchEngine();
1592 ASSERT_TRUE(engine.is_valid());
1593
1594 // Send a window metrics events so frames may be scheduled.
1595 FlutterWindowMetricsEvent event = {};
1596 event.struct_size = sizeof(event);
1597 // Flutter still thinks it is 800 x 600.
1598 event.width = 800;
1599 event.height = 600;
1600 event.pixel_ratio = 1.0;
1601 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1602 kSuccess);
1603
1604 ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1605}
1606
1607TEST_P(EmbedderTestMultiBackend, CanRenderGradientWithCompositor) {
1608 EmbedderTestContextType backend = GetParam();
1609 auto& context = GetEmbedderContext(backend);
1610
1611 EmbedderConfigBuilder builder(context);
1612 builder.SetDartEntrypoint("render_gradient");
1613 builder.SetSurface(DlISize(800, 600));
1614 builder.SetCompositor();
1615 builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, true));
1616
1617 auto rendered_scene = context.GetNextSceneImage();
1618
1619 auto engine = builder.LaunchEngine();
1620 ASSERT_TRUE(engine.is_valid());
1621
1622 // Send a window metrics events so frames may be scheduled.
1623 FlutterWindowMetricsEvent event = {};
1624 event.struct_size = sizeof(event);
1625 event.width = 800;
1626 event.height = 600;
1627 event.pixel_ratio = 1.0;
1628 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1629 kSuccess);
1630
1631 ASSERT_TRUE(ImageMatchesFixture(
1632 FixtureNameForBackend(backend, "gradient.png"), rendered_scene));
1633}
1634
1635TEST_F(EmbedderTest, CanRenderGradientWithCompositorWithXform) {
1636 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1637
1638 // This must match the transformation provided in the
1639 // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1640 // transforms are consistent respected.
1641 const auto root_surface_transformation =
1642 DlMatrix::MakeTranslation({0, 800}) *
1644
1645 context.SetRootSurfaceTransformation(root_surface_transformation);
1646
1647 EmbedderConfigBuilder builder(context);
1648
1649 builder.SetDartEntrypoint("render_gradient");
1650 builder.SetSurface(DlISize(600, 800));
1651 builder.SetCompositor();
1652 builder.SetRenderTargetType(
1654
1655 auto rendered_scene = context.GetNextSceneImage();
1656
1657 auto engine = builder.LaunchEngine();
1658 ASSERT_TRUE(engine.is_valid());
1659
1660 // Send a window metrics events so frames may be scheduled.
1661 FlutterWindowMetricsEvent event = {};
1662 event.struct_size = sizeof(event);
1663 // Flutter still thinks it is 800 x 600.
1664 event.width = 800;
1665 event.height = 600;
1666 event.pixel_ratio = 1.0;
1667 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1668 kSuccess);
1669
1670 ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1671}
1672
1674 CanRenderGradientWithCompositorOnNonRootLayer) {
1675 EmbedderTestContextType backend = GetParam();
1676 auto& context = GetEmbedderContext(backend);
1677
1678 EmbedderConfigBuilder builder(context);
1679 builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1680 builder.SetSurface(DlISize(800, 600));
1681 builder.SetCompositor();
1682 builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, true));
1683
1684 context.GetCompositor().SetNextPresentCallback(
1686 size_t layers_count) {
1687 ASSERT_EQ(layers_count, 3u);
1688
1689 // Layer Root
1690 {
1691 FlutterBackingStore backing_store = *layers[0]->backing_store;
1692 backing_store.did_update = true;
1693 ConfigureBackingStore(backing_store, backend, true);
1694
1695 FlutterRect paint_region_rects[] = {
1696 FlutterRectMakeLTRB(0, 0, 800, 600),
1697 };
1698 FlutterRegion paint_region = {
1699 .struct_size = sizeof(FlutterRegion),
1700 .rects_count = 1,
1701 .rects = paint_region_rects,
1702 };
1703 FlutterBackingStorePresentInfo present_info = {
1705 .paint_region = &paint_region,
1706 };
1707
1708 FlutterLayer layer = {};
1709 layer.struct_size = sizeof(layer);
1711 layer.backing_store = &backing_store;
1712 layer.size = FlutterSizeMake(800.0, 600.0);
1713 layer.offset = FlutterPointMake(0.0, 0.0);
1714 layer.backing_store_present_info = &present_info;
1715
1716 ASSERT_EQ(*layers[0], layer);
1717 }
1718
1719 // Layer 1
1720 {
1723 platform_view.identifier = 1;
1724
1725 FlutterLayer layer = {};
1726 layer.struct_size = sizeof(layer);
1729 layer.size = FlutterSizeMake(100.0, 200.0);
1730 layer.offset = FlutterPointMake(0.0, 0.0);
1731
1732 ASSERT_EQ(*layers[1], layer);
1733 }
1734
1735 // Layer 2
1736 {
1737 FlutterBackingStore backing_store = *layers[2]->backing_store;
1738 backing_store.did_update = true;
1739 ConfigureBackingStore(backing_store, backend, true);
1740
1741 FlutterRect paint_region_rects[] = {
1742 FlutterRectMakeLTRB(0, 0, 800, 600),
1743 };
1744 FlutterRegion paint_region = {
1745 .struct_size = sizeof(FlutterRegion),
1746 .rects_count = 1,
1747 .rects = paint_region_rects,
1748 };
1749 FlutterBackingStorePresentInfo present_info = {
1751 .paint_region = &paint_region,
1752 };
1753
1754 FlutterLayer layer = {};
1755 layer.struct_size = sizeof(layer);
1757 layer.backing_store = &backing_store;
1758 layer.size = FlutterSizeMake(800.0, 600.0);
1759 layer.offset = FlutterPointMake(0.0, 0.0);
1760 layer.backing_store_present_info = &present_info;
1761
1762 ASSERT_EQ(*layers[2], layer);
1763 }
1764 });
1765
1766 context.GetCompositor().SetPlatformViewRendererCallback(
1767 [&](const FlutterLayer& layer,
1768 GrDirectContext* context) -> sk_sp<SkImage> {
1769 auto surface = CreateRenderSurface(layer, context);
1770 auto canvas = surface->getCanvas();
1771 FML_CHECK(canvas != nullptr);
1772
1773 switch (layer.platform_view->identifier) {
1774 case 1: {
1775 FML_CHECK(layer.size.width == 100);
1776 FML_CHECK(layer.size.height == 200);
1777 // This is occluded anyway. We just want to make sure we see this.
1778 } break;
1779 default:
1780 // Asked to render an unknown platform view.
1781 FML_CHECK(false)
1782 << "Test was asked to composite an unknown platform view.";
1783 }
1784
1785 return surface->makeImageSnapshot();
1786 });
1787
1788 auto rendered_scene = context.GetNextSceneImage();
1789
1790 auto engine = builder.LaunchEngine();
1791 ASSERT_TRUE(engine.is_valid());
1792
1793 // Send a window metrics events so frames may be scheduled.
1794 FlutterWindowMetricsEvent event = {};
1795 event.struct_size = sizeof(event);
1796 event.width = 800;
1797 event.height = 600;
1798 event.pixel_ratio = 1.0;
1799 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1800 kSuccess);
1801
1802 ASSERT_TRUE(ImageMatchesFixture(
1803 FixtureNameForBackend(backend, "gradient.png"), rendered_scene));
1804}
1805
1806TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) {
1807 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1808
1809 // This must match the transformation provided in the
1810 // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1811 // transforms are consistent respected.
1812 const auto root_surface_transformation =
1813 DlMatrix::MakeTranslation({0, 800}) *
1815
1816 context.SetRootSurfaceTransformation(root_surface_transformation);
1817
1818 EmbedderConfigBuilder builder(context);
1819
1820 builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1821 builder.SetSurface(DlISize(600, 800));
1822 builder.SetCompositor();
1823 builder.SetRenderTargetType(
1825
1826 context.GetCompositor().SetNextPresentCallback(
1828 size_t layers_count) {
1829 ASSERT_EQ(layers_count, 3u);
1830
1831 // Layer Root
1832 {
1833 FlutterBackingStore backing_store = *layers[0]->backing_store;
1834 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1835 backing_store.did_update = true;
1837
1838 FlutterRect paint_region_rects[] = {
1839 FlutterRectMakeLTRB(0, 0, 600, 800),
1840 };
1841 FlutterRegion paint_region = {
1842 .struct_size = sizeof(FlutterRegion),
1843 .rects_count = 1,
1844 .rects = paint_region_rects,
1845 };
1846 FlutterBackingStorePresentInfo present_info = {
1848 .paint_region = &paint_region,
1849 };
1850
1851 FlutterLayer layer = {};
1852 layer.struct_size = sizeof(layer);
1854 layer.backing_store = &backing_store;
1855 layer.size = FlutterSizeMake(600.0, 800.0);
1856 layer.offset = FlutterPointMake(0.0, 0.0);
1857 layer.backing_store_present_info = &present_info;
1858
1859 ASSERT_EQ(*layers[0], layer);
1860 }
1861
1862 // Layer 1
1863 {
1866 platform_view.identifier = 1;
1867
1868 FlutterLayer layer = {};
1869 layer.struct_size = sizeof(layer);
1872 layer.size = FlutterSizeMake(200.0, 100.0);
1873 layer.offset = FlutterPointMake(0.0, 700.0);
1874
1875 ASSERT_EQ(*layers[1], layer);
1876 }
1877
1878 // Layer 2
1879 {
1880 FlutterBackingStore backing_store = *layers[2]->backing_store;
1881 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1882 backing_store.did_update = true;
1884
1885 FlutterRect paint_region_rects[] = {
1886 FlutterRectMakeLTRB(0, 0, 600, 800),
1887 };
1888 FlutterRegion paint_region = {
1889 .struct_size = sizeof(FlutterRegion),
1890 .rects_count = 1,
1891 .rects = paint_region_rects,
1892 };
1893 FlutterBackingStorePresentInfo present_info = {
1895 .paint_region = &paint_region,
1896 };
1897
1898 FlutterLayer layer = {};
1899 layer.struct_size = sizeof(layer);
1901 layer.backing_store = &backing_store;
1902 layer.size = FlutterSizeMake(600.0, 800.0);
1903 layer.offset = FlutterPointMake(0.0, 0.0);
1904 layer.backing_store_present_info = &present_info;
1905
1906 ASSERT_EQ(*layers[2], layer);
1907 }
1908 });
1909
1910 context.GetCompositor().SetPlatformViewRendererCallback(
1911 [&](const FlutterLayer& layer,
1912 GrDirectContext* context) -> sk_sp<SkImage> {
1913 auto surface = CreateRenderSurface(layer, context);
1914 auto canvas = surface->getCanvas();
1915 FML_CHECK(canvas != nullptr);
1916
1917 switch (layer.platform_view->identifier) {
1918 case 1: {
1919 FML_CHECK(layer.size.width == 200);
1920 FML_CHECK(layer.size.height == 100);
1921 // This is occluded anyway. We just want to make sure we see this.
1922 } break;
1923 default:
1924 // Asked to render an unknown platform view.
1925 FML_CHECK(false)
1926 << "Test was asked to composite an unknown platform view.";
1927 }
1928
1929 return surface->makeImageSnapshot();
1930 });
1931
1932 auto rendered_scene = context.GetNextSceneImage();
1933
1934 auto engine = builder.LaunchEngine();
1935 ASSERT_TRUE(engine.is_valid());
1936
1937 // Send a window metrics events so frames may be scheduled.
1938 FlutterWindowMetricsEvent event = {};
1939 event.struct_size = sizeof(event);
1940 // Flutter still thinks it is 800 x 600.
1941 event.width = 800;
1942 event.height = 600;
1943 event.pixel_ratio = 1.0;
1944 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1945 kSuccess);
1946
1947 ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1948}
1949
1950TEST_F(EmbedderTest, VerifyB141980393) {
1951 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
1952
1953 EmbedderConfigBuilder builder(context);
1954
1955 // The Flutter application is 800 x 600 but rendering on a surface that is 600
1956 // x 800 achieved using a root surface transformation.
1957 const auto root_surface_transformation =
1958 DlMatrix::MakeTranslation({0, 800}) *
1960 const auto flutter_application_rect = DlRect::MakeWH(800, 600);
1961 const auto root_surface_rect =
1962 flutter_application_rect.TransformAndClipBounds(
1963 root_surface_transformation);
1964
1965 ASSERT_FLOAT_EQ(root_surface_rect.GetWidth(), 600.0f);
1966 ASSERT_FLOAT_EQ(root_surface_rect.GetHeight(), 800.0f);
1967
1968 // Configure the fixture for the surface transformation.
1969 context.SetRootSurfaceTransformation(root_surface_transformation);
1970
1971 // Configure the Flutter project args for the root surface transformation.
1972 builder.SetSurface(
1973 DlISize(root_surface_rect.GetWidth(), root_surface_rect.GetHeight()));
1974
1975 // Use a compositor instead of rendering directly to the surface.
1976 builder.SetCompositor();
1977 builder.SetRenderTargetType(
1979
1980 builder.SetDartEntrypoint("verify_b141980393");
1981
1983
1984 context.GetCompositor().SetNextPresentCallback(
1986 size_t layers_count) {
1987 ASSERT_EQ(layers_count, 1u);
1988
1989 // Layer Root
1990 {
1993 platform_view.identifier = 1337;
1994
1995 FlutterLayer layer = {};
1996 layer.struct_size = sizeof(layer);
1999
2000 // From the Dart side. These dimensions match those specified in Dart
2001 // code and are free of root surface transformations.
2002 const double unxformed_top_margin = 31.0;
2003 const double unxformed_bottom_margin = 37.0;
2004 const auto unxformed_platform_view_rect = DlRect::MakeXYWH(
2005 0.0, // x
2006 unxformed_top_margin, // y (top margin)
2007 800, // width
2008 600 - unxformed_top_margin - unxformed_bottom_margin // height
2009 );
2010
2011 // The platform views are in the coordinate space of the root surface
2012 // with top-left origin. The embedder has specified a transformation
2013 // to this surface which it must account for in the coordinates it
2014 // receives here.
2015 const auto xformed_platform_view_rect =
2016 unxformed_platform_view_rect.TransformAndClipBounds(
2017 root_surface_transformation);
2018
2019 // Spell out the value that we are going to be checking below for
2020 // clarity.
2021 ASSERT_EQ(xformed_platform_view_rect,
2022 DlRect::MakeXYWH(31.0, // x
2023 0.0, // y
2024 532.0, // width
2025 800.0 // height
2026 ));
2027
2028 // Verify that the engine is giving us the right size and offset.
2029 layer.offset = FlutterPointMake(xformed_platform_view_rect.GetX(),
2030 xformed_platform_view_rect.GetY());
2031 layer.size = FlutterSizeMake(xformed_platform_view_rect.GetWidth(),
2032 xformed_platform_view_rect.GetHeight());
2033
2034 ASSERT_EQ(*layers[0], layer);
2035 }
2036
2037 latch.Signal();
2038 });
2039
2040 auto engine = builder.LaunchEngine();
2041
2042 // Send a window metrics events so frames may be scheduled.
2043 FlutterWindowMetricsEvent event = {};
2044 event.struct_size = sizeof(event);
2045
2046 // The Flutter application is 800 x 600 rendering on a surface 600 x 800
2047 // achieved via a root surface transformation.
2048 event.width = flutter_application_rect.GetWidth();
2049 event.height = flutter_application_rect.GetHeight();
2050 event.pixel_ratio = 1.0;
2051 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2052 kSuccess);
2053 ASSERT_TRUE(engine.is_valid());
2054
2055 latch.Wait();
2056}
2057
2058//------------------------------------------------------------------------------
2059/// Asserts that embedders can provide a task runner for the render thread.
2060///
2061TEST_F(EmbedderTest, CanCreateEmbedderWithCustomRenderTaskRunner) {
2062 std::mutex engine_mutex;
2064 fml::AutoResetWaitableEvent task_latch;
2065 bool task_executed = false;
2066 EmbedderTestTaskRunner render_task_runner(
2067 CreateNewThread("custom_render_thread"), [&](FlutterTask task) {
2068 std::scoped_lock engine_lock(engine_mutex);
2069 if (engine.is_valid()) {
2070 ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
2071 task_executed = true;
2072 task_latch.Signal();
2073 }
2074 });
2075 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2076 EmbedderConfigBuilder builder(context);
2077 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
2078 builder.SetSurface(DlISize(800, 600));
2079 builder.SetRenderTaskRunner(
2080 &render_task_runner.GetFlutterTaskRunnerDescription());
2081
2082 {
2083 std::scoped_lock lock(engine_mutex);
2084 engine = builder.InitializeEngine();
2085 }
2086
2087 ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
2088
2089 ASSERT_TRUE(engine.is_valid());
2090
2091 FlutterWindowMetricsEvent event = {};
2092 event.struct_size = sizeof(event);
2093 event.width = 800;
2094 event.height = 600;
2095 event.pixel_ratio = 1.0;
2096 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2097 kSuccess);
2098 task_latch.Wait();
2099 ASSERT_TRUE(task_executed);
2100 ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
2101
2102 {
2103 std::scoped_lock engine_lock(engine_mutex);
2104 engine.reset();
2105 }
2106}
2107
2108//------------------------------------------------------------------------------
2109/// Asserts that the render task runner can be the same as the platform task
2110/// runner.
2111///
2113 CanCreateEmbedderWithCustomRenderTaskRunnerTheSameAsPlatformTaskRunner) {
2114 // A new thread needs to be created for the platform thread because the test
2115 // can't wait for assertions to be completed on the same thread that services
2116 // platform task runner tasks.
2117 auto platform_task_runner = CreateNewThread("platform_thread");
2118
2119 static std::mutex engine_mutex;
2120 static UniqueEngine engine;
2121 fml::AutoResetWaitableEvent task_latch;
2122 bool task_executed = false;
2123 EmbedderTestTaskRunner common_task_runner(
2124 platform_task_runner, [&](FlutterTask task) {
2125 std::scoped_lock engine_lock(engine_mutex);
2126 if (engine.is_valid()) {
2127 ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
2128 task_executed = true;
2129 task_latch.Signal();
2130 }
2131 });
2132
2133 platform_task_runner->PostTask([&]() {
2134 EmbedderTestContextType backend = GetParam();
2135 auto& context = GetEmbedderContext(backend);
2136 EmbedderConfigBuilder builder(context);
2137 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
2138 builder.SetSurface(DlISize(800, 600));
2139 builder.SetRenderTaskRunner(
2140 &common_task_runner.GetFlutterTaskRunnerDescription());
2141 builder.SetPlatformTaskRunner(
2142 &common_task_runner.GetFlutterTaskRunnerDescription());
2143
2144 {
2145 std::scoped_lock lock(engine_mutex);
2146 engine = builder.InitializeEngine();
2147 }
2148
2149 ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
2150
2151 ASSERT_TRUE(engine.is_valid());
2152
2153 FlutterWindowMetricsEvent event = {};
2154 event.struct_size = sizeof(event);
2155 event.width = 800;
2156 event.height = 600;
2157 event.pixel_ratio = 1.0;
2158 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2159 kSuccess);
2160 });
2161
2162 task_latch.Wait();
2163
2164 // Don't use the task latch because that may be called multiple time
2165 // (including during the shutdown process).
2166 fml::AutoResetWaitableEvent shutdown_latch;
2167
2168 platform_task_runner->PostTask([&]() {
2169 ASSERT_TRUE(task_executed);
2170 ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
2171
2172 {
2173 std::scoped_lock engine_lock(engine_mutex);
2174 engine.reset();
2175 }
2176 shutdown_latch.Signal();
2177 });
2178
2179 shutdown_latch.Wait();
2180
2181 {
2182 std::scoped_lock engine_lock(engine_mutex);
2183 // Engine should have been killed by this point.
2184 ASSERT_FALSE(engine.is_valid());
2185 }
2186}
2187
2189 CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurface) {
2190 EmbedderTestContextType backend = GetParam();
2191 auto& context = GetEmbedderContext(backend);
2192
2193 EmbedderConfigBuilder builder(context);
2194 builder.SetSurface(DlISize(800, 600));
2195 builder.SetCompositor();
2196 builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
2197
2198 builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, false));
2199
2200 fml::CountDownLatch latch(1);
2201
2202 auto rendered_scene = context.GetNextSceneImage();
2203
2204 context.GetCompositor().SetNextPresentCallback(
2206 size_t layers_count) {
2207 ASSERT_EQ(layers_count, 3u);
2208
2209 // Layer 0 (Root)
2210 {
2211 FlutterBackingStore backing_store = *layers[0]->backing_store;
2212 backing_store.did_update = true;
2213 ConfigureBackingStore(backing_store, backend, false);
2214
2215 FlutterRect paint_region_rects[] = {
2216 FlutterRectMakeLTRB(0, 0, 800, 600),
2217 };
2218 FlutterRegion paint_region = {
2219 .struct_size = sizeof(FlutterRegion),
2220 .rects_count = 1,
2221 .rects = paint_region_rects,
2222 };
2223 FlutterBackingStorePresentInfo present_info = {
2225 .paint_region = &paint_region,
2226 };
2227
2228 FlutterLayer layer = {};
2229 layer.struct_size = sizeof(layer);
2231 layer.backing_store = &backing_store;
2232 layer.size = FlutterSizeMake(800.0, 600.0);
2233 layer.offset = FlutterPointMake(0.0, 0.0);
2234 layer.backing_store_present_info = &present_info;
2235
2236 ASSERT_EQ(*layers[0], layer);
2237 }
2238
2239 // Layer 1
2240 {
2243 platform_view.identifier = 42;
2244
2245 FlutterLayer layer = {};
2246 layer.struct_size = sizeof(layer);
2249 layer.size = FlutterSizeMake(800.0, 560.0);
2250 layer.offset = FlutterPointMake(0.0, 40.0);
2251
2252 ASSERT_EQ(*layers[1], layer);
2253 }
2254
2255 // Layer 2
2256 {
2257 FlutterBackingStore backing_store = *layers[2]->backing_store;
2258 backing_store.did_update = true;
2259 ConfigureBackingStore(backing_store, backend, false);
2260
2261 FlutterRect paint_region_rects[] = {
2262 FlutterRectMakeLTRB(0, 0, 800, 600),
2263 };
2264 FlutterRegion paint_region = {
2265 .struct_size = sizeof(FlutterRegion),
2266 .rects_count = 1,
2267 .rects = paint_region_rects,
2268 };
2269 FlutterBackingStorePresentInfo present_info = {
2271 .paint_region = &paint_region,
2272 };
2273
2274 FlutterLayer layer = {};
2275 layer.struct_size = sizeof(layer);
2277 layer.backing_store = &backing_store;
2278 layer.size = FlutterSizeMake(800.0, 600.0);
2279 layer.offset = FlutterPointMake(0.0, 0.0);
2280 layer.backing_store_present_info = &present_info;
2281
2282 ASSERT_EQ(*layers[2], layer);
2283 }
2284
2285 latch.CountDown();
2286 });
2287
2288 auto engine = builder.LaunchEngine();
2289
2290 // Send a window metrics events so frames may be scheduled.
2291 FlutterWindowMetricsEvent event = {};
2292 event.struct_size = sizeof(event);
2293 event.width = 400 * 2.0;
2294 event.height = 300 * 2.0;
2295 event.pixel_ratio = 2.0;
2296 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2297 kSuccess);
2298 ASSERT_TRUE(engine.is_valid());
2299
2300 latch.Wait();
2301
2302 ASSERT_TRUE(ImageMatchesFixture(
2303 FixtureNameForBackend(backend, "dpr_noxform.png"), rendered_scene));
2304}
2305
2308 CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurfaceWithRootSurfaceXformation) {
2309 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2310
2311 EmbedderConfigBuilder builder(context);
2312 builder.SetSurface(DlISize(600, 800));
2313 builder.SetCompositor();
2314 builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
2315
2316 builder.SetRenderTargetType(
2318
2319 const auto root_surface_transformation =
2320 DlMatrix::MakeTranslation({0, 800}) *
2322
2323 context.SetRootSurfaceTransformation(root_surface_transformation);
2324
2325 auto rendered_scene = context.GetNextSceneImage();
2326 fml::CountDownLatch latch(1);
2327
2328 context.GetCompositor().SetNextPresentCallback(
2330 size_t layers_count) {
2331 ASSERT_EQ(layers_count, 3u);
2332
2333 // Layer 0 (Root)
2334 {
2335 FlutterBackingStore backing_store = *layers[0]->backing_store;
2336 backing_store.type = kFlutterBackingStoreTypeOpenGL;
2337 backing_store.did_update = true;
2339
2340 FlutterRect paint_region_rects[] = {
2341 FlutterRectMakeLTRB(0, 0, 600, 800),
2342 };
2343 FlutterRegion paint_region = {
2344 .struct_size = sizeof(FlutterRegion),
2345 .rects_count = 1,
2346 .rects = paint_region_rects,
2347 };
2348 FlutterBackingStorePresentInfo present_info = {
2350 .paint_region = &paint_region,
2351 };
2352
2353 FlutterLayer layer = {};
2354 layer.struct_size = sizeof(layer);
2356 layer.backing_store = &backing_store;
2357 layer.size = FlutterSizeMake(600.0, 800.0);
2358 layer.offset = FlutterPointMake(0.0, 0.0);
2359 layer.backing_store_present_info = &present_info;
2360
2361 ASSERT_EQ(*layers[0], layer);
2362 }
2363
2364 // Layer 1
2365 {
2368 platform_view.identifier = 42;
2369
2370 FlutterLayer layer = {};
2371 layer.struct_size = sizeof(layer);
2374 layer.size = FlutterSizeMake(560.0, 800.0);
2375 layer.offset = FlutterPointMake(40.0, 0.0);
2376
2377 ASSERT_EQ(*layers[1], layer);
2378 }
2379
2380 // Layer 2
2381 {
2382 FlutterBackingStore backing_store = *layers[2]->backing_store;
2383 backing_store.type = kFlutterBackingStoreTypeOpenGL;
2384 backing_store.did_update = true;
2386
2387 FlutterRect paint_region_rects[] = {
2388 FlutterRectMakeLTRB(0, 0, 600, 800),
2389 };
2390 FlutterRegion paint_region = {
2391 .struct_size = sizeof(FlutterRegion),
2392 .rects_count = 1,
2393 .rects = paint_region_rects,
2394 };
2395 FlutterBackingStorePresentInfo present_info = {
2397 .paint_region = &paint_region,
2398 };
2399
2400 FlutterLayer layer = {};
2401 layer.struct_size = sizeof(layer);
2403 layer.backing_store = &backing_store;
2404 layer.size = FlutterSizeMake(600.0, 800.0);
2405 layer.offset = FlutterPointMake(0.0, 0.0);
2406 layer.backing_store_present_info = &present_info;
2407
2408 ASSERT_EQ(*layers[2], layer);
2409 }
2410
2411 latch.CountDown();
2412 });
2413
2414 auto engine = builder.LaunchEngine();
2415
2416 // Send a window metrics events so frames may be scheduled.
2417 FlutterWindowMetricsEvent event = {};
2418 event.struct_size = sizeof(event);
2419 event.width = 400 * 2.0;
2420 event.height = 300 * 2.0;
2421 event.pixel_ratio = 2.0;
2422 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2423 kSuccess);
2424 ASSERT_TRUE(engine.is_valid());
2425
2426 latch.Wait();
2427
2428 ASSERT_TRUE(ImageMatchesFixture("dpr_xform.png", rendered_scene));
2429}
2430
2432 PushingMutlipleFramesSetsUpNewRecordingCanvasWithCustomCompositor) {
2433 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2434
2435 EmbedderConfigBuilder builder(context);
2436 builder.SetSurface(DlISize(600, 1024));
2437 builder.SetCompositor();
2438 builder.SetDartEntrypoint("push_frames_over_and_over");
2439
2440 builder.SetRenderTargetType(
2442
2443 const auto root_surface_transformation =
2444 DlMatrix::MakeTranslation({0, 1024}) *
2446
2447 context.SetRootSurfaceTransformation(root_surface_transformation);
2448
2449 auto engine = builder.LaunchEngine();
2450
2451 // Send a window metrics events so frames may be scheduled.
2452 FlutterWindowMetricsEvent event = {};
2453 event.struct_size = sizeof(event);
2454 event.width = 1024;
2455 event.height = 600;
2456 event.pixel_ratio = 1.0;
2457 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2458 kSuccess);
2459 ASSERT_TRUE(engine.is_valid());
2460
2461 constexpr size_t frames_expected = 10;
2462 fml::CountDownLatch frame_latch(frames_expected);
2463 std::atomic_size_t frames_seen = 0;
2464 context.AddNativeCallback("SignalNativeTest",
2465 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2466 frames_seen++;
2467 frame_latch.CountDown();
2468 }));
2469 frame_latch.Wait();
2470
2471 ASSERT_GE(frames_seen, frames_expected);
2472
2473 FlutterEngineShutdown(engine.release());
2474}
2475
2477 PushingMutlipleFramesSetsUpNewRecordingCanvasWithoutCustomCompositor) {
2478 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2479
2480 EmbedderConfigBuilder builder(context);
2481 builder.SetSurface(DlISize(600, 1024));
2482 builder.SetDartEntrypoint("push_frames_over_and_over");
2483
2484 const auto root_surface_transformation =
2485 DlMatrix::MakeTranslation({0, 1024}) *
2487
2488 context.SetRootSurfaceTransformation(root_surface_transformation);
2489
2490 auto engine = builder.LaunchEngine();
2491
2492 // Send a window metrics events so frames may be scheduled.
2493 FlutterWindowMetricsEvent event = {};
2494 event.struct_size = sizeof(event);
2495 event.width = 1024;
2496 event.height = 600;
2497 event.pixel_ratio = 1.0;
2498 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2499 kSuccess);
2500 ASSERT_TRUE(engine.is_valid());
2501
2502 constexpr size_t frames_expected = 10;
2503 fml::CountDownLatch frame_latch(frames_expected);
2504 std::atomic_size_t frames_seen = 0;
2505 context.AddNativeCallback("SignalNativeTest",
2506 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2507 frames_seen++;
2508 frame_latch.CountDown();
2509 }));
2510 frame_latch.Wait();
2511
2512 ASSERT_GE(frames_seen, frames_expected);
2513
2514 FlutterEngineShutdown(engine.release());
2515}
2516
2517TEST_P(EmbedderTestMultiBackend, PlatformViewMutatorsAreValid) {
2518 EmbedderTestContextType backend = GetParam();
2519 auto& context = GetEmbedderContext(backend);
2520
2521 EmbedderConfigBuilder builder(context);
2522 builder.SetSurface(DlISize(800, 600));
2523 builder.SetCompositor();
2524 builder.SetDartEntrypoint("platform_view_mutators");
2525
2526 builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, false));
2527
2528 fml::CountDownLatch latch(1);
2529 context.GetCompositor().SetNextPresentCallback(
2531 size_t layers_count) {
2532 ASSERT_EQ(layers_count, 2u);
2533
2534 // Layer 0 (Root)
2535 {
2536 FlutterBackingStore backing_store = *layers[0]->backing_store;
2537 backing_store.did_update = true;
2538 ConfigureBackingStore(backing_store, backend, false);
2539
2540 FlutterRect paint_region_rects[] = {
2541 FlutterRectMakeLTRB(0, 0, 800, 600),
2542 };
2543 FlutterRegion paint_region = {
2544 .struct_size = sizeof(FlutterRegion),
2545 .rects_count = 1,
2546 .rects = paint_region_rects,
2547 };
2548 FlutterBackingStorePresentInfo present_info = {
2550 .paint_region = &paint_region,
2551 };
2552
2553 FlutterLayer layer = {};
2554 layer.struct_size = sizeof(layer);
2556 layer.backing_store = &backing_store;
2557 layer.size = FlutterSizeMake(800.0, 600.0);
2558 layer.offset = FlutterPointMake(0.0, 0.0);
2559 layer.backing_store_present_info = &present_info;
2560
2561 ASSERT_EQ(*layers[0], layer);
2562 }
2563
2564 // Layer 2
2565 {
2568 platform_view.identifier = 42;
2569 platform_view.mutations_count = 3;
2570
2571 FlutterLayer layer = {};
2572 layer.struct_size = sizeof(layer);
2575 layer.size = FlutterSizeMake(800.0, 600.0);
2576 layer.offset = FlutterPointMake(0.0, 0.0);
2577
2578 ASSERT_EQ(*layers[1], layer);
2579
2580 // There are no ordering guarantees.
2581 for (size_t i = 0; i < platform_view.mutations_count; i++) {
2582 FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2583 switch (mutation.type) {
2585 mutation.clip_rounded_rect =
2586 FlutterRoundedRectMake(SkRRect::MakeRectXY(
2587 SkRect::MakeLTRB(10.0, 10.0, 800.0 - 10.0,
2588 600.0 - 10.0),
2589 14.0, 14.0));
2590 break;
2593 mutation.clip_rect = FlutterRectMake(
2594 DlRect::MakeXYWH(10.0, 10.0, 800.0 - 20.0, 600.0 - 20.0));
2595 break;
2598 mutation.opacity = 128.0 / 255.0;
2599 break;
2601 FML_CHECK(false)
2602 << "There should be no transformation in the test.";
2603 break;
2604 }
2605
2606 ASSERT_EQ(*platform_view.mutations[i], mutation);
2607 }
2608 }
2609 latch.CountDown();
2610 });
2611
2612 auto engine = builder.LaunchEngine();
2613
2614 // Send a window metrics events so frames may be scheduled.
2615 FlutterWindowMetricsEvent event = {};
2616 event.struct_size = sizeof(event);
2617 event.width = 800;
2618 event.height = 600;
2619 event.pixel_ratio = 1.0;
2620 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2621 kSuccess);
2622 ASSERT_TRUE(engine.is_valid());
2623
2624 latch.Wait();
2625}
2626
2627TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) {
2628 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2629
2630 EmbedderConfigBuilder builder(context);
2631 builder.SetSurface(DlISize(800, 600));
2632 builder.SetCompositor();
2633 builder.SetDartEntrypoint("platform_view_mutators_with_pixel_ratio");
2634
2635 builder.SetRenderTargetType(
2637
2638 fml::CountDownLatch latch(1);
2639 context.GetCompositor().SetNextPresentCallback(
2641 size_t layers_count) {
2642 ASSERT_EQ(layers_count, 2u);
2643
2644 // Layer 0 (Root)
2645 {
2646 FlutterBackingStore backing_store = *layers[0]->backing_store;
2647 backing_store.type = kFlutterBackingStoreTypeOpenGL;
2648 backing_store.did_update = true;
2650
2651 FlutterRect paint_region_rects[] = {
2652 FlutterRectMakeLTRB(0, 0, 800, 600),
2653 };
2654 FlutterRegion paint_region = {
2655 .struct_size = sizeof(FlutterRegion),
2656 .rects_count = 1,
2657 .rects = paint_region_rects,
2658 };
2659 FlutterBackingStorePresentInfo present_info = {
2661 .paint_region = &paint_region,
2662 };
2663
2664 FlutterLayer layer = {};
2665 layer.struct_size = sizeof(layer);
2667 layer.backing_store = &backing_store;
2668 layer.size = FlutterSizeMake(800.0, 600.0);
2669 layer.offset = FlutterPointMake(0.0, 0.0);
2670 layer.backing_store_present_info = &present_info;
2671
2672 ASSERT_EQ(*layers[0], layer);
2673 }
2674
2675 // Layer 2
2676 {
2679 platform_view.identifier = 42;
2680 platform_view.mutations_count = 3;
2681
2682 FlutterLayer layer = {};
2683 layer.struct_size = sizeof(layer);
2686 layer.size = FlutterSizeMake(800.0, 600.0);
2687 layer.offset = FlutterPointMake(0.0, 0.0);
2688
2689 ASSERT_EQ(*layers[1], layer);
2690
2691 // There are no ordering guarantees.
2692 for (size_t i = 0; i < platform_view.mutations_count; i++) {
2693 FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2694 switch (mutation.type) {
2696 mutation.clip_rounded_rect =
2697 FlutterRoundedRectMake(SkRRect::MakeRectXY(
2698 SkRect::MakeLTRB(5.0, 5.0, 400.0 - 5.0, 300.0 - 5.0),
2699 7.0, 7.0));
2700 break;
2703 mutation.clip_rect = FlutterRectMake(
2704 DlRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2705 break;
2708 mutation.opacity = 128.0 / 255.0;
2709 break;
2713 DlMatrix::MakeScale({2.0, 2.0, 1}));
2714 break;
2715 }
2716
2717 ASSERT_EQ(*platform_view.mutations[i], mutation);
2718 }
2719 }
2720 latch.CountDown();
2721 });
2722
2723 auto engine = builder.LaunchEngine();
2724
2725 // Send a window metrics events so frames may be scheduled.
2726 FlutterWindowMetricsEvent event = {};
2727 event.struct_size = sizeof(event);
2728 event.width = 800;
2729 event.height = 600;
2730 event.pixel_ratio = 2.0;
2731 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2732 kSuccess);
2733 ASSERT_TRUE(engine.is_valid());
2734
2735 latch.Wait();
2736}
2737
2739 PlatformViewMutatorsAreValidWithPixelRatioAndRootSurfaceTransformation) {
2740 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2741
2742 EmbedderConfigBuilder builder(context);
2743 builder.SetSurface(DlISize(800, 600));
2744 builder.SetCompositor();
2745 builder.SetDartEntrypoint("platform_view_mutators_with_pixel_ratio");
2746
2747 builder.SetRenderTargetType(
2749
2750 static const auto root_surface_transformation =
2751 DlMatrix::MakeTranslation({0, 800}) *
2753
2754 context.SetRootSurfaceTransformation(root_surface_transformation);
2755
2756 fml::CountDownLatch latch(1);
2757 context.GetCompositor().SetNextPresentCallback(
2759 size_t layers_count) {
2760 ASSERT_EQ(layers_count, 2u);
2761
2762 // Layer 0 (Root)
2763 {
2764 FlutterBackingStore backing_store = *layers[0]->backing_store;
2765 backing_store.type = kFlutterBackingStoreTypeOpenGL;
2766 backing_store.did_update = true;
2768
2769 FlutterRect paint_region_rects[] = {
2770 FlutterRectMakeLTRB(0, 0, 600, 800),
2771 };
2772 FlutterRegion paint_region = {
2773 .struct_size = sizeof(FlutterRegion),
2774 .rects_count = 1,
2775 .rects = paint_region_rects,
2776 };
2777 FlutterBackingStorePresentInfo present_info = {
2779 .paint_region = &paint_region,
2780 };
2781
2782 FlutterLayer layer = {};
2783 layer.struct_size = sizeof(layer);
2785 layer.backing_store = &backing_store;
2786 layer.size = FlutterSizeMake(600.0, 800.0);
2787 layer.offset = FlutterPointMake(0.0, 0.0);
2788 layer.backing_store_present_info = &present_info;
2789
2790 ASSERT_EQ(*layers[0], layer);
2791 }
2792
2793 // Layer 2
2794 {
2797 platform_view.identifier = 42;
2798 platform_view.mutations_count = 4;
2799
2800 FlutterLayer layer = {};
2801 layer.struct_size = sizeof(layer);
2804 layer.size = FlutterSizeMake(600.0, 800.0);
2805 layer.offset = FlutterPointMake(0.0, 0.0);
2806
2807 ASSERT_EQ(*layers[1], layer);
2808
2809 // There are no ordering guarantees.
2810 for (size_t i = 0; i < platform_view.mutations_count; i++) {
2811 FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2812 switch (mutation.type) {
2814 mutation.clip_rounded_rect =
2815 FlutterRoundedRectMake(SkRRect::MakeRectXY(
2816 SkRect::MakeLTRB(5.0, 5.0, 400.0 - 5.0, 300.0 - 5.0),
2817 7.0, 7.0));
2818 break;
2821 mutation.clip_rect = FlutterRectMake(
2822 DlRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2823 break;
2826 mutation.opacity = 128.0 / 255.0;
2827 break;
2830 mutation.transformation =
2831 FlutterTransformationMake(root_surface_transformation);
2832
2833 break;
2834 }
2835
2836 ASSERT_EQ(*platform_view.mutations[i], mutation);
2837 }
2838 }
2839 latch.CountDown();
2840 });
2841
2842 auto engine = builder.LaunchEngine();
2843
2844 // Send a window metrics events so frames may be scheduled.
2845 FlutterWindowMetricsEvent event = {};
2846 event.struct_size = sizeof(event);
2847 event.width = 800;
2848 event.height = 600;
2849 event.pixel_ratio = 2.0;
2850 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2851 kSuccess);
2852 ASSERT_TRUE(engine.is_valid());
2853
2854 latch.Wait();
2855}
2856
2857TEST_F(EmbedderTest, EmptySceneIsAcceptable) {
2858 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2859
2860 EmbedderConfigBuilder builder(context);
2861 builder.SetSurface(DlISize(800, 600));
2862 builder.SetCompositor();
2863 builder.SetDartEntrypoint("empty_scene");
2865 context.AddNativeCallback(
2866 "SignalNativeTest",
2867 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
2868
2869 auto engine = builder.LaunchEngine();
2870
2871 ASSERT_TRUE(engine.is_valid());
2872
2873 FlutterWindowMetricsEvent event = {};
2874 event.struct_size = sizeof(event);
2875 event.width = 800;
2876 event.height = 600;
2877 event.pixel_ratio = 1.0;
2878 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2879 kSuccess);
2880 latch.Wait();
2881}
2882
2883TEST_F(EmbedderTest, SceneWithNoRootContainerIsAcceptable) {
2884 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2885
2886 EmbedderConfigBuilder builder(context);
2887 builder.SetSurface(DlISize(800, 600));
2888 builder.SetCompositor();
2889 builder.SetRenderTargetType(
2891 builder.SetDartEntrypoint("scene_with_no_container");
2893 context.AddNativeCallback(
2894 "SignalNativeTest",
2895 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
2896
2897 auto engine = builder.LaunchEngine();
2898
2899 ASSERT_TRUE(engine.is_valid());
2900
2901 FlutterWindowMetricsEvent event = {};
2902 event.struct_size = sizeof(event);
2903 event.width = 800;
2904 event.height = 600;
2905 event.pixel_ratio = 1.0;
2906 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2907 kSuccess);
2908 latch.Wait();
2909}
2910
2911// Verifies that https://skia-review.googlesource.com/c/skia/+/259174 is pulled
2912// into the engine.
2913TEST_F(EmbedderTest, ArcEndCapsAreDrawnCorrectly) {
2914 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2915
2916 EmbedderConfigBuilder builder(context);
2917 builder.SetSurface(DlISize(800, 1024));
2918 builder.SetCompositor();
2919 builder.SetDartEntrypoint("arc_end_caps_correct");
2920 builder.SetRenderTargetType(
2922
2923 const auto root_surface_transformation =
2924 DlMatrix::MakeScale({1.0, -1.0, 1}) *
2925 DlMatrix::MakeTranslation({1024.0f, -800.0f}) *
2927
2928 context.SetRootSurfaceTransformation(root_surface_transformation);
2929
2930 auto engine = builder.LaunchEngine();
2931
2932 auto scene_image = context.GetNextSceneImage();
2933
2934 ASSERT_TRUE(engine.is_valid());
2935
2936 FlutterWindowMetricsEvent event = {};
2937 event.struct_size = sizeof(event);
2938 event.width = 800;
2939 event.height = 1024;
2940 event.pixel_ratio = 1.0;
2941 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
2942 kSuccess);
2943
2944 ASSERT_TRUE(ImageMatchesFixture("arc_end_caps.png", scene_image));
2945}
2946
2947TEST_F(EmbedderTest, ClipsAreCorrectlyCalculated) {
2948 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
2949
2950 EmbedderConfigBuilder builder(context);
2951 builder.SetSurface(DlISize(400, 300));
2952 builder.SetCompositor();
2953 builder.SetDartEntrypoint("scene_builder_with_clips");
2954 builder.SetRenderTargetType(
2956
2957 const auto root_surface_transformation =
2958 DlMatrix::MakeTranslation({0, 400}) *
2960
2961 context.SetRootSurfaceTransformation(root_surface_transformation);
2962
2964 context.GetCompositor().SetNextPresentCallback(
2966 size_t layers_count) {
2967 ASSERT_EQ(layers_count, 2u);
2968
2969 {
2972 platform_view.identifier = 42;
2973
2974 FlutterLayer layer = {};
2975 layer.struct_size = sizeof(layer);
2978 layer.size = FlutterSizeMake(300.0, 400.0);
2979 layer.offset = FlutterPointMake(0.0, 0.0);
2980
2981 ASSERT_EQ(*layers[0], layer);
2982
2983 bool clip_assertions_checked = false;
2984
2985 // The total transformation on the stack upto the platform view.
2986 const auto total_xformation =
2988
2992 [&](const auto& mutation) {
2993 FlutterRect clip = mutation.clip_rect;
2994
2995 // The test is only set up to supply one clip. Make sure it is
2996 // the one we expect.
2997 const auto rect_to_compare =
2998 DlRect::MakeLTRB(10.0, 10.0, 390, 290);
2999 ASSERT_EQ(clip, FlutterRectMake(rect_to_compare));
3000
3001 // This maps the clip from device space into surface space.
3002 ASSERT_TRUE(total_xformation.IsAligned2D());
3003 DlRect mapped =
3004 rect_to_compare.TransformAndClipBounds(total_xformation);
3005 ASSERT_EQ(mapped, DlRect::MakeLTRB(10, 10, 290, 390));
3006 clip_assertions_checked = true;
3007 });
3008
3009 ASSERT_TRUE(clip_assertions_checked);
3010 }
3011
3012 latch.Signal();
3013 });
3014
3015 auto engine = builder.LaunchEngine();
3016 ASSERT_TRUE(engine.is_valid());
3017
3018 FlutterWindowMetricsEvent event = {};
3019 event.struct_size = sizeof(event);
3020 event.width = 400;
3021 event.height = 300;
3022 event.pixel_ratio = 1.0;
3023 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3024 kSuccess);
3025
3026 latch.Wait();
3027}
3028
3029TEST_F(EmbedderTest, ComplexClipsAreCorrectlyCalculated) {
3030 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3031
3032 EmbedderConfigBuilder builder(context);
3033 builder.SetSurface(DlISize(1024, 600));
3034 builder.SetCompositor();
3035 builder.SetDartEntrypoint("scene_builder_with_complex_clips");
3036 builder.SetRenderTargetType(
3038
3039 const auto root_surface_transformation =
3040 DlMatrix::MakeTranslation({0, 1024}) *
3042
3043 context.SetRootSurfaceTransformation(root_surface_transformation);
3044
3046 context.GetCompositor().SetNextPresentCallback(
3048 size_t layers_count) {
3049 ASSERT_EQ(layers_count, 2u);
3050
3051 {
3054 platform_view.identifier = 42;
3055
3056 FlutterLayer layer = {};
3057 layer.struct_size = sizeof(layer);
3060 layer.size = FlutterSizeMake(600.0, 1024.0);
3061 layer.offset = FlutterPointMake(0.0, -256.0);
3062
3063 ASSERT_EQ(*layers[0], layer);
3064
3065 const auto** mutations = platform_view.mutations;
3066
3067 ASSERT_EQ(mutations[0]->type,
3069 ASSERT_EQ(DlMatrixMake(mutations[0]->transformation),
3070 root_surface_transformation);
3071
3072 ASSERT_EQ(mutations[1]->type,
3074 ASSERT_EQ(SkRectMake(mutations[1]->clip_rect),
3075 SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
3076
3077 ASSERT_EQ(mutations[2]->type,
3079 ASSERT_EQ(DlMatrixMake(mutations[2]->transformation),
3080 DlMatrix::MakeTranslation({512.0, 0.0}));
3081
3082 ASSERT_EQ(mutations[3]->type,
3084 ASSERT_EQ(SkRectMake(mutations[3]->clip_rect),
3085 SkRect::MakeLTRB(0.0, 0.0, 512.0, 600.0));
3086
3087 ASSERT_EQ(mutations[4]->type,
3089 ASSERT_EQ(DlMatrixMake(mutations[4]->transformation),
3090 DlMatrix::MakeTranslation({-256.0, 0.0}));
3091
3092 ASSERT_EQ(mutations[5]->type,
3094 ASSERT_EQ(SkRectMake(mutations[5]->clip_rect),
3095 SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
3096 }
3097
3098 latch.Signal();
3099 });
3100
3101 auto engine = builder.LaunchEngine();
3102 ASSERT_TRUE(engine.is_valid());
3103
3104 FlutterWindowMetricsEvent event = {};
3105 event.struct_size = sizeof(event);
3106 event.width = 1024;
3107 event.height = 600;
3108 event.pixel_ratio = 1.0;
3109 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3110 kSuccess);
3111
3112 latch.Wait();
3113}
3114
3115TEST_F(EmbedderTest, ObjectsCanBePostedViaPorts) {
3116 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3117 EmbedderConfigBuilder builder(context);
3118 builder.SetSurface(DlISize(800, 1024));
3119 builder.SetDartEntrypoint("objects_can_be_posted");
3120
3121 // Synchronously acquire the send port from the Dart end. We will be using
3122 // this to send message. The Dart end will just echo those messages back to us
3123 // for inspection.
3124 FlutterEngineDartPort port = 0;
3126 context.AddNativeCallback("SignalNativeCount",
3127 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3129 Dart_GetNativeArgument(args, 0));
3130 event.Signal();
3131 }));
3132 auto engine = builder.LaunchEngine();
3133 ASSERT_TRUE(engine.is_valid());
3134 event.Wait();
3135 ASSERT_NE(port, 0);
3136
3137 using Trampoline = std::function<void(Dart_Handle message)>;
3138 Trampoline trampoline;
3139
3140 context.AddNativeCallback("SendObjectToNativeCode",
3141 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3142 FML_CHECK(trampoline);
3143 auto trampoline_copy = trampoline;
3144 trampoline = nullptr;
3145 trampoline_copy(Dart_GetNativeArgument(args, 0));
3146 }));
3147
3148 // Check null.
3149 {
3150 FlutterEngineDartObject object = {};
3152 trampoline = [&](Dart_Handle handle) {
3153 ASSERT_TRUE(Dart_IsNull(handle));
3154 event.Signal();
3155 };
3156 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3157 kSuccess);
3158 event.Wait();
3159 }
3160
3161 // Check bool.
3162 {
3163 FlutterEngineDartObject object = {};
3165 object.bool_value = true;
3166 trampoline = [&](Dart_Handle handle) {
3167 ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(handle));
3168 event.Signal();
3169 };
3170 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3171 kSuccess);
3172 event.Wait();
3173 }
3174
3175 // Check int32.
3176 {
3177 FlutterEngineDartObject object = {};
3179 object.int32_value = 1988;
3180 trampoline = [&](Dart_Handle handle) {
3181 ASSERT_EQ(tonic::DartConverter<int32_t>::FromDart(handle), 1988);
3182 event.Signal();
3183 };
3184 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3185 kSuccess);
3186 event.Wait();
3187 }
3188
3189 // Check int64.
3190 {
3191 FlutterEngineDartObject object = {};
3193 object.int64_value = 1988;
3194 trampoline = [&](Dart_Handle handle) {
3195 ASSERT_EQ(tonic::DartConverter<int64_t>::FromDart(handle), 1988);
3196 event.Signal();
3197 };
3198 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3199 kSuccess);
3200 event.Wait();
3201 }
3202
3203 // Check double.
3204 {
3205 FlutterEngineDartObject object = {};
3207 object.double_value = 1988.0;
3208 trampoline = [&](Dart_Handle handle) {
3209 ASSERT_DOUBLE_EQ(tonic::DartConverter<double>::FromDart(handle), 1988.0);
3210 event.Signal();
3211 };
3212 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3213 kSuccess);
3214 event.Wait();
3215 }
3216
3217 // Check string.
3218 {
3219 const char* message = "Hello. My name is Inigo Montoya.";
3220 FlutterEngineDartObject object = {};
3222 object.string_value = message;
3223 trampoline = [&](Dart_Handle handle) {
3225 std::string{message});
3226 event.Signal();
3227 };
3228 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3229 kSuccess);
3230 event.Wait();
3231 }
3232
3233 // Check buffer (copied out).
3234 {
3235 std::vector<uint8_t> message;
3236 message.resize(1988);
3237
3238 ASSERT_TRUE(MemsetPatternSetOrCheck(
3240
3242
3243 buffer.struct_size = sizeof(buffer);
3244 buffer.user_data = nullptr;
3245 buffer.buffer_collect_callback = nullptr;
3246 buffer.buffer = message.data();
3247 buffer.buffer_size = message.size();
3248
3249 FlutterEngineDartObject object = {};
3251 object.buffer_value = &buffer;
3252 trampoline = [&](Dart_Handle handle) {
3253 intptr_t length = 0;
3254 Dart_ListLength(handle, &length);
3255 ASSERT_EQ(length, 1988);
3256 // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
3257 // DartConvertor in tonic is broken which is preventing the buffer
3258 // being checked here. Fix tonic and strengthen this check. For now, just
3259 // the buffer length is checked.
3260 event.Signal();
3261 };
3262 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3263 kSuccess);
3264 event.Wait();
3265 }
3266
3267 std::vector<uint8_t> message;
3268 fml::AutoResetWaitableEvent buffer_released_latch;
3269
3270 // Check buffer (caller own buffer with zero copy transfer).
3271 {
3272 message.resize(1988);
3273
3274 ASSERT_TRUE(MemsetPatternSetOrCheck(
3276
3278
3279 buffer.struct_size = sizeof(buffer);
3280 buffer.user_data = &buffer_released_latch;
3281 buffer.buffer_collect_callback = +[](void* user_data) {
3282 reinterpret_cast<fml::AutoResetWaitableEvent*>(user_data)->Signal();
3283 };
3284 buffer.buffer = message.data();
3285 buffer.buffer_size = message.size();
3286
3287 FlutterEngineDartObject object = {};
3289 object.buffer_value = &buffer;
3290 trampoline = [&](Dart_Handle handle) {
3291 intptr_t length = 0;
3292 Dart_ListLength(handle, &length);
3293 ASSERT_EQ(length, 1988);
3294 // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
3295 // DartConvertor in tonic is broken which is preventing the buffer
3296 // being checked here. Fix tonic and strengthen this check. For now, just
3297 // the buffer length is checked.
3298 event.Signal();
3299 };
3300 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3301 kSuccess);
3302 event.Wait();
3303 }
3304
3305 engine.reset();
3306
3307 // We cannot determine when the VM will GC objects that might have external
3308 // typed data finalizers. Since we need to ensure that we correctly wired up
3309 // finalizers from the embedders, we force the VM to collect all objects but
3310 // just shutting it down.
3311 buffer_released_latch.Wait();
3312}
3313
3314TEST_F(EmbedderTest, CompositorCanPostZeroLayersForPresentation) {
3315 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3316
3317 EmbedderConfigBuilder builder(context);
3318 builder.SetSurface(DlISize(300, 200));
3319 builder.SetCompositor();
3320 builder.SetDartEntrypoint("empty_scene_posts_zero_layers_to_compositor");
3321 builder.SetRenderTargetType(
3323
3325
3326 context.GetCompositor().SetNextPresentCallback(
3328 size_t layers_count) {
3329 ASSERT_EQ(layers_count, 0u);
3330 latch.Signal();
3331 });
3332
3333 auto engine = builder.LaunchEngine();
3334
3335 FlutterWindowMetricsEvent event = {};
3336 event.struct_size = sizeof(event);
3337 event.width = 300;
3338 event.height = 200;
3339 event.pixel_ratio = 1.0;
3340 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3341 kSuccess);
3342 ASSERT_TRUE(engine.is_valid());
3343 latch.Wait();
3344
3345 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
3346}
3347
3348TEST_F(EmbedderTest, CompositorCanPostOnlyPlatformViews) {
3349 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3350
3351 EmbedderConfigBuilder builder(context);
3352 builder.SetSurface(DlISize(300, 200));
3353 builder.SetCompositor();
3354 builder.SetDartEntrypoint("compositor_can_post_only_platform_views");
3355 builder.SetRenderTargetType(
3357
3359
3360 context.GetCompositor().SetNextPresentCallback(
3362 size_t layers_count) {
3363 ASSERT_EQ(layers_count, 2u);
3364
3365 // Layer 0
3366 {
3369 platform_view.identifier = 42;
3370 FlutterLayer layer = {};
3371 layer.struct_size = sizeof(layer);
3374 layer.size = FlutterSizeMake(300.0, 200.0);
3375 layer.offset = FlutterPointMake(0.0, 0.0);
3376
3377 ASSERT_EQ(*layers[0], layer);
3378 }
3379
3380 // Layer 1
3381 {
3384 platform_view.identifier = 24;
3385 FlutterLayer layer = {};
3386 layer.struct_size = sizeof(layer);
3389 layer.size = FlutterSizeMake(300.0, 200.0);
3390 layer.offset = FlutterPointMake(0.0, 0.0);
3391
3392 ASSERT_EQ(*layers[1], layer);
3393 }
3394 latch.Signal();
3395 });
3396
3397 auto engine = builder.LaunchEngine();
3398
3399 FlutterWindowMetricsEvent event = {};
3400 event.struct_size = sizeof(event);
3401 event.width = 300;
3402 event.height = 200;
3403 event.pixel_ratio = 1.0;
3404 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3405 kSuccess);
3406 ASSERT_TRUE(engine.is_valid());
3407 latch.Wait();
3408
3409 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
3410}
3411
3412TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) {
3413 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3414
3415 EmbedderConfigBuilder builder(context);
3416 builder.SetSurface(DlISize(300, 200));
3417 builder.SetCompositor();
3418 builder.SetDartEntrypoint("render_targets_are_recycled");
3419 builder.SetRenderTargetType(
3421
3422 fml::CountDownLatch latch(2);
3423
3424 context.AddNativeCallback("SignalNativeTest",
3425 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3426 latch.CountDown();
3427 }));
3428
3429 context.GetCompositor().SetNextPresentCallback(
3431 size_t layers_count) {
3432 ASSERT_EQ(layers_count, 20u);
3433 latch.CountDown();
3434 });
3435
3436 auto engine = builder.LaunchEngine();
3437 ASSERT_TRUE(engine.is_valid());
3438
3439 FlutterWindowMetricsEvent event = {};
3440 event.struct_size = sizeof(event);
3441 event.width = 300;
3442 event.height = 200;
3443 event.pixel_ratio = 1.0;
3444 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3445 kSuccess);
3446
3447 latch.Wait();
3448 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 10u);
3449 ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
3450 ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 0u);
3451 // Killing the engine should immediately collect all pending render targets.
3452 engine.reset();
3453 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
3454 ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
3455 ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 10u);
3456}
3457
3458TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) {
3459 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3460
3461 EmbedderConfigBuilder builder(context);
3462 builder.SetSurface(DlISize(300, 200));
3463 builder.SetCompositor();
3464 builder.SetDartEntrypoint("render_targets_are_in_stable_order");
3465 builder.SetRenderTargetType(
3467
3468 fml::CountDownLatch latch(2);
3469
3470 context.AddNativeCallback("SignalNativeTest",
3471 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3472 latch.CountDown();
3473 }));
3474
3475 size_t frame_count = 0;
3476 std::vector<void*> first_frame_backing_store_user_data;
3477 context.GetCompositor().SetPresentCallback(
3479 size_t layers_count) {
3480 ASSERT_EQ(layers_count, 20u);
3481
3482 if (first_frame_backing_store_user_data.empty()) {
3483 for (size_t i = 0; i < layers_count; ++i) {
3485 first_frame_backing_store_user_data.push_back(
3486 layers[i]->backing_store->user_data);
3487 }
3488 }
3489 return;
3490 }
3491
3492 ASSERT_EQ(first_frame_backing_store_user_data.size(), 10u);
3493
3494 frame_count++;
3495 std::vector<void*> backing_store_user_data;
3496 for (size_t i = 0; i < layers_count; ++i) {
3498 backing_store_user_data.push_back(
3499 layers[i]->backing_store->user_data);
3500 }
3501 }
3502
3503 ASSERT_EQ(backing_store_user_data.size(), 10u);
3504
3505 ASSERT_EQ(first_frame_backing_store_user_data, backing_store_user_data);
3506
3507 if (frame_count == 20) {
3508 latch.CountDown();
3509 }
3510 },
3511 false // one shot
3512 );
3513
3514 auto engine = builder.LaunchEngine();
3515 ASSERT_TRUE(engine.is_valid());
3516
3517 FlutterWindowMetricsEvent event = {};
3518 event.struct_size = sizeof(event);
3519 event.width = 300;
3520 event.height = 200;
3521 event.pixel_ratio = 1.0;
3522 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3523 kSuccess);
3524
3525 latch.Wait();
3526}
3527
3528TEST_F(EmbedderTest, FrameInfoContainsValidWidthAndHeight) {
3529 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3530 const auto root_surface_transformation =
3531 DlMatrix::MakeTranslation({0, 1024}) *
3533 context.SetRootSurfaceTransformation(root_surface_transformation);
3534
3535 EmbedderConfigBuilder builder(context);
3536 builder.SetSurface(DlISize(600, 1024));
3537 builder.SetDartEntrypoint("push_frames_over_and_over");
3538 auto engine = builder.LaunchEngine();
3539
3540 // Send a window metrics events so frames may be scheduled.
3541 static FlutterWindowMetricsEvent event = {};
3542 event.struct_size = sizeof(event);
3543 event.width = 1024;
3544 event.height = 600;
3545 event.pixel_ratio = 1.0;
3546 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3547 kSuccess);
3548 ASSERT_TRUE(engine.is_valid());
3549
3550 static fml::CountDownLatch frame_latch(10);
3551
3552 context.AddNativeCallback("SignalNativeTest",
3553 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3554 /* Nothing to do. */
3555 }));
3556
3557 context.SetGLGetFBOCallback([](FlutterFrameInfo frame_info) {
3558 // width and height are rotated by 90 deg
3559 ASSERT_EQ(frame_info.size.width, event.height);
3560 ASSERT_EQ(frame_info.size.height, event.width);
3561
3562 frame_latch.CountDown();
3563 });
3564
3565 frame_latch.Wait();
3566}
3567
3568TEST_F(EmbedderTest, MustNotRunWithBothFBOCallbacksSet) {
3569 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3570 context.SetOpenGLFBOCallBack();
3571
3572 EmbedderConfigBuilder builder(context);
3573 builder.SetSurface(DlISize(600, 1024));
3574
3575 auto engine = builder.LaunchEngine();
3576 ASSERT_FALSE(engine.is_valid());
3577}
3578
3579TEST_F(EmbedderTest, MustNotRunWithBothPresentCallbacksSet) {
3580 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3581 context.SetOpenGLPresentCallBack();
3582
3583 EmbedderConfigBuilder builder(context);
3584 builder.SetSurface(DlISize(600, 1024));
3585
3586 auto engine = builder.LaunchEngine();
3587 ASSERT_FALSE(engine.is_valid());
3588}
3589
3590TEST_F(EmbedderTest, MustStillRunWhenPopulateExistingDamageIsNotProvided) {
3591 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3592 context.GetRendererConfig().open_gl.populate_existing_damage = nullptr;
3593
3594 EmbedderConfigBuilder builder(context);
3595 builder.SetSurface(DlISize(1, 1));
3596
3597 auto engine = builder.LaunchEngine();
3598 ASSERT_TRUE(engine.is_valid());
3599}
3600
3601TEST_F(EmbedderTest, MustRunWhenPopulateExistingDamageIsProvided) {
3602 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3603 context.GetRendererConfig().open_gl.populate_existing_damage =
3604 [](void* context, const intptr_t id,
3605 FlutterDamage* existing_damage) -> void {
3606 return reinterpret_cast<EmbedderTestContextGL*>(context)
3607 ->GLPopulateExistingDamage(id, existing_damage);
3608 };
3609
3610 EmbedderConfigBuilder builder(context);
3611 builder.SetSurface(DlISize(1, 1));
3612 auto engine = builder.LaunchEngine();
3613 ASSERT_TRUE(engine.is_valid());
3614}
3615
3616TEST_F(EmbedderTest, MustRunWithPopulateExistingDamageAndFBOCallback) {
3617 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3618 context.GetRendererConfig().open_gl.fbo_callback =
3619 [](void* context) -> uint32_t { return 0; };
3620 context.GetRendererConfig().open_gl.fbo_with_frame_info_callback = nullptr;
3621 context.GetRendererConfig().open_gl.populate_existing_damage =
3622 [](void* context, const intptr_t id,
3623 FlutterDamage* existing_damage) -> void {
3624 return reinterpret_cast<EmbedderTestContextGL*>(context)
3625 ->GLPopulateExistingDamage(id, existing_damage);
3626 };
3627
3628 EmbedderConfigBuilder builder(context);
3629 builder.SetSurface(DlISize(1, 1));
3630 auto engine = builder.LaunchEngine();
3631 ASSERT_TRUE(engine.is_valid());
3632}
3633
3635 MustNotRunWhenPopulateExistingDamageButNoOtherFBOCallback) {
3636 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3637 context.GetRendererConfig().open_gl.fbo_callback = nullptr;
3638 context.GetRendererConfig().open_gl.fbo_with_frame_info_callback = nullptr;
3639 context.GetRendererConfig().open_gl.populate_existing_damage =
3640 [](void* context, const intptr_t id,
3641 FlutterDamage* existing_damage) -> void {
3642 return reinterpret_cast<EmbedderTestContextGL*>(context)
3643 ->GLPopulateExistingDamage(id, existing_damage);
3644 };
3645
3646 EmbedderConfigBuilder builder(context);
3647 builder.SetSurface(DlISize(1, 1));
3648 auto engine = builder.LaunchEngine();
3649 ASSERT_FALSE(engine.is_valid());
3650}
3651
3652TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) {
3653 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3654 const auto root_surface_transformation =
3655 DlMatrix::MakeTranslation({0, 1024}) *
3657 context.SetRootSurfaceTransformation(root_surface_transformation);
3658
3659 EmbedderConfigBuilder builder(context);
3660 builder.SetSurface(DlISize(600, 1024));
3661 builder.SetDartEntrypoint("push_frames_over_and_over");
3662
3663 auto engine = builder.LaunchEngine();
3664
3665 // Send a window metrics events so frames may be scheduled.
3666 FlutterWindowMetricsEvent event = {};
3667 event.struct_size = sizeof(event);
3668 event.width = 1024;
3669 event.height = 600;
3670 event.pixel_ratio = 1.0;
3671 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3672 kSuccess);
3673 ASSERT_TRUE(engine.is_valid());
3674
3675 static fml::CountDownLatch frame_latch(10);
3676
3677 context.AddNativeCallback("SignalNativeTest",
3678 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3679 /* Nothing to do. */
3680 }));
3681
3682 const uint32_t window_fbo_id = context.GetWindowFBOId();
3683 context.SetGLPresentCallback(
3684 [window_fbo_id = window_fbo_id](FlutterPresentInfo present_info) {
3685 ASSERT_EQ(present_info.fbo_id, window_fbo_id);
3686
3687 frame_latch.CountDown();
3688 });
3689
3690 frame_latch.Wait();
3691}
3692
3694 PresentInfoReceivesFullDamageWhenExistingDamageIsWholeScreen) {
3695 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3696 context.GetRendererConfig().open_gl.populate_existing_damage =
3697 [](void* context, const intptr_t id,
3698 FlutterDamage* existing_damage) -> void {
3699 return reinterpret_cast<EmbedderTestContextGL*>(context)
3700 ->GLPopulateExistingDamage(id, existing_damage);
3701 };
3702 // Return existing damage as the entire screen on purpose.
3704 [](const intptr_t id, FlutterDamage* existing_damage_ptr) {
3705 const size_t num_rects = 1;
3706 // The array must be valid after the callback returns.
3707 static FlutterRect existing_damage_rects[num_rects] = {
3708 FlutterRect{0, 0, 800, 600}};
3709 existing_damage_ptr->num_rects = num_rects;
3710 existing_damage_ptr->damage = existing_damage_rects;
3711 });
3712
3713 EmbedderConfigBuilder builder(context);
3714 builder.SetSurface(DlISize(800, 600));
3715 builder.SetDartEntrypoint("render_gradient_retained");
3716 auto engine = builder.LaunchEngine();
3717 ASSERT_TRUE(engine.is_valid());
3718
3720
3721 // First frame should be entirely rerendered.
3722 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
3723 const size_t num_rects = 1;
3724 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3725 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3726 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3727 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
3728 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
3729
3730 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3731 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3732 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3733 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3734 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3735
3736 latch.Signal();
3737 });
3738
3739 // Send a window metrics events so frames may be scheduled.
3740 FlutterWindowMetricsEvent event = {};
3741 event.struct_size = sizeof(event);
3742 event.width = 800;
3743 event.height = 600;
3744 event.pixel_ratio = 1.0;
3745 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3746 kSuccess);
3747 latch.Wait();
3748
3749 // Because it's the same as the first frame, the second frame damage should
3750 // be empty but, because there was a full existing buffer damage, the buffer
3751 // damage should be the entire screen.
3752 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
3753 const size_t num_rects = 1;
3754 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3755 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3756 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3757 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
3758 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
3759
3760 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3761 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3762 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3763 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3764 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3765
3766 latch.Signal();
3767 });
3768
3769 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3770 kSuccess);
3771 latch.Wait();
3772}
3773
3774TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
3775 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3776 context.GetRendererConfig().open_gl.populate_existing_damage =
3777 [](void* context, const intptr_t id,
3778 FlutterDamage* existing_damage) -> void {
3779 return reinterpret_cast<EmbedderTestContextGL*>(context)
3780 ->GLPopulateExistingDamage(id, existing_damage);
3781 };
3782 // Return no existing damage on purpose.
3784 [](const intptr_t id, FlutterDamage* existing_damage_ptr) {
3785 const size_t num_rects = 1;
3786 // The array must be valid after the callback returns.
3787 static FlutterRect existing_damage_rects[num_rects] = {
3788 FlutterRect{0, 0, 0, 0}};
3789 existing_damage_ptr->num_rects = num_rects;
3790 existing_damage_ptr->damage = existing_damage_rects;
3791 });
3792
3793 EmbedderConfigBuilder builder(context);
3794 builder.SetSurface(DlISize(800, 600));
3795 builder.SetDartEntrypoint("render_gradient_retained");
3796 auto engine = builder.LaunchEngine();
3797 ASSERT_TRUE(engine.is_valid());
3798
3800
3801 // First frame should be entirely rerendered.
3802 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
3803 const size_t num_rects = 1;
3804 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3805 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3806 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3807 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
3808 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
3809
3810 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3811 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3812 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3813 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3814 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3815
3816 latch.Signal();
3817 });
3818
3819 // Send a window metrics events so frames may be scheduled.
3820 FlutterWindowMetricsEvent event = {};
3821 event.struct_size = sizeof(event);
3822 event.width = 800;
3823 event.height = 600;
3824 event.pixel_ratio = 1.0;
3825 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3826 kSuccess);
3827 latch.Wait();
3828
3829 // Because it's the same as the first frame, the second frame should not be
3830 // rerendered assuming there is no existing damage.
3831 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
3832 const size_t num_rects = 1;
3833 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3834 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3835 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3836 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
3837 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
3838
3839 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3840 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3841 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3842 ASSERT_EQ(present_info.buffer_damage.damage->right, 0);
3843 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 0);
3844
3845 latch.Signal();
3846 });
3847
3848 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3849 kSuccess);
3850 latch.Wait();
3851}
3852
3853TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
3854 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3855 context.GetRendererConfig().open_gl.populate_existing_damage =
3856 [](void* context, const intptr_t id,
3857 FlutterDamage* existing_damage) -> void {
3858 return reinterpret_cast<EmbedderTestContextGL*>(context)
3859 ->GLPopulateExistingDamage(id, existing_damage);
3860 };
3861 // Return existing damage as only part of the screen on purpose.
3863 [&](const intptr_t id, FlutterDamage* existing_damage_ptr) {
3864 const size_t num_rects = 1;
3865 // The array must be valid after the callback returns.
3866 static FlutterRect existing_damage_rects[num_rects] = {
3867 FlutterRect{200, 150, 400, 300}};
3868 existing_damage_ptr->num_rects = num_rects;
3869 existing_damage_ptr->damage = existing_damage_rects;
3870 });
3871
3872 EmbedderConfigBuilder builder(context);
3873 builder.SetSurface(DlISize(800, 600));
3874 builder.SetDartEntrypoint("render_gradient_retained");
3875 auto engine = builder.LaunchEngine();
3876 ASSERT_TRUE(engine.is_valid());
3877
3879
3880 // First frame should be entirely rerendered.
3881 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
3882 const size_t num_rects = 1;
3883 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3884 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3885 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3886 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
3887 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
3888
3889 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3890 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3891 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3892 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3893 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3894
3895 latch.Signal();
3896 });
3897
3898 // Send a window metrics events so frames may be scheduled.
3899 FlutterWindowMetricsEvent event = {};
3900 event.struct_size = sizeof(event);
3901 event.width = 800;
3902 event.height = 600;
3903 event.pixel_ratio = 1.0;
3904 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3905 kSuccess);
3906 latch.Wait();
3907
3908 // Because it's the same as the first frame, the second frame damage should be
3909 // empty but, because there was a partial existing damage, the buffer damage
3910 // should represent that partial damage area.
3911 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
3912 const size_t num_rects = 1;
3913 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3914 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3915 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3916 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
3917 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
3918
3919 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3920 ASSERT_EQ(present_info.buffer_damage.damage->left, 200);
3921 ASSERT_EQ(present_info.buffer_damage.damage->top, 150);
3922 ASSERT_EQ(present_info.buffer_damage.damage->right, 400);
3923 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 300);
3924
3925 latch.Signal();
3926 });
3927
3928 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3929 kSuccess);
3930 latch.Wait();
3931}
3932
3933TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) {
3934 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3935 context.GetRendererConfig().open_gl.populate_existing_damage =
3936 [](void* context, const intptr_t id,
3937 FlutterDamage* existing_damage) -> void {
3938 return reinterpret_cast<EmbedderTestContextGL*>(context)
3939 ->GLPopulateExistingDamage(id, existing_damage);
3940 };
3941
3942 EmbedderConfigBuilder builder(context);
3943 builder.SetSurface(DlISize(800, 600));
3944 builder.SetDartEntrypoint("render_gradient_retained");
3945 auto engine = builder.LaunchEngine();
3946 ASSERT_TRUE(engine.is_valid());
3947
3948 const uint32_t window_fbo_id = context.GetWindowFBOId();
3949 context.SetGLPopulateExistingDamageCallback(
3950 [window_fbo_id = window_fbo_id](intptr_t id,
3951 FlutterDamage* existing_damage) {
3952 ASSERT_EQ(id, window_fbo_id);
3953 existing_damage->num_rects = 0;
3954 existing_damage->damage = nullptr;
3955 });
3956
3957 // Send a window metrics events so frames may be scheduled.
3958 FlutterWindowMetricsEvent event = {};
3959 event.struct_size = sizeof(event);
3960 event.width = 800;
3961 event.height = 600;
3962 event.pixel_ratio = 1.0;
3963 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
3964 kSuccess);
3965}
3966
3967TEST_F(EmbedderTest, PopulateExistingDamageReceivesInvalidID) {
3968 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
3969 context.GetRendererConfig().open_gl.populate_existing_damage =
3970 [](void* context, const intptr_t id,
3971 FlutterDamage* existing_damage) -> void {
3972 return reinterpret_cast<EmbedderTestContextGL*>(context)
3973 ->GLPopulateExistingDamage(id, existing_damage);
3974 };
3975 // Return a bad FBO ID on purpose.
3977 [](void* context, const FlutterFrameInfo* frame_info) -> uint32_t {
3978 return 123;
3979 };
3980
3981 EmbedderConfigBuilder builder(context);
3982 builder.SetSurface(DlISize(800, 600));
3983 builder.SetDartEntrypoint("render_gradient_retained");
3984 auto engine = builder.LaunchEngine();
3985 ASSERT_TRUE(engine.is_valid());
3986
3987 context.AddNativeCallback("SignalNativeTest",
3988 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3989 /* Nothing to do. */
3990 }));
3991
3992 const uint32_t window_fbo_id = context.GetWindowFBOId();
3993 context.SetGLPopulateExistingDamageCallback(
3994 [window_fbo_id = window_fbo_id](intptr_t id,
3995 FlutterDamage* existing_damage) {
3996 ASSERT_NE(id, window_fbo_id);
3997 existing_damage->num_rects = 0;
3998 existing_damage->damage = nullptr;
3999 });
4000
4001 // Send a window metrics events so frames may be scheduled.
4002 FlutterWindowMetricsEvent event = {};
4003 event.struct_size = sizeof(event);
4004 event.width = 800;
4005 event.height = 600;
4006 event.pixel_ratio = 1.0;
4007 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4008 kSuccess);
4009}
4010
4011TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithDisplayId) {
4012 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4013
4014 EmbedderConfigBuilder builder(context);
4015 builder.SetSurface(DlISize(800, 600));
4016 builder.SetCompositor();
4017 builder.SetDartEntrypoint("empty_scene");
4019 context.AddNativeCallback(
4020 "SignalNativeTest",
4021 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
4022
4023 auto engine = builder.LaunchEngine();
4024
4025 ASSERT_TRUE(engine.is_valid());
4026
4027 FlutterEngineDisplay display;
4028 display.struct_size = sizeof(FlutterEngineDisplay);
4029 display.display_id = 1;
4030 display.refresh_rate = 20;
4031
4032 std::vector<FlutterEngineDisplay> displays = {display};
4033
4036 displays.size());
4037 ASSERT_EQ(result, kSuccess);
4038
4040 ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
4041
4042 FlutterWindowMetricsEvent event = {};
4043 event.struct_size = sizeof(event);
4044 event.width = 800;
4045 event.height = 600;
4046 event.pixel_ratio = 1.0;
4047 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4048 kSuccess);
4049
4050 latch.Wait();
4051}
4052
4053TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithoutDisplayId) {
4054 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4055
4056 EmbedderConfigBuilder builder(context);
4057 builder.SetSurface(DlISize(800, 600));
4058 builder.SetCompositor();
4059 builder.SetDartEntrypoint("empty_scene");
4061 context.AddNativeCallback(
4062 "SignalNativeTest",
4063 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
4064
4065 auto engine = builder.LaunchEngine();
4066
4067 ASSERT_TRUE(engine.is_valid());
4068
4069 FlutterEngineDisplay display;
4070 display.struct_size = sizeof(FlutterEngineDisplay);
4071 display.single_display = true;
4072 display.refresh_rate = 20;
4073
4074 std::vector<FlutterEngineDisplay> displays = {display};
4075
4078 displays.size());
4079 ASSERT_EQ(result, kSuccess);
4080
4082 ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
4083
4084 FlutterWindowMetricsEvent event = {};
4085 event.struct_size = sizeof(event);
4086 event.width = 800;
4087 event.height = 600;
4088 event.pixel_ratio = 1.0;
4089 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4090 kSuccess);
4091
4092 latch.Wait();
4093}
4094
4095TEST_F(EmbedderTest, SetValidMultiDisplayConfiguration) {
4096 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4097
4098 EmbedderConfigBuilder builder(context);
4099 builder.SetSurface(DlISize(800, 600));
4100 builder.SetCompositor();
4101 builder.SetDartEntrypoint("empty_scene");
4103 context.AddNativeCallback(
4104 "SignalNativeTest",
4105 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
4106
4107 auto engine = builder.LaunchEngine();
4108
4109 ASSERT_TRUE(engine.is_valid());
4110
4111 FlutterEngineDisplay display_1;
4112 display_1.struct_size = sizeof(FlutterEngineDisplay);
4113 display_1.display_id = 1;
4114 display_1.single_display = false;
4115 display_1.refresh_rate = 20;
4116
4117 FlutterEngineDisplay display_2;
4118 display_2.struct_size = sizeof(FlutterEngineDisplay);
4119 display_2.display_id = 2;
4120 display_2.single_display = false;
4121 display_2.refresh_rate = 60;
4122
4123 std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
4124
4127 displays.size());
4128 ASSERT_EQ(result, kSuccess);
4129
4131 ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display_1.refresh_rate);
4132
4133 FlutterWindowMetricsEvent event = {};
4134 event.struct_size = sizeof(event);
4135 event.width = 800;
4136 event.height = 600;
4137 event.pixel_ratio = 1.0;
4138 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4139 kSuccess);
4140
4141 latch.Wait();
4142}
4143
4144TEST_F(EmbedderTest, MultipleDisplaysWithSingleDisplayTrueIsInvalid) {
4145 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4146
4147 EmbedderConfigBuilder builder(context);
4148 builder.SetSurface(DlISize(800, 600));
4149 builder.SetCompositor();
4150 builder.SetDartEntrypoint("empty_scene");
4152 context.AddNativeCallback(
4153 "SignalNativeTest",
4154 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
4155
4156 auto engine = builder.LaunchEngine();
4157
4158 ASSERT_TRUE(engine.is_valid());
4159
4160 FlutterEngineDisplay display_1;
4161 display_1.struct_size = sizeof(FlutterEngineDisplay);
4162 display_1.display_id = 1;
4163 display_1.single_display = true;
4164 display_1.refresh_rate = 20;
4165
4166 FlutterEngineDisplay display_2;
4167 display_2.struct_size = sizeof(FlutterEngineDisplay);
4168 display_2.display_id = 2;
4169 display_2.single_display = true;
4170 display_2.refresh_rate = 60;
4171
4172 std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
4173
4176 displays.size());
4177 ASSERT_NE(result, kSuccess);
4178
4179 FlutterWindowMetricsEvent event = {};
4180 event.struct_size = sizeof(event);
4181 event.width = 800;
4182 event.height = 600;
4183 event.pixel_ratio = 1.0;
4184 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4185 kSuccess);
4186
4187 latch.Wait();
4188}
4189
4190TEST_F(EmbedderTest, MultipleDisplaysWithSameDisplayIdIsInvalid) {
4191 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4192
4193 EmbedderConfigBuilder builder(context);
4194 builder.SetSurface(DlISize(800, 600));
4195 builder.SetCompositor();
4196 builder.SetDartEntrypoint("empty_scene");
4198 context.AddNativeCallback(
4199 "SignalNativeTest",
4200 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
4201
4202 auto engine = builder.LaunchEngine();
4203
4204 ASSERT_TRUE(engine.is_valid());
4205
4206 FlutterEngineDisplay display_1;
4207 display_1.struct_size = sizeof(FlutterEngineDisplay);
4208 display_1.display_id = 1;
4209 display_1.single_display = false;
4210 display_1.refresh_rate = 20;
4211
4212 FlutterEngineDisplay display_2;
4213 display_2.struct_size = sizeof(FlutterEngineDisplay);
4214 display_2.display_id = 1;
4215 display_2.single_display = false;
4216 display_2.refresh_rate = 60;
4217
4218 std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
4219
4222 displays.size());
4223 ASSERT_NE(result, kSuccess);
4224
4225 FlutterWindowMetricsEvent event = {};
4226 event.struct_size = sizeof(event);
4227 event.width = 800;
4228 event.height = 600;
4229 event.pixel_ratio = 1.0;
4230 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4231 kSuccess);
4232
4233 latch.Wait();
4234}
4235
4236TEST_F(EmbedderTest, CompositorRenderTargetsNotRecycledWhenAvoidsCacheSet) {
4237 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4238
4239 EmbedderConfigBuilder builder(context);
4240 builder.SetSurface(DlISize(300, 200));
4241 builder.SetCompositor(/*avoid_backing_store_cache=*/true);
4242 builder.SetDartEntrypoint("render_targets_are_recycled");
4243 builder.SetRenderTargetType(
4245
4246 const unsigned num_frames = 8;
4247 const unsigned num_engine_layers = 10;
4248 const unsigned num_backing_stores = num_frames * num_engine_layers;
4249 fml::CountDownLatch latch(1 + num_frames); // 1 for native test signal.
4250
4251 context.AddNativeCallback("SignalNativeTest",
4252 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
4253 latch.CountDown();
4254 }));
4255
4256 context.GetCompositor().SetPresentCallback(
4258 size_t layers_count) {
4259 ASSERT_EQ(layers_count, 20u);
4260 latch.CountDown();
4261 },
4262 /*one_shot=*/false);
4263
4264 auto engine = builder.LaunchEngine();
4265 ASSERT_TRUE(engine.is_valid());
4266
4267 FlutterWindowMetricsEvent event = {};
4268 event.struct_size = sizeof(event);
4269 event.width = 300;
4270 event.height = 200;
4271 event.pixel_ratio = 1.0;
4272 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4273 kSuccess);
4274
4275 latch.Wait();
4276
4277 ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(),
4278 num_backing_stores);
4279 // Killing the engine should collect all the frames.
4280 engine.reset();
4281 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
4282}
4283
4284TEST_F(EmbedderTest, SnapshotRenderTargetScalesDownToDriverMax) {
4285 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4286
4287 EmbedderConfigBuilder builder(context);
4288 builder.SetSurface(DlISize(800, 600));
4289 builder.SetCompositor();
4290
4291 auto max_size = context.GetCompositor().GetGrContext()->maxRenderTargetSize();
4292
4293 context.AddIsolateCreateCallback([&]() {
4294 Dart_Handle snapshot_large_scene = Dart_GetField(
4295 Dart_RootLibrary(), tonic::ToDart("snapshot_large_scene"));
4296 tonic::DartInvoke(snapshot_large_scene, {tonic::ToDart<int64_t>(max_size)});
4297 });
4298
4300 context.AddNativeCallback(
4301 "SnapshotsCallback", CREATE_NATIVE_ENTRY(([&](Dart_NativeArguments args) {
4302 auto get_arg = [&args](int index) {
4303 Dart_Handle dart_image = Dart_GetNativeArgument(args, index);
4304 Dart_Handle internal_image =
4305 Dart_GetField(dart_image, tonic::ToDart("_image"));
4307 internal_image);
4308 };
4309
4310 CanvasImage* big_image = get_arg(0);
4311 ASSERT_EQ(big_image->width(), max_size);
4312 ASSERT_EQ(big_image->height(), max_size / 2);
4313
4314 CanvasImage* small_image = get_arg(1);
4315 ASSERT_TRUE(ImageMatchesFixture("snapshot_large_scene.png",
4316 small_image->image()->skia_image()));
4317
4318 latch.Signal();
4319 })));
4320
4321 UniqueEngine engine = builder.LaunchEngine();
4322 ASSERT_TRUE(engine.is_valid());
4323
4324 latch.Wait();
4325}
4326
4327TEST_F(EmbedderTest, ObjectsPostedViaPortsServicedOnSecondaryTaskHeap) {
4328 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4329 EmbedderConfigBuilder builder(context);
4330 builder.SetSurface(DlISize(800, 1024));
4331 builder.SetDartEntrypoint("objects_can_be_posted");
4332
4333 // Synchronously acquire the send port from the Dart end. We will be using
4334 // this to send message. The Dart end will just echo those messages back to us
4335 // for inspection.
4336 FlutterEngineDartPort port = 0;
4338 context.AddNativeCallback("SignalNativeCount",
4339 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
4341 Dart_GetNativeArgument(args, 0));
4342 event.Signal();
4343 }));
4344 auto engine = builder.LaunchEngine();
4345 ASSERT_TRUE(engine.is_valid());
4346 event.Wait();
4347 ASSERT_NE(port, 0);
4348
4349 using Trampoline = std::function<void(Dart_Handle message)>;
4350 Trampoline trampoline;
4351
4352 context.AddNativeCallback("SendObjectToNativeCode",
4353 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
4354 FML_CHECK(trampoline);
4355 auto trampoline_copy = trampoline;
4356 trampoline = nullptr;
4357 trampoline_copy(Dart_GetNativeArgument(args, 0));
4358 }));
4359
4360 // Send a boolean value and assert that it's received by the right heap.
4361 {
4362 FlutterEngineDartObject object = {};
4364 object.bool_value = true;
4365 trampoline = [&](Dart_Handle handle) {
4366 ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(handle));
4368 EXPECT_EQ(task_grade, fml::TaskSourceGrade::kDartEventLoop);
4369 event.Signal();
4370 };
4371 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
4372 kSuccess);
4373 event.Wait();
4374 }
4375}
4376
4377TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLTexture) {
4378 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4379 EmbedderConfigBuilder builder(context);
4380 builder.SetSurface(DlISize(800, 600));
4381 builder.SetCompositor();
4382 builder.SetRenderTargetType(
4384 builder.SetDartEntrypoint("invalid_backingstore");
4385
4386 class TestCollectOnce {
4387 public:
4388 // Collect() should only be called once
4389 void Collect() {
4390 ASSERT_FALSE(collected_);
4391 collected_ = true;
4392 }
4393
4394 private:
4395 bool collected_ = false;
4396 };
4398
4399 builder.GetCompositor().create_backing_store_callback =
4400 [](const FlutterBackingStoreConfig* config, //
4401 FlutterBackingStore* backing_store_out, //
4402 void* user_data //
4403 ) {
4404 backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
4405 // Deliberately set this to be invalid
4406 backing_store_out->user_data = nullptr;
4407 backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeTexture;
4408 backing_store_out->open_gl.texture.target = 0;
4409 backing_store_out->open_gl.texture.name = 0;
4410 backing_store_out->open_gl.texture.format = 0;
4411 static TestCollectOnce collect_once_user_data;
4412 collect_once_user_data = {};
4413 backing_store_out->open_gl.texture.user_data = &collect_once_user_data;
4414 backing_store_out->open_gl.texture.destruction_callback =
4415 [](void* user_data) {
4416 reinterpret_cast<TestCollectOnce*>(user_data)->Collect();
4417 };
4418 return true;
4419 };
4420
4421 context.AddNativeCallback(
4422 "SignalNativeTest",
4424 [&latch](Dart_NativeArguments args) { latch.Signal(); }));
4425
4426 auto engine = builder.LaunchEngine();
4427
4428 // Send a window metrics events so frames may be scheduled.
4429 FlutterWindowMetricsEvent event = {};
4430 event.struct_size = sizeof(event);
4431 event.width = 800;
4432 event.height = 600;
4433 event.pixel_ratio = 1.0;
4434 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4435 kSuccess);
4436 ASSERT_TRUE(engine.is_valid());
4437 latch.Wait();
4438}
4439
4440TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLFramebuffer) {
4441 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4442 EmbedderConfigBuilder builder(context);
4443 builder.SetSurface(DlISize(800, 600));
4444 builder.SetCompositor();
4445 builder.SetRenderTargetType(
4447 builder.SetDartEntrypoint("invalid_backingstore");
4448
4449 class TestCollectOnce {
4450 public:
4451 // Collect() should only be called once
4452 void Collect() {
4453 ASSERT_FALSE(collected_);
4454 collected_ = true;
4455 }
4456
4457 private:
4458 bool collected_ = false;
4459 };
4461
4462 builder.GetCompositor().create_backing_store_callback =
4463 [](const FlutterBackingStoreConfig* config, //
4464 FlutterBackingStore* backing_store_out, //
4465 void* user_data //
4466 ) {
4467 backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
4468 // Deliberately set this to be invalid
4469 backing_store_out->user_data = nullptr;
4470 backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
4471 backing_store_out->open_gl.framebuffer.target = 0;
4472 backing_store_out->open_gl.framebuffer.name = 0;
4473 static TestCollectOnce collect_once_user_data;
4474 collect_once_user_data = {};
4475 backing_store_out->open_gl.framebuffer.user_data =
4476 &collect_once_user_data;
4477 backing_store_out->open_gl.framebuffer.destruction_callback =
4478 [](void* user_data) {
4479 reinterpret_cast<TestCollectOnce*>(user_data)->Collect();
4480 };
4481 return true;
4482 };
4483
4484 context.AddNativeCallback(
4485 "SignalNativeTest",
4487 [&latch](Dart_NativeArguments args) { latch.Signal(); }));
4488
4489 auto engine = builder.LaunchEngine();
4490
4491 // Send a window metrics events so frames may be scheduled.
4492 FlutterWindowMetricsEvent event = {};
4493 event.struct_size = sizeof(event);
4494 event.width = 800;
4495 event.height = 600;
4496 event.pixel_ratio = 1.0;
4497 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4498 kSuccess);
4499 ASSERT_TRUE(engine.is_valid());
4500 latch.Wait();
4501}
4502
4503TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLSurface) {
4504 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4505 EmbedderConfigBuilder builder(context);
4506 builder.SetSurface(DlISize(800, 600));
4507 builder.SetCompositor();
4508 builder.SetRenderTargetType(
4510 builder.SetDartEntrypoint("invalid_backingstore");
4511
4513
4514 builder.GetCompositor().create_backing_store_callback =
4515 [](const FlutterBackingStoreConfig* config, //
4516 FlutterBackingStore* backing_store_out, //
4517 void* user_data //
4518 ) {
4519 backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
4520 backing_store_out->user_data = user_data;
4521 backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeSurface;
4522 backing_store_out->open_gl.surface.user_data = user_data;
4523 // Deliberately set this to an invalid format
4524 backing_store_out->open_gl.surface.format = 0;
4525 backing_store_out->open_gl.surface.make_current_callback = [](void*,
4526 bool*) {
4527 ADD_FAILURE() << "make_current_callback method should not be called";
4528 return true;
4529 };
4530 backing_store_out->open_gl.surface.clear_current_callback = [](void*,
4531 bool*) {
4532 ADD_FAILURE() << "clear_current_callback method should not be called";
4533 return true;
4534 };
4535 backing_store_out->open_gl.surface.destruction_callback =
4536 [](void* user_data) {
4537 FAIL() << "destruction_callback method should not be called";
4538 };
4539
4540 return true;
4541 };
4542
4543 context.AddNativeCallback(
4544 "SignalNativeTest",
4546 [&latch](Dart_NativeArguments args) { latch.Signal(); }));
4547
4548 auto engine = builder.LaunchEngine();
4549
4550 // Send a window metrics events so frames may be scheduled.
4551 FlutterWindowMetricsEvent event = {};
4552 event.struct_size = sizeof(event);
4553 event.width = 800;
4554 event.height = 600;
4555 event.pixel_ratio = 1.0;
4556 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4557 kSuccess);
4558 ASSERT_TRUE(engine.is_valid());
4559 latch.Wait();
4560}
4561
4562TEST_F(EmbedderTest, ExternalTextureGLRefreshedTooOften) {
4563 TestGLSurface surface(DlISize(100, 100));
4564 auto context = surface.GetGrContext();
4565
4566 typedef void (*glGenTexturesProc)(uint32_t n, uint32_t* textures);
4567 typedef void (*glFinishProc)();
4568
4569 glGenTexturesProc glGenTextures;
4570 glFinishProc glFinish;
4571
4572 glGenTextures = reinterpret_cast<glGenTexturesProc>(
4573 surface.GetProcAddress("glGenTextures"));
4574 glFinish = reinterpret_cast<glFinishProc>(surface.GetProcAddress("glFinish"));
4575
4576 uint32_t name;
4577 glGenTextures(1, &name);
4578
4579 bool resolve_called = false;
4580
4582 [&](int64_t, size_t, size_t) {
4583 resolve_called = true;
4584 auto res = std::make_unique<FlutterOpenGLTexture>();
4585 res->target = GL_TEXTURE_2D;
4586 res->name = name;
4587 res->format = GL_RGBA8;
4588 res->user_data = nullptr;
4589 res->destruction_callback = [](void*) {};
4590 res->width = res->height = 100;
4591 return res;
4592 });
4594
4595 auto skia_surface = surface.GetOnscreenSurface();
4596 DlSkCanvasAdapter canvas(skia_surface->getCanvas());
4597
4598 Texture* texture_ = &texture;
4600 .canvas = &canvas,
4601 .gr_context = context.get(),
4602 };
4603 texture_->Paint(ctx, DlRect::MakeXYWH(0, 0, 100, 100), false,
4605
4606 EXPECT_TRUE(resolve_called);
4607 resolve_called = false;
4608
4609 texture_->Paint(ctx, DlRect::MakeXYWH(0, 0, 100, 100), false,
4611
4612 EXPECT_FALSE(resolve_called);
4613
4614 texture_->MarkNewFrameAvailable();
4615 texture_->Paint(ctx, DlRect::MakeXYWH(0, 0, 100, 100), false,
4617
4618 EXPECT_TRUE(resolve_called);
4619
4620 glFinish();
4621}
4622
4625 PresentInfoReceivesFullScreenDamageWhenPopulateExistingDamageIsNotProvided) {
4626 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4627 context.GetRendererConfig().open_gl.populate_existing_damage = nullptr;
4628
4629 EmbedderConfigBuilder builder(context);
4630 builder.SetSurface(DlISize(800, 600));
4631 builder.SetDartEntrypoint("render_gradient_retained");
4632 auto engine = builder.LaunchEngine();
4633 ASSERT_TRUE(engine.is_valid());
4634
4636
4637 // First frame should be entirely rerendered.
4638 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
4639 const size_t num_rects = 1;
4640 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4641 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4642 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4643 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
4644 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
4645
4646 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4647 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
4648 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
4649 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
4650 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
4651
4652 latch.Signal();
4653 });
4654
4655 // Send a window metrics events so frames may be scheduled.
4656 FlutterWindowMetricsEvent event = {};
4657 event.struct_size = sizeof(event);
4658 event.width = 800;
4659 event.height = 600;
4660 event.pixel_ratio = 1.0;
4661 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4662 kSuccess);
4663 latch.Wait();
4664
4665 // Since populate_existing_damage is not provided, the partial repaint
4666 // functionality is actually disabled. So, the next frame should be entirely
4667 // new frame.
4668 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
4669 const size_t num_rects = 1;
4670 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4671 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4672 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4673 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
4674 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
4675
4676 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4677 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
4678 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
4679 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
4680 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
4681
4682 latch.Signal();
4683 });
4684
4685 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4686 kSuccess);
4687 latch.Wait();
4688}
4689
4691 PresentInfoReceivesJoinedDamageWhenExistingDamageContainsMultipleRects) {
4692 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4693 context.GetRendererConfig().open_gl.populate_existing_damage =
4694 [](void* context, const intptr_t id,
4695 FlutterDamage* existing_damage) -> void {
4696 return reinterpret_cast<EmbedderTestContextGL*>(context)
4697 ->GLPopulateExistingDamage(id, existing_damage);
4698 };
4699 // Return existing damage as the entire screen on purpose.
4701 [](const intptr_t id, FlutterDamage* existing_damage_ptr) {
4702 const size_t num_rects = 2;
4703 // The array must be valid after the callback returns.
4704 static FlutterRect existing_damage_rects[num_rects] = {
4705 FlutterRect{100, 150, 200, 250},
4706 FlutterRect{200, 250, 300, 350},
4707 };
4708 existing_damage_ptr->num_rects = num_rects;
4709 existing_damage_ptr->damage = existing_damage_rects;
4710 });
4711
4712 EmbedderConfigBuilder builder(context);
4713 builder.SetSurface(DlISize(800, 600));
4714 builder.SetDartEntrypoint("render_gradient_retained");
4715 auto engine = builder.LaunchEngine();
4716 ASSERT_TRUE(engine.is_valid());
4717
4719
4720 // First frame should be entirely rerendered.
4721 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
4722 const size_t num_rects = 1;
4723 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4724 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4725 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4726 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
4727 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
4728
4729 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4730 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
4731 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
4732 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
4733 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
4734
4735 latch.Signal();
4736 });
4737
4738 // Send a window metrics events so frames may be scheduled.
4739 FlutterWindowMetricsEvent event = {};
4740 event.struct_size = sizeof(event);
4741 event.width = 800;
4742 event.height = 600;
4743 event.pixel_ratio = 1.0;
4744 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4745 kSuccess);
4746 latch.Wait();
4747
4748 // Because it's the same as the first frame, the second frame damage should
4749 // be empty but, because there was a full existing buffer damage, the buffer
4750 // damage should be the entire screen.
4751 context.SetGLPresentCallback([&](FlutterPresentInfo present_info) {
4752 const size_t num_rects = 1;
4753 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4754 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4755 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4756 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
4757 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
4758
4759 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4760 ASSERT_EQ(present_info.buffer_damage.damage->left, 100);
4761 ASSERT_EQ(present_info.buffer_damage.damage->top, 150);
4762 ASSERT_EQ(present_info.buffer_damage.damage->right, 300);
4763 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 350);
4764
4765 latch.Signal();
4766 });
4767
4768 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4769 kSuccess);
4770 latch.Wait();
4771}
4772
4773TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
4774 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4775 EmbedderConfigBuilder builder(context);
4776
4777 bool present_called = false;
4778 context.SetGLPresentCallback(
4779 [&present_called](FlutterPresentInfo present_info) {
4780 present_called = true;
4781 });
4782
4783 builder.AddCommandLineArgument("--enable-impeller");
4784 builder.SetDartEntrypoint("render_impeller_test");
4785 builder.SetSurface(DlISize(800, 600));
4786 builder.SetCompositor();
4787 builder.SetRenderTargetType(
4789
4790 auto rendered_scene = context.GetNextSceneImage();
4791
4792 auto engine = builder.LaunchEngine();
4793 ASSERT_TRUE(engine.is_valid());
4794
4795 // Bind to an arbitrary FBO in order to verify that Impeller binds to the
4796 // provided FBO during rendering.
4797 typedef void (*glGenFramebuffersProc)(GLsizei n, GLuint* ids);
4798 typedef void (*glBindFramebufferProc)(GLenum target, GLuint framebuffer);
4799 auto glGenFramebuffers = reinterpret_cast<glGenFramebuffersProc>(
4800 context.GLGetProcAddress("glGenFramebuffers"));
4801 auto glBindFramebuffer = reinterpret_cast<glBindFramebufferProc>(
4802 context.GLGetProcAddress("glBindFramebuffer"));
4803 const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
4804 fml::AutoResetWaitableEvent raster_event;
4806 GLuint fbo;
4807 glGenFramebuffers(1, &fbo);
4808 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4809 raster_event.Signal();
4810 });
4811 raster_event.Wait();
4812
4813 // Send a window metrics events so frames may be scheduled.
4814 FlutterWindowMetricsEvent event = {};
4815 event.struct_size = sizeof(event);
4816 event.width = 800;
4817 event.height = 600;
4818 event.pixel_ratio = 1.0;
4819 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4820 kSuccess);
4821
4822 ASSERT_TRUE(ImageMatchesFixture(
4824 "impeller_test.png"),
4825 rendered_scene));
4826
4827 // The scene will be rendered by the compositor, and the surface present
4828 // callback should not be invoked.
4829 ASSERT_FALSE(present_called);
4830}
4831
4832TEST_F(EmbedderTest, ImpellerOpenGLImageSnapshot) {
4833 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4834
4835 bool result = false;
4837 context.AddNativeCallback("NotifyBoolValue",
4838 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
4840 Dart_GetNativeArgument(args, 0));
4841 latch.Signal();
4842 }));
4843
4844 EmbedderConfigBuilder builder(context);
4845 builder.AddCommandLineArgument("--enable-impeller");
4846 builder.SetDartEntrypoint("render_impeller_image_snapshot_test");
4847 builder.SetSurface(DlISize(800, 600));
4848 builder.SetCompositor();
4849 builder.SetRenderTargetType(
4851
4852 auto engine = builder.LaunchEngine();
4853 ASSERT_TRUE(engine.is_valid());
4854 latch.Wait();
4855
4856 ASSERT_TRUE(result);
4857}
4858
4859TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLSurface) {
4860 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4861
4862 EmbedderConfigBuilder builder(context);
4863 builder.SetSurface(DlISize(800, 600));
4864 builder.SetCompositor();
4865 builder.SetDartEntrypoint("can_composite_platform_views");
4866
4867 builder.SetRenderTargetType(
4869
4870 fml::CountDownLatch latch(3);
4871 context.GetCompositor().SetNextPresentCallback(
4873 size_t layers_count) {
4874 ASSERT_EQ(layers_count, 3u);
4875
4876 {
4877 FlutterBackingStore backing_store = *layers[0]->backing_store;
4878 backing_store.struct_size = sizeof(backing_store);
4879 backing_store.type = kFlutterBackingStoreTypeOpenGL;
4880 backing_store.did_update = true;
4882
4883 FlutterRect paint_region_rects[] = {
4884 FlutterRectMakeLTRB(0, 0, 800, 600),
4885 };
4886 FlutterRegion paint_region = {
4887 .struct_size = sizeof(FlutterRegion),
4888 .rects_count = 1,
4889 .rects = paint_region_rects,
4890 };
4891 FlutterBackingStorePresentInfo present_info = {
4893 .paint_region = &paint_region,
4894 };
4895
4896 FlutterLayer layer = {};
4897 layer.struct_size = sizeof(layer);
4899 layer.backing_store = &backing_store;
4900 layer.size = FlutterSizeMake(800.0, 600.0);
4901 layer.offset = FlutterPointMake(0, 0);
4902 layer.backing_store_present_info = &present_info;
4903 ASSERT_EQ(*layers[0], layer);
4904 }
4905
4906 {
4909 platform_view.identifier = 42;
4910
4911 FlutterLayer layer = {};
4912 layer.struct_size = sizeof(layer);
4915 layer.size = FlutterSizeMake(123.0, 456.0);
4916 layer.offset = FlutterPointMake(1.0, 2.0);
4917
4918 ASSERT_EQ(*layers[1], layer);
4919 }
4920
4921 {
4922 FlutterBackingStore backing_store = *layers[2]->backing_store;
4923 backing_store.struct_size = sizeof(backing_store);
4924 backing_store.type = kFlutterBackingStoreTypeOpenGL;
4925 backing_store.did_update = true;
4927
4928 FlutterRect paint_region_rects[] = {
4929 FlutterRectMakeLTRB(2, 3, 800, 600),
4930 };
4931 FlutterRegion paint_region = {
4932 .struct_size = sizeof(FlutterRegion),
4933 .rects_count = 1,
4934 .rects = paint_region_rects,
4935 };
4936 FlutterBackingStorePresentInfo present_info = {
4938 .paint_region = &paint_region,
4939 };
4940
4941 FlutterLayer layer = {};
4942 layer.struct_size = sizeof(layer);
4944 layer.backing_store = &backing_store;
4945 layer.size = FlutterSizeMake(800.0, 600.0);
4946 layer.offset = FlutterPointMake(0.0, 0.0);
4947 layer.backing_store_present_info = &present_info;
4948
4949 ASSERT_EQ(*layers[2], layer);
4950 }
4951
4952 latch.CountDown();
4953 });
4954
4955 context.AddNativeCallback(
4956 "SignalNativeTest",
4958 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
4959
4960 auto engine = builder.LaunchEngine();
4961
4962 // Send a window metrics events so frames may be scheduled.
4963 FlutterWindowMetricsEvent event = {};
4964 event.struct_size = sizeof(event);
4965 event.width = 800;
4966 event.height = 600;
4967 event.pixel_ratio = 1.0;
4968 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
4969 kSuccess);
4970 ASSERT_TRUE(engine.is_valid());
4971
4972 latch.Wait();
4973}
4974
4975TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownSceneToOpenGLSurfaces) {
4976 auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4977
4978 EmbedderConfigBuilder builder(context);
4979 builder.SetSurface(DlISize(800, 600));
4980 builder.SetCompositor();
4981 builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
4982
4983 builder.SetRenderTargetType(
4985
4986 fml::CountDownLatch latch(5);
4987
4988 auto scene_image = context.GetNextSceneImage();
4989
4990 context.GetCompositor().SetNextPresentCallback(
4992 size_t layers_count) {
4993 ASSERT_EQ(layers_count, 5u);
4994
4995 // Layer Root
4996 {
4997 FlutterBackingStore backing_store = *layers[0]->backing_store;
4998 backing_store.type = kFlutterBackingStoreTypeOpenGL;
4999 backing_store.did_update = true;
5001
5002 FlutterRect paint_region_rects[] = {
5003 FlutterRectMakeLTRB(0, 0, 800, 600),
5004 };
5005 FlutterRegion paint_region = {
5006 .struct_size = sizeof(FlutterRegion),
5007 .rects_count = 1,
5008 .rects = paint_region_rects,
5009 };
5010 FlutterBackingStorePresentInfo present_info = {
5012 .paint_region = &paint_region,
5013 };
5014
5015 FlutterLayer layer = {};
5016 layer.struct_size = sizeof(layer);
5018 layer.backing_store = &backing_store;
5019 layer.size = FlutterSizeMake(800.0, 600.0);
5020 layer.offset = FlutterPointMake(0.0, 0.0);
5021 layer.backing_store_present_info = &present_info;
5022
5023 ASSERT_EQ(*layers[0], layer);
5024 }
5025
5026 // Layer 1
5027 {
5030 platform_view.identifier = 1;
5031
5032 FlutterLayer layer = {};
5033 layer.struct_size = sizeof(layer);
5036 layer.size = FlutterSizeMake(50.0, 150.0);
5037 layer.offset = FlutterPointMake(20.0, 20.0);
5038
5039 ASSERT_EQ(*layers[1], layer);
5040 }
5041
5042 // Layer 2
5043 {
5044 FlutterBackingStore backing_store = *layers[2]->backing_store;
5045 backing_store.type = kFlutterBackingStoreTypeOpenGL;
5046 backing_store.did_update = true;
5048
5049 FlutterRect paint_region_rects[] = {
5050 FlutterRectMakeLTRB(30, 30, 80, 180),
5051 };
5052 FlutterRegion paint_region = {
5053 .struct_size = sizeof(FlutterRegion),
5054 .rects_count = 1,
5055 .rects = paint_region_rects,
5056 };
5057 FlutterBackingStorePresentInfo present_info = {
5059 .paint_region = &paint_region,
5060 };
5061
5062 FlutterLayer layer = {};
5063 layer.struct_size = sizeof(layer);
5065 layer.backing_store = &backing_store;
5066 layer.size = FlutterSizeMake(800.0, 600.0);
5067 layer.offset = FlutterPointMake(0.0, 0.0);
5068 layer.backing_store_present_info = &present_info;
5069
5070 ASSERT_EQ(*layers[2], layer);
5071 }
5072
5073 // Layer 3
5074 {
5077 platform_view.identifier = 2;
5078
5079 FlutterLayer layer = {};
5080 layer.struct_size = sizeof(layer);
5083 layer.size = FlutterSizeMake(50.0, 150.0);
5084 layer.offset = FlutterPointMake(40.0, 40.0);
5085
5086 ASSERT_EQ(*layers[3], layer);
5087 }
5088
5089 // Layer 4
5090 {
5091 FlutterBackingStore backing_store = *layers[4]->backing_store;
5092 backing_store.type = kFlutterBackingStoreTypeOpenGL;
5093 backing_store.did_update = true;
5095
5096 FlutterRect paint_region_rects[] = {
5097 FlutterRectMakeLTRB(50, 50, 100, 200),
5098 };
5099 FlutterRegion paint_region = {
5100 .struct_size = sizeof(FlutterRegion),
5101 .rects_count = 1,
5102 .rects = paint_region_rects,
5103 };
5104 FlutterBackingStorePresentInfo present_info = {
5106 .paint_region = &paint_region,
5107 };
5108
5109 FlutterLayer layer = {};
5110 layer.struct_size = sizeof(layer);
5112 layer.backing_store = &backing_store;
5113 layer.size = FlutterSizeMake(800.0, 600.0);
5114 layer.offset = FlutterPointMake(0.0, 0.0);
5115 layer.backing_store_present_info = &present_info;
5116
5117 ASSERT_EQ(*layers[4], layer);
5118 }
5119
5120 latch.CountDown();
5121 });
5122
5123 context.GetCompositor().SetPlatformViewRendererCallback(
5124 [&](const FlutterLayer& layer,
5125 GrDirectContext* context) -> sk_sp<SkImage> {
5126 auto surface = CreateRenderSurface(layer, context);
5127 auto canvas = surface->getCanvas();
5128 FML_CHECK(canvas != nullptr);
5129
5130 switch (layer.platform_view->identifier) {
5131 case 1: {
5132 SkPaint paint;
5133 // See dart test for total order.
5134 paint.setColor(SK_ColorGREEN);
5135 paint.setAlpha(127);
5136 const auto& rect =
5137 SkRect::MakeWH(layer.size.width, layer.size.height);
5138 canvas->drawRect(rect, paint);
5139 latch.CountDown();
5140 } break;
5141 case 2: {
5142 SkPaint paint;
5143 // See dart test for total order.
5144 paint.setColor(SK_ColorMAGENTA);
5145 paint.setAlpha(127);
5146 const auto& rect =
5147 SkRect::MakeWH(layer.size.width, layer.size.height);
5148 canvas->drawRect(rect, paint);
5149 latch.CountDown();
5150 } break;
5151 default:
5152 // Asked to render an unknown platform view.
5153 FML_CHECK(false)
5154 << "Test was asked to composite an unknown platform view.";
5155 }
5156
5157 return surface->makeImageSnapshot();
5158 });
5159
5160 context.AddNativeCallback(
5161 "SignalNativeTest",
5163 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
5164
5165 auto engine = builder.LaunchEngine();
5166
5167 // Send a window metrics events so frames may be scheduled.
5168 FlutterWindowMetricsEvent event = {};
5169 event.struct_size = sizeof(event);
5170 event.width = 800;
5171 event.height = 600;
5172 event.pixel_ratio = 1.0;
5173 ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
5174 kSuccess);
5175 ASSERT_TRUE(engine.is_valid());
5176
5177 latch.Wait();
5178
5179 ASSERT_TRUE(ImageMatchesFixture("compositor.png", scene_image));
5180
5181 // There should no present calls on the root surface.
5182 ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
5183}
5184
5186 EmbedderTestGlVk,
5190
5191} // namespace flutter::testing
5192
5193// NOLINTEND(clang-analyzer-core.StackAddressEscape)
std::unique_ptr< flutter::PlatformViewIOS > platform_view
GLenum type
sk_sp< DlImage > image() const
Definition image.h:42
Backend implementation of |DlCanvas| for |SkCanvas|.
std::function< std::unique_ptr< FlutterOpenGLTexture >(int64_t, size_t, size_t)> ExternalTextureCallback
size_t GetCachedEntriesCount() const
fml::TaskRunnerAffineWeakPtr< Rasterizer > GetRasterizer() const
Rasterizers may only be accessed on the raster task runner.
Definition shell.cc:920
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
Definition shell.cc:911
double GetMainDisplayRefreshRate()
Queries the DisplayManager for the main display refresh rate.
Definition shell.cc:2031
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
virtual void MarkNewFrameAvailable()=0
virtual void Paint(PaintContext &context, const DlRect &bounds, bool freeze, const DlImageSampling sampling)=0
void SetPlatformTaskRunner(const FlutterTaskRunnerDescription *runner)
void SetRenderTargetType(EmbedderTestBackingStoreProducer::RenderTargetType type, FlutterSoftwarePixelFormat software_pixfmt=kFlutterSoftwarePixelFormatNative32)
void SetRenderTaskRunner(const FlutterTaskRunnerDescription *runner)
void SetCompositor(bool avoid_backing_store_cache=false, bool use_present_layers_callback=false)
void SetGLPopulateExistingDamageCallback(GLPopulateExistingDamageCallback callback)
A task runner that we expect the embedder to provide but whose implementation is a real FML task runn...
static TaskSourceGrade GetCurrentTaskSourceGrade()
virtual void PostTask(const fml::closure &task) override
FlutterEngineResult FlutterEngineRunTask(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterTask *task)
Inform the engine to run the specified task. This task has been given to the embedder via the Flutter...
Definition embedder.cc:3313
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterWindowMetricsEvent *flutter_metrics)
Definition embedder.cc:2660
FlutterEngineResult FlutterEnginePostDartObject(FLUTTER_API_SYMBOL(FlutterEngine) engine, FlutterEngineDartPort port, const FlutterEngineDartObject *object)
Posts a Dart object to specified send port. The corresponding receive port for send port can be in an...
Definition embedder.cc:3428
FLUTTER_EXPORT FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Stops running the Flutter engine instance. After this call, the embedder is also guaranteed that no m...
Definition embedder.cc:2636
FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Shuts down a Flutter engine instance. The engine handle is no longer valid for any calls in the embed...
Definition embedder.cc:2649
FlutterEngineResult FlutterEngineNotifyDisplayUpdate(FLUTTER_API_SYMBOL(FlutterEngine) raw_engine, const FlutterEngineDisplaysUpdateType update_type, const FlutterEngineDisplay *embedder_displays, size_t display_count)
Posts updates corresponding to display changes to a running engine instance.
Definition embedder.cc:3613
FlutterEngineResult FlutterEngineRunInitialized(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Runs an initialized engine instance. An engine can be initialized via FlutterEngineInitialize....
Definition embedder.cc:2461
@ kFlutterLayerContentTypePlatformView
Indicates that the contents of this layer are determined by the embedder.
Definition embedder.h:2104
@ kFlutterLayerContentTypeBackingStore
Definition embedder.h:2102
@ kFlutterPlatformViewMutationTypeClipRoundedRect
Definition embedder.h:2006
@ kFlutterPlatformViewMutationTypeClipRect
Definition embedder.h:2003
@ kFlutterPlatformViewMutationTypeTransformation
Definition embedder.h:2009
@ kFlutterPlatformViewMutationTypeOpacity
Definition embedder.h:2000
@ kFlutterEngineDartObjectTypeString
Definition embedder.h:2336
@ kFlutterEngineDartObjectTypeBool
Definition embedder.h:2332
@ kFlutterEngineDartObjectTypeDouble
Definition embedder.h:2335
@ kFlutterEngineDartObjectTypeInt32
Definition embedder.h:2333
@ kFlutterEngineDartObjectTypeBuffer
Definition embedder.h:2339
@ kFlutterEngineDartObjectTypeInt64
Definition embedder.h:2334
@ kFlutterEngineDartObjectTypeNull
Definition embedder.h:2331
FlutterEngineResult
Definition embedder.h:72
@ kFlutterEngineDisplaysUpdateTypeStartup
Definition embedder.h:2324
int64_t FlutterEngineDartPort
Definition embedder.h:2328
@ kFlutterOpenGLTargetTypeFramebuffer
Definition embedder.h:417
@ kFlutterOpenGLTargetTypeSurface
Definition embedder.h:420
@ kFlutterOpenGLTargetTypeTexture
Definition embedder.h:414
@ kFlutterBackingStoreTypeSoftware
Specified an software allocation for Flutter to render into using the CPU.
Definition embedder.h:2053
@ kFlutterBackingStoreTypeOpenGL
Definition embedder.h:2051
flutter::DlMatrix DlMatrixMake(const FlutterTransformation &xformation)
FlutterSize FlutterSizeMake(double width, double height)
FlutterRect FlutterRectMake(const SkRect &rect)
FlutterRect FlutterRectMakeLTRB(double l, double t, double r, double b)
FlutterPoint FlutterPointMake(double x, double y)
FlutterTransformation FlutterTransformationMake(const flutter::DlMatrix &matrix)
SkRect SkRectMake(const FlutterRect &rect)
flutter::EmbedderEngine * ToEmbedderEngine(const FlutterEngine &engine)
FlutterRoundedRect FlutterRoundedRectMake(const SkRRect &rect)
FlutterEngine engine
Definition main.cc:84
VkSurfaceKHR surface
Definition main.cc:65
const FlutterLayer size_t layers_count
const FlutterLayer ** layers
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_BEGIN_DECLS GBytes * message
uint32_t * target
G_BEGIN_DECLS FlutterViewId view_id
FlutterDesktopBinaryReply callback
#define FML_CHECK(condition)
Definition logging.h:104
size_t length
FlTexture * texture
TEST_F(DisplayListTest, Defaults)
sk_sp< SkSurface > CreateRenderSurface(const FlutterLayer &layer, GrDirectContext *context)
bool MemsetPatternSetOrCheck(uint8_t *buffer, size_t size, MemsetPatternOp op)
Depending on the operation, either scribbles a known pattern into the buffer or checks if that patter...
Definition testing.cc:78
void FilterMutationsByType(const FlutterPlatformViewMutation **mutations, size_t count, FlutterPlatformViewMutationType type, const std::function< void(const FlutterPlatformViewMutation &mutation)> &handler)
void ConfigureBackingStore(FlutterBackingStore &backing_store, EmbedderTestContextType backend, bool opengl_framebuffer)
Configures per-backend properties for a given backing store.
INSTANTIATE_TEST_SUITE_P(EmbedderTestGlVk, EmbedderTestMultiBackend, ::testing::Values(EmbedderTestContextType::kOpenGLContext, EmbedderTestContextType::kVulkanContext))
TEST_P(DlGoldenTest, TextBlurMaskFilterRespectCTM)
std::string FixtureNameForBackend(EmbedderTestContextType backend, const std::string &name)
Prepends a prefix to the name which is unique to the test context type. This is useful for tests that...
bool ImageMatchesFixture(const std::string &fixture_file_name, const sk_sp< SkImage > &scene_image)
EmbedderTestBackingStoreProducer::RenderTargetType GetRenderTargetFromBackend(EmbedderTestContextType backend, bool opengl_framebuffer)
Resolves a render target type for a given backend description. This is useful for tests that use Embe...
DlMatrix GetTotalMutationTransformationMatrix(const FlutterPlatformViewMutation **mutations, size_t count)
impeller::ISize32 DlISize
impeller::Degrees DlDegrees
DEF_SWITCHES_START aot vmservice shared library name
Definition switch_defs.h:27
int64_t FlutterViewId
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
Dart_Handle ToDart(const T &object)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
std::vector< FlutterEngineDisplay > * displays
FlutterBackingStoreType type
Specifies the type of backing store.
Definition embedder.h:2071
FlutterOpenGLBackingStore open_gl
The description of the OpenGL backing store.
Definition embedder.h:2077
FlutterSoftwareBackingStore software
The description of the software backing store.
Definition embedder.h:2079
size_t struct_size
The size of this struct. Must be sizeof(FlutterBackingStore).
Definition embedder.h:2065
size_t struct_size
The size of this struct. Must be sizeof(FlutterBackingStorePresentInfo).
Definition embedder.h:2121
A structure to represent a damage region.
Definition embedder.h:664
size_t num_rects
The number of rectangles within the damage region.
Definition embedder.h:668
FlutterRect * damage
The actual damage region(s) in question.
Definition embedder.h:670
FlutterEngineDartObjectType type
Definition embedder.h:2387
size_t struct_size
The size of this struct. Must be sizeof(FlutterEngineDisplay).
Definition embedder.h:2291
FlutterEngineDisplayId display_id
Definition embedder.h:2293
FlutterUIntSize size
The size of the surface that will be backed by the fbo.
Definition embedder.h:683
FlutterPoint offset
Definition embedder.h:2145
FlutterLayerContentType type
Definition embedder.h:2134
const FlutterBackingStore * backing_store
Definition embedder.h:2138
FlutterBackingStorePresentInfo * backing_store_present_info
Definition embedder.h:2151
const FlutterPlatformView * platform_view
Definition embedder.h:2141
size_t struct_size
This size of this struct. Must be sizeof(FlutterLayer).
Definition embedder.h:2131
FlutterSize size
The size of the layer (in physical pixels).
Definition embedder.h:2147
FlutterOpenGLTargetType type
Definition embedder.h:1914
UIntFrameInfoCallback fbo_with_frame_info_callback
Definition embedder.h:771
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformView).
Definition embedder.h:2025
FlutterPlatformViewIdentifier identifier
Definition embedder.h:2029
FlutterTransformation transformation
Definition embedder.h:2019
FlutterPlatformViewMutationType type
The type of the mutation described by the subsequent union.
Definition embedder.h:2014
FlutterRoundedRect clip_rounded_rect
Definition embedder.h:2018
uint32_t fbo_id
Id of the fbo backing the surface that was presented.
Definition embedder.h:705
FlutterDamage frame_damage
Damage representing the area that the compositor needs to render.
Definition embedder.h:707
FlutterDamage buffer_damage
Damage used to set the buffer's damage region.
Definition embedder.h:709
A structure to represent a rectangle.
Definition embedder.h:641
double bottom
Definition embedder.h:645
double top
Definition embedder.h:643
double left
Definition embedder.h:642
double right
Definition embedder.h:644
A region represented by a collection of non-overlapping rectangles.
Definition embedder.h:2108
size_t struct_size
The size of this struct. Must be sizeof(FlutterRegion).
Definition embedder.h:2110
FlutterOpenGLRendererConfig open_gl
Definition embedder.h:1033
double height
Definition embedder.h:629
double width
Definition embedder.h:628
size_t row_bytes
The number of bytes in a single row of the allocation.
Definition embedder.h:1932
size_t height
The number of rows in the allocation.
Definition embedder.h:1934
uint32_t height
Definition embedder.h:637
uint32_t width
Definition embedder.h:636
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition embedder.h:1047
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95
static Matrix MakeRotationZ(Radians r)
Definition matrix.h:223
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
static constexpr TRect MakeWH(Type width, Type height)
Definition rect.h:140
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
Definition rect.h:438
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
#define CREATE_NATIVE_ENTRY(native_entry)
const uintptr_t id