Flutter Engine
The Flutter Engine
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 "vulkan/vulkan.h"
13
14#include "GLES3/gl3.h"
15#include "flutter/flow/raster_cache.h"
16#include "flutter/fml/file.h"
17#include "flutter/fml/make_copyable.h"
18#include "flutter/fml/mapping.h"
19#include "flutter/fml/message_loop.h"
20#include "flutter/fml/message_loop_task_queues.h"
21#include "flutter/fml/native_library.h"
22#include "flutter/fml/paths.h"
23#include "flutter/fml/synchronization/count_down_latch.h"
24#include "flutter/fml/synchronization/waitable_event.h"
25#include "flutter/fml/task_source.h"
26#include "flutter/fml/thread.h"
27#include "flutter/lib/ui/painting/image.h"
28#include "flutter/runtime/dart_vm.h"
29#include "flutter/shell/platform/embedder/embedder_surface_gl_impeller.h"
30#include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
31#include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"
32#include "flutter/shell/platform/embedder/tests/embedder_test.h"
33#include "flutter/shell/platform/embedder/tests/embedder_test_context_gl.h"
34#include "flutter/shell/platform/embedder/tests/embedder_unittests_util.h"
35#include "flutter/testing/assertions_skia.h"
36#include "flutter/testing/test_gl_surface.h"
37#include "flutter/testing/testing.h"
40
41// CREATE_NATIVE_ENTRY is leaky by design
42// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
43
44namespace flutter {
45namespace testing {
46
48
49TEST_F(EmbedderTest, CanGetVulkanEmbedderContext) {
50 auto& context = GetEmbedderContext(EmbedderTestContextType::kVulkanContext);
52}
53
54TEST_F(EmbedderTest, CanCreateOpenGLRenderingEngine) {
56 GetEmbedderContext(EmbedderTestContextType::kOpenGLContext));
57 builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
58 auto engine = builder.LaunchEngine();
59 ASSERT_TRUE(engine.is_valid());
60}
61
62//------------------------------------------------------------------------------
63/// If an incorrectly configured compositor is set on the engine, the engine
64/// must fail to launch instead of failing to render a frame at a later point in
65/// time.
66///
68 MustPreventEngineLaunchWhenRequiredCompositorArgsAreAbsent) {
69 auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
71 builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
72 builder.SetCompositor();
73 builder.GetCompositor().create_backing_store_callback = nullptr;
74 builder.GetCompositor().collect_backing_store_callback = nullptr;
75 builder.GetCompositor().present_layers_callback = nullptr;
76 builder.GetCompositor().present_view_callback = nullptr;
77 auto engine = builder.LaunchEngine();
78 ASSERT_FALSE(engine.is_valid());
79}
80
81//------------------------------------------------------------------------------
82/// Either present_layers_callback or present_view_callback must be provided,
83/// but not both, otherwise the engine must fail to launch instead of failing to
84/// render a frame at a later point in time.
85///
86TEST_F(EmbedderTest, LaunchFailsWhenMultiplePresentCallbacks) {
87 auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
89 builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
90 builder.SetCompositor();
91 builder.GetCompositor().present_layers_callback =
92 [](const FlutterLayer** layers, size_t layers_count, void* user_data) {
93 return true;
94 };
95 builder.GetCompositor().present_view_callback =
96 [](const FlutterPresentViewInfo* info) { return true; };
97 auto engine = builder.LaunchEngine();
98 ASSERT_FALSE(engine.is_valid());
99}
100
101//------------------------------------------------------------------------------
102/// Must be able to render to a custom compositor whose render targets are fully
103/// complete OpenGL textures.
104///
105TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) {
106 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
107
109 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
110 builder.SetCompositor();
111 builder.SetDartEntrypoint("can_composite_platform_views");
112
113 builder.SetRenderTargetType(
115
116 fml::CountDownLatch latch(3);
117 context.GetCompositor().SetNextPresentCallback(
118 [&](FlutterViewId view_id, const FlutterLayer** layers,
119 size_t layers_count) {
120 ASSERT_EQ(layers_count, 3u);
121
122 {
123 FlutterBackingStore backing_store = *layers[0]->backing_store;
124 backing_store.struct_size = sizeof(backing_store);
125 backing_store.type = kFlutterBackingStoreTypeOpenGL;
126 backing_store.did_update = true;
128
129 FlutterRect paint_region_rects[] = {
130 FlutterRectMakeLTRB(0, 0, 800, 600),
131 };
132 FlutterRegion paint_region = {
133 .struct_size = sizeof(FlutterRegion),
134 .rects_count = 1,
135 .rects = paint_region_rects,
136 };
137 FlutterBackingStorePresentInfo present_info = {
139 .paint_region = &paint_region,
140 };
141
142 FlutterLayer layer = {};
143 layer.struct_size = sizeof(layer);
145 layer.backing_store = &backing_store;
146 layer.size = FlutterSizeMake(800.0, 600.0);
147 layer.offset = FlutterPointMake(0, 0);
148 layer.backing_store_present_info = &present_info;
149
150 ASSERT_EQ(*layers[0], layer);
151 }
152
153 {
155 platform_view.struct_size = sizeof(platform_view);
156 platform_view.identifier = 42;
157
158 FlutterLayer layer = {};
159 layer.struct_size = sizeof(layer);
162 layer.size = FlutterSizeMake(123.0, 456.0);
163 layer.offset = FlutterPointMake(1.0, 2.0);
164
165 ASSERT_EQ(*layers[1], layer);
166 }
167
168 {
169 FlutterBackingStore backing_store = *layers[2]->backing_store;
170 backing_store.struct_size = sizeof(backing_store);
171 backing_store.type = kFlutterBackingStoreTypeOpenGL;
172 backing_store.did_update = true;
174
175 FlutterRect paint_region_rects[] = {
176 FlutterRectMakeLTRB(2, 3, 800, 600),
177 };
178 FlutterRegion paint_region = {
179 .struct_size = sizeof(FlutterRegion),
180 .rects_count = 1,
181 .rects = paint_region_rects,
182 };
183 FlutterBackingStorePresentInfo present_info = {
185 .paint_region = &paint_region,
186 };
187
188 FlutterLayer layer = {};
189 layer.struct_size = sizeof(layer);
191 layer.backing_store = &backing_store;
192 layer.size = FlutterSizeMake(800.0, 600.0);
193 layer.offset = FlutterPointMake(0.0, 0.0);
194 layer.backing_store_present_info = &present_info;
195
196 ASSERT_EQ(*layers[2], layer);
197 }
198
199 latch.CountDown();
200 });
201
202 context.AddNativeCallback(
203 "SignalNativeTest",
205 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
206
207 auto engine = builder.LaunchEngine();
208
209 // Send a window metrics events so frames may be scheduled.
210 FlutterWindowMetricsEvent event = {};
211 event.struct_size = sizeof(event);
212 event.width = 800;
213 event.height = 600;
214 event.pixel_ratio = 1.0;
216 kSuccess);
217 ASSERT_TRUE(engine.is_valid());
218
219 latch.Wait();
220}
221
222//------------------------------------------------------------------------------
223/// Layers in a hierarchy containing a platform view should not be cached. The
224/// other layers in the hierarchy should be, however.
225TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) {
226 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
227
229 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
230 builder.SetCompositor();
231 builder.SetDartEntrypoint("can_composite_platform_views_with_opacity");
232
233 builder.SetRenderTargetType(
235
237 fml::CountDownLatch verify(1);
238
239 context.GetCompositor().SetNextPresentCallback(
240 [&](FlutterViewId view_id, const FlutterLayer** layers,
241 size_t layers_count) {
242 ASSERT_EQ(layers_count, 3u);
243
244 {
245 FlutterBackingStore backing_store = *layers[0]->backing_store;
246 backing_store.struct_size = sizeof(backing_store);
247 backing_store.type = kFlutterBackingStoreTypeOpenGL;
248 backing_store.did_update = true;
250
251 FlutterRect paint_region_rects[] = {
252 FlutterRectMakeLTRB(0, 0, 800, 600),
253 };
254 FlutterRegion paint_region = {
255 .struct_size = sizeof(FlutterRegion),
256 .rects_count = 1,
257 .rects = paint_region_rects,
258 };
259 FlutterBackingStorePresentInfo present_info = {
261 .paint_region = &paint_region,
262 };
263
264 FlutterLayer layer = {};
265 layer.struct_size = sizeof(layer);
267 layer.backing_store = &backing_store;
268 layer.size = FlutterSizeMake(800.0, 600.0);
269 layer.offset = FlutterPointMake(0, 0);
270 layer.backing_store_present_info = &present_info;
271
272 ASSERT_EQ(*layers[0], layer);
273 }
274
275 {
277 platform_view.struct_size = sizeof(platform_view);
278 platform_view.identifier = 42;
279
280 FlutterLayer layer = {};
281 layer.struct_size = sizeof(layer);
284 layer.size = FlutterSizeMake(123.0, 456.0);
285 layer.offset = FlutterPointMake(1.0, 2.0);
286
287 ASSERT_EQ(*layers[1], layer);
288 }
289
290 {
291 FlutterBackingStore backing_store = *layers[2]->backing_store;
292 backing_store.struct_size = sizeof(backing_store);
293 backing_store.type = kFlutterBackingStoreTypeOpenGL;
294 backing_store.did_update = true;
296
297 FlutterRect paint_region_rects[] = {
298 FlutterRectMakeLTRB(3, 3, 800, 600),
299 };
300 FlutterRegion paint_region = {
301 .struct_size = sizeof(FlutterRegion),
302 .rects_count = 1,
303 .rects = paint_region_rects,
304 };
305 FlutterBackingStorePresentInfo present_info = {
307 .paint_region = &paint_region,
308 };
309
310 FlutterLayer layer = {};
311 layer.struct_size = sizeof(layer);
313 layer.backing_store = &backing_store;
314 layer.size = FlutterSizeMake(800.0, 600.0);
315 layer.offset = FlutterPointMake(0.0, 0.0);
316 layer.backing_store_present_info = &present_info;
317
318 ASSERT_EQ(*layers[2], layer);
319 }
320
321 setup.CountDown();
322 });
323
324 context.AddNativeCallback(
325 "SignalNativeTest",
327 [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
328
329 UniqueEngine engine = builder.LaunchEngine();
330
331 // Send a window metrics events so frames may be scheduled.
332 FlutterWindowMetricsEvent event = {};
333 event.struct_size = sizeof(event);
334 event.width = 800;
335 event.height = 600;
336 event.pixel_ratio = 1.0;
338 kSuccess);
339 ASSERT_TRUE(engine.is_valid());
340
341 setup.Wait();
343 shell.GetTaskRunners().GetRasterTaskRunner()->PostTask([&] {
344 const flutter::RasterCache& raster_cache =
345 shell.GetRasterizer()->compositor_context()->raster_cache();
346 // 3 layers total, but one of them had the platform view. So the cache
347 // should only have 2 entries.
348 ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 2u);
349 verify.CountDown();
350 });
351
352 verify.Wait();
353}
354
355//------------------------------------------------------------------------------
356/// The RasterCache should normally be enabled.
357///
358TEST_F(EmbedderTest, RasterCacheEnabled) {
359 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
360
362 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
363 builder.SetCompositor();
364 builder.SetDartEntrypoint("can_composite_with_opacity");
365
366 builder.SetRenderTargetType(
368
370 fml::CountDownLatch verify(1);
371
372 context.GetCompositor().SetNextPresentCallback(
373 [&](FlutterViewId view_id, const FlutterLayer** layers,
374 size_t layers_count) {
375 ASSERT_EQ(layers_count, 1u);
376
377 {
378 FlutterBackingStore backing_store = *layers[0]->backing_store;
379 backing_store.struct_size = sizeof(backing_store);
380 backing_store.type = kFlutterBackingStoreTypeOpenGL;
381 backing_store.did_update = true;
383
384 FlutterRect paint_region_rects[] = {
385 FlutterRectMakeLTRB(0, 0, 800, 600),
386 };
387 FlutterRegion paint_region = {
388 .struct_size = sizeof(FlutterRegion),
389 .rects_count = 1,
390 .rects = paint_region_rects,
391 };
392 FlutterBackingStorePresentInfo present_info = {
394 .paint_region = &paint_region,
395 };
396
397 FlutterLayer layer = {};
398 layer.struct_size = sizeof(layer);
400 layer.backing_store = &backing_store;
401 layer.size = FlutterSizeMake(800.0, 600.0);
402 layer.offset = FlutterPointMake(0, 0);
403 layer.backing_store_present_info = &present_info;
404
405 ASSERT_EQ(*layers[0], layer);
406 }
407
408 setup.CountDown();
409 });
410
411 context.AddNativeCallback(
412 "SignalNativeTest",
414 [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
415
416 UniqueEngine engine = builder.LaunchEngine();
417
418 // Send a window metrics events so frames may be scheduled.
419 FlutterWindowMetricsEvent event = {};
420 event.struct_size = sizeof(event);
421 event.width = 800;
422 event.height = 600;
423 event.pixel_ratio = 1.0;
425 kSuccess);
426 ASSERT_TRUE(engine.is_valid());
427
428 setup.Wait();
430 shell.GetTaskRunners().GetRasterTaskRunner()->PostTask([&] {
431 const flutter::RasterCache& raster_cache =
432 shell.GetRasterizer()->compositor_context()->raster_cache();
433 ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 1u);
434 verify.CountDown();
435 });
436
437 verify.Wait();
438}
439
440//------------------------------------------------------------------------------
441/// Must be able to render using a custom compositor whose render targets for
442/// the individual layers are OpenGL textures.
443///
444TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) {
445 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
446
448 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
449 builder.SetCompositor();
450 builder.SetDartEntrypoint("can_composite_platform_views");
451
452 builder.SetRenderTargetType(
454
455 fml::CountDownLatch latch(3);
456 context.GetCompositor().SetNextPresentCallback(
457 [&](FlutterViewId view_id, const FlutterLayer** layers,
458 size_t layers_count) {
459 ASSERT_EQ(layers_count, 3u);
460
461 {
462 FlutterBackingStore backing_store = *layers[0]->backing_store;
463 backing_store.struct_size = sizeof(backing_store);
464 backing_store.type = kFlutterBackingStoreTypeOpenGL;
465 backing_store.did_update = true;
467
468 FlutterRect paint_region_rects[] = {
469 FlutterRectMakeLTRB(0, 0, 800, 600),
470 };
471 FlutterRegion paint_region = {
472 .struct_size = sizeof(FlutterRegion),
473 .rects_count = 1,
474 .rects = paint_region_rects,
475 };
476 FlutterBackingStorePresentInfo present_info = {
478 .paint_region = &paint_region,
479 };
480
481 FlutterLayer layer = {};
482 layer.struct_size = sizeof(layer);
484 layer.backing_store = &backing_store;
485 layer.size = FlutterSizeMake(800.0, 600.0);
486 layer.offset = FlutterPointMake(0, 0);
487 layer.backing_store_present_info = &present_info;
488
489 ASSERT_EQ(*layers[0], layer);
490 }
491
492 {
494 platform_view.struct_size = sizeof(platform_view);
495 platform_view.identifier = 42;
496
497 FlutterLayer layer = {};
498 layer.struct_size = sizeof(layer);
501 layer.size = FlutterSizeMake(123.0, 456.0);
502 layer.offset = FlutterPointMake(1.0, 2.0);
503
504 ASSERT_EQ(*layers[1], layer);
505 }
506
507 {
508 FlutterBackingStore backing_store = *layers[2]->backing_store;
509 backing_store.struct_size = sizeof(backing_store);
510 backing_store.type = kFlutterBackingStoreTypeOpenGL;
511 backing_store.did_update = true;
513
514 FlutterRect paint_region_rects[] = {
515 FlutterRectMakeLTRB(2, 3, 800, 600),
516 };
517 FlutterRegion paint_region = {
518 .struct_size = sizeof(FlutterRegion),
519 .rects_count = 1,
520 .rects = paint_region_rects,
521 };
522 FlutterBackingStorePresentInfo present_info = {
524 .paint_region = &paint_region,
525 };
526
527 FlutterLayer layer = {};
528 layer.struct_size = sizeof(layer);
530 layer.backing_store = &backing_store;
531 layer.size = FlutterSizeMake(800.0, 600.0);
532 layer.offset = FlutterPointMake(0.0, 0.0);
533 layer.backing_store_present_info = &present_info;
534
535 ASSERT_EQ(*layers[2], layer);
536 }
537
538 latch.CountDown();
539 });
540
541 context.AddNativeCallback(
542 "SignalNativeTest",
544 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
545
546 auto engine = builder.LaunchEngine();
547
548 // Send a window metrics events so frames may be scheduled.
549 FlutterWindowMetricsEvent event = {};
550 event.struct_size = sizeof(event);
551 event.width = 800;
552 event.height = 600;
553 event.pixel_ratio = 1.0;
555 kSuccess);
556 ASSERT_TRUE(engine.is_valid());
557
558 latch.Wait();
559}
560
561//------------------------------------------------------------------------------
562/// Must be able to render using a custom compositor whose render target for the
563/// individual layers are software buffers.
564///
565TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) {
566 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
567
569 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
570 builder.SetCompositor();
571 builder.SetDartEntrypoint("can_composite_platform_views");
572
573 builder.SetRenderTargetType(
575
576 fml::CountDownLatch latch(3);
577 context.GetCompositor().SetNextPresentCallback(
578 [&](FlutterViewId view_id, const FlutterLayer** layers,
579 size_t layers_count) {
580 ASSERT_EQ(layers_count, 3u);
581
582 {
583 FlutterBackingStore backing_store = *layers[0]->backing_store;
584 backing_store.struct_size = sizeof(backing_store);
586 backing_store.did_update = true;
587 ASSERT_FLOAT_EQ(
588 backing_store.software.row_bytes * backing_store.software.height,
589 800 * 4 * 600.0);
590
591 FlutterRect paint_region_rects[] = {
592 FlutterRectMakeLTRB(0, 0, 800, 600),
593 };
594 FlutterRegion paint_region = {
595 .struct_size = sizeof(FlutterRegion),
596 .rects_count = 1,
597 .rects = paint_region_rects,
598 };
599 FlutterBackingStorePresentInfo present_info = {
601 .paint_region = &paint_region,
602 };
603
604 FlutterLayer layer = {};
605 layer.struct_size = sizeof(layer);
607 layer.backing_store = &backing_store;
608 layer.size = FlutterSizeMake(800.0, 600.0);
609 layer.offset = FlutterPointMake(0, 0);
610 layer.backing_store_present_info = &present_info;
611
612 ASSERT_EQ(*layers[0], layer);
613 }
614
615 {
617 platform_view.struct_size = sizeof(platform_view);
618 platform_view.identifier = 42;
619
620 FlutterLayer layer = {};
621 layer.struct_size = sizeof(layer);
624 layer.size = FlutterSizeMake(123.0, 456.0);
625 layer.offset = FlutterPointMake(1.0, 2.0);
626
627 ASSERT_EQ(*layers[1], layer);
628 }
629
630 {
631 FlutterBackingStore backing_store = *layers[2]->backing_store;
632 backing_store.struct_size = sizeof(backing_store);
634 backing_store.did_update = true;
635
636 FlutterRect paint_region_rects[] = {
637 FlutterRectMakeLTRB(2, 3, 800, 600),
638 };
639 FlutterRegion paint_region = {
640 .struct_size = sizeof(FlutterRegion),
641 .rects_count = 1,
642 .rects = paint_region_rects,
643 };
644 FlutterBackingStorePresentInfo present_info = {
646 .paint_region = &paint_region,
647 };
648
649 FlutterLayer layer = {};
650 layer.struct_size = sizeof(layer);
652 layer.backing_store = &backing_store;
653 layer.size = FlutterSizeMake(800.0, 600.0);
654 layer.offset = FlutterPointMake(0.0, 0.0);
655 layer.backing_store_present_info = &present_info;
656
657 ASSERT_EQ(*layers[2], layer);
658 }
659
660 latch.CountDown();
661 });
662
663 context.AddNativeCallback(
664 "SignalNativeTest",
666 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
667
668 auto engine = builder.LaunchEngine();
669
670 // Send a window metrics events so frames may be scheduled.
671 FlutterWindowMetricsEvent event = {};
672 event.struct_size = sizeof(event);
673 event.width = 800;
674 event.height = 600;
675 event.pixel_ratio = 1.0;
677 kSuccess);
678 ASSERT_TRUE(engine.is_valid());
679
680 latch.Wait();
681}
682
683//------------------------------------------------------------------------------
684/// Test the layer structure and pixels rendered when using a custom compositor.
685///
686TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) {
687 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
688
690 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
691 builder.SetCompositor();
692 builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
693
694 builder.SetRenderTargetType(
696
697 fml::CountDownLatch latch(5);
698
699 auto scene_image = context.GetNextSceneImage();
700
701 context.GetCompositor().SetNextPresentCallback(
702 [&](FlutterViewId view_id, const FlutterLayer** layers,
703 size_t layers_count) {
704 ASSERT_EQ(layers_count, 5u);
705
706 // Layer Root
707 {
708 FlutterBackingStore backing_store = *layers[0]->backing_store;
709 backing_store.type = kFlutterBackingStoreTypeOpenGL;
710 backing_store.did_update = true;
712
713 FlutterRect paint_region_rects[] = {
714 FlutterRectMakeLTRB(0, 0, 800, 600),
715 };
716 FlutterRegion paint_region = {
717 .struct_size = sizeof(FlutterRegion),
718 .rects_count = 1,
719 .rects = paint_region_rects,
720 };
721 FlutterBackingStorePresentInfo present_info = {
723 .paint_region = &paint_region,
724 };
725
726 FlutterLayer layer = {};
727 layer.struct_size = sizeof(layer);
729 layer.backing_store = &backing_store;
730 layer.size = FlutterSizeMake(800.0, 600.0);
731 layer.offset = FlutterPointMake(0.0, 0.0);
732 layer.backing_store_present_info = &present_info;
733
734 ASSERT_EQ(*layers[0], layer);
735 }
736
737 // Layer 1
738 {
740 platform_view.struct_size = sizeof(platform_view);
741 platform_view.identifier = 1;
742
743 FlutterLayer layer = {};
744 layer.struct_size = sizeof(layer);
747 layer.size = FlutterSizeMake(50.0, 150.0);
748 layer.offset = FlutterPointMake(20.0, 20.0);
749
750 ASSERT_EQ(*layers[1], layer);
751 }
752
753 // Layer 2
754 {
755 FlutterBackingStore backing_store = *layers[2]->backing_store;
756 backing_store.type = kFlutterBackingStoreTypeOpenGL;
757 backing_store.did_update = true;
759
760 FlutterRect paint_region_rects[] = {
761 FlutterRectMakeLTRB(30, 30, 80, 180),
762 };
763 FlutterRegion paint_region = {
764 .struct_size = sizeof(FlutterRegion),
765 .rects_count = 1,
766 .rects = paint_region_rects,
767 };
768 FlutterBackingStorePresentInfo present_info = {
770 .paint_region = &paint_region,
771 };
772
773 FlutterLayer layer = {};
774 layer.struct_size = sizeof(layer);
776 layer.backing_store = &backing_store;
777 layer.size = FlutterSizeMake(800.0, 600.0);
778 layer.offset = FlutterPointMake(0.0, 0.0);
779 layer.backing_store_present_info = &present_info;
780
781 ASSERT_EQ(*layers[2], layer);
782 }
783
784 // Layer 3
785 {
787 platform_view.struct_size = sizeof(platform_view);
788 platform_view.identifier = 2;
789
790 FlutterLayer layer = {};
791 layer.struct_size = sizeof(layer);
794 layer.size = FlutterSizeMake(50.0, 150.0);
795 layer.offset = FlutterPointMake(40.0, 40.0);
796
797 ASSERT_EQ(*layers[3], layer);
798 }
799
800 // Layer 4
801 {
802 FlutterBackingStore backing_store = *layers[4]->backing_store;
803 backing_store.type = kFlutterBackingStoreTypeOpenGL;
804 backing_store.did_update = true;
806
807 FlutterRect paint_region_rects[] = {
808 FlutterRectMakeLTRB(50, 50, 100, 200),
809 };
810 FlutterRegion paint_region = {
811 .struct_size = sizeof(FlutterRegion),
812 .rects_count = 1,
813 .rects = paint_region_rects,
814 };
815 FlutterBackingStorePresentInfo present_info = {
817 .paint_region = &paint_region,
818 };
819
820 FlutterLayer layer = {};
821 layer.struct_size = sizeof(layer);
823 layer.backing_store = &backing_store;
824 layer.size = FlutterSizeMake(800.0, 600.0);
825 layer.offset = FlutterPointMake(0.0, 0.0);
826 layer.backing_store_present_info = &present_info;
827
828 ASSERT_EQ(*layers[4], layer);
829 }
830
831 latch.CountDown();
832 });
833
834 context.GetCompositor().SetPlatformViewRendererCallback(
835 [&](const FlutterLayer& layer,
836 GrDirectContext* context) -> sk_sp<SkImage> {
837 auto surface = CreateRenderSurface(layer, context);
838 auto canvas = surface->getCanvas();
839 FML_CHECK(canvas != nullptr);
840
841 switch (layer.platform_view->identifier) {
842 case 1: {
844 // See dart test for total order.
845 paint.setColor(SK_ColorGREEN);
846 paint.setAlpha(127);
847 const auto& rect =
848 SkRect::MakeWH(layer.size.width, layer.size.height);
849 canvas->drawRect(rect, paint);
850 latch.CountDown();
851 } break;
852 case 2: {
854 // See dart test for total order.
855 paint.setColor(SK_ColorMAGENTA);
856 paint.setAlpha(127);
857 const auto& rect =
858 SkRect::MakeWH(layer.size.width, layer.size.height);
859 canvas->drawRect(rect, paint);
860 latch.CountDown();
861 } break;
862 default:
863 // Asked to render an unknown platform view.
864 FML_CHECK(false)
865 << "Test was asked to composite an unknown platform view.";
866 }
867
868 return surface->makeImageSnapshot();
869 });
870
871 context.AddNativeCallback(
872 "SignalNativeTest",
874 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
875
876 auto engine = builder.LaunchEngine();
877
878 // Send a window metrics events so frames may be scheduled.
879 FlutterWindowMetricsEvent event = {};
880 event.struct_size = sizeof(event);
881 event.width = 800;
882 event.height = 600;
883 event.pixel_ratio = 1.0;
885 kSuccess);
886 ASSERT_TRUE(engine.is_valid());
887
888 latch.Wait();
889
890 ASSERT_TRUE(ImageMatchesFixture("compositor.png", scene_image));
891
892 // There should no present calls on the root surface.
893 ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
894}
895
896//------------------------------------------------------------------------------
897/// Custom compositor must play nicely with a custom task runner. The raster
898/// thread merging mechanism must not interfere with the custom compositor.
899///
900TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) {
901 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
902
904
905 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
906 builder.SetCompositor();
907 builder.SetDartEntrypoint("can_composite_platform_views");
908
909 auto platform_task_runner = CreateNewThread("test_platform_thread");
910 static std::mutex engine_mutex;
913
914 EmbedderTestTaskRunner test_task_runner(
915 platform_task_runner, [&](FlutterTask task) {
916 std::scoped_lock lock(engine_mutex);
917 if (!engine.is_valid()) {
918 return;
919 }
920 ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
921 });
922
923 builder.SetRenderTargetType(
925
926 fml::CountDownLatch latch(3);
927 context.GetCompositor().SetNextPresentCallback(
928 [&](FlutterViewId view_id, const FlutterLayer** layers,
929 size_t layers_count) {
930 ASSERT_EQ(layers_count, 3u);
931
932 {
933 FlutterBackingStore backing_store = *layers[0]->backing_store;
934 backing_store.struct_size = sizeof(backing_store);
935 backing_store.type = kFlutterBackingStoreTypeOpenGL;
936 backing_store.did_update = true;
938
939 FlutterRect paint_region_rects[] = {
940 FlutterRectMakeLTRB(0, 0, 800, 600),
941 };
942 FlutterRegion paint_region = {
943 .struct_size = sizeof(FlutterRegion),
944 .rects_count = 1,
945 .rects = paint_region_rects,
946 };
947 FlutterBackingStorePresentInfo present_info = {
949 .paint_region = &paint_region,
950 };
951
952 FlutterLayer layer = {};
953 layer.struct_size = sizeof(layer);
955 layer.backing_store = &backing_store;
956 layer.size = FlutterSizeMake(800.0, 600.0);
957 layer.offset = FlutterPointMake(0, 0);
958 layer.backing_store_present_info = &present_info;
959
960 ASSERT_EQ(*layers[0], layer);
961 }
962
963 {
965 platform_view.struct_size = sizeof(platform_view);
966 platform_view.identifier = 42;
967
968 FlutterRect paint_region_rects[] = {
969 FlutterRectMakeLTRB(2, 3, 800, 600),
970 };
971 FlutterRegion paint_region = {
972 .struct_size = sizeof(FlutterRegion),
973 .rects_count = 1,
974 .rects = paint_region_rects,
975 };
976 FlutterBackingStorePresentInfo present_info = {
978 .paint_region = &paint_region,
979 };
980
981 FlutterLayer layer = {};
982 layer.struct_size = sizeof(layer);
985 layer.size = FlutterSizeMake(123.0, 456.0);
986 layer.offset = FlutterPointMake(1.0, 2.0);
987 layer.backing_store_present_info = &present_info;
988
989 ASSERT_EQ(*layers[1], layer);
990 }
991
992 {
993 FlutterBackingStore backing_store = *layers[2]->backing_store;
994 backing_store.struct_size = sizeof(backing_store);
995 backing_store.type = kFlutterBackingStoreTypeOpenGL;
996 backing_store.did_update = true;
998
999 FlutterRect paint_region_rects[] = {
1000 FlutterRectMakeLTRB(2, 3, 800, 600),
1001 };
1002 FlutterRegion paint_region = {
1003 .struct_size = sizeof(FlutterRegion),
1004 .rects_count = 1,
1005 .rects = paint_region_rects,
1006 };
1007 FlutterBackingStorePresentInfo present_info = {
1009 .paint_region = &paint_region,
1010 };
1011
1012 FlutterLayer layer = {};
1013 layer.struct_size = sizeof(layer);
1015 layer.backing_store = &backing_store;
1016 layer.size = FlutterSizeMake(800.0, 600.0);
1017 layer.offset = FlutterPointMake(0.0, 0.0);
1018 layer.backing_store_present_info = &present_info;
1019
1020 ASSERT_EQ(*layers[2], layer);
1021 }
1022
1023 latch.CountDown();
1024 });
1025
1026 const auto task_runner_description =
1027 test_task_runner.GetFlutterTaskRunnerDescription();
1028
1029 builder.SetPlatformTaskRunner(&task_runner_description);
1030
1031 context.AddNativeCallback(
1032 "SignalNativeTest",
1034 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1035
1036 platform_task_runner->PostTask([&]() {
1037 std::scoped_lock lock(engine_mutex);
1038 engine = builder.LaunchEngine();
1039 ASSERT_TRUE(engine.is_valid());
1040
1041 // Send a window metrics events so frames may be scheduled.
1042 FlutterWindowMetricsEvent event = {};
1043 event.struct_size = sizeof(event);
1044 event.width = 800;
1045 event.height = 600;
1046 event.pixel_ratio = 1.0;
1048 kSuccess);
1049 ASSERT_TRUE(engine.is_valid());
1050 sync_latch.Signal();
1051 });
1052 sync_latch.Wait();
1053
1054 latch.Wait();
1055
1056 platform_task_runner->PostTask([&]() {
1057 std::scoped_lock lock(engine_mutex);
1058 engine.reset();
1059 sync_latch.Signal();
1060 });
1061 sync_latch.Wait();
1062}
1063
1064//------------------------------------------------------------------------------
1065/// Test the layer structure and pixels rendered when using a custom compositor
1066/// and a single layer.
1067///
1068TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) {
1069 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1070
1072 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1073 builder.SetCompositor();
1074 builder.SetDartEntrypoint(
1075 "can_composite_platform_views_with_root_layer_only");
1076
1077 builder.SetRenderTargetType(
1079
1080 fml::CountDownLatch latch(3);
1081
1082 auto scene_image = context.GetNextSceneImage();
1083
1084 context.GetCompositor().SetNextPresentCallback(
1085 [&](FlutterViewId view_id, const FlutterLayer** layers,
1086 size_t layers_count) {
1087 ASSERT_EQ(layers_count, 1u);
1088
1089 // Layer Root
1090 {
1091 FlutterBackingStore backing_store = *layers[0]->backing_store;
1092 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1093 backing_store.did_update = true;
1095
1096 FlutterRect paint_region_rects[] = {
1097 FlutterRectMakeLTRB(0, 0, 800, 600),
1098 };
1099 FlutterRegion paint_region = {
1100 .struct_size = sizeof(FlutterRegion),
1101 .rects_count = 1,
1102 .rects = paint_region_rects,
1103 };
1104 FlutterBackingStorePresentInfo present_info = {
1106 .paint_region = &paint_region,
1107 };
1108
1109 FlutterLayer layer = {};
1110 layer.struct_size = sizeof(layer);
1112 layer.backing_store = &backing_store;
1113 layer.size = FlutterSizeMake(800.0, 600.0);
1114 layer.offset = FlutterPointMake(0.0, 0.0);
1115 layer.backing_store_present_info = &present_info;
1116
1117 ASSERT_EQ(*layers[0], layer);
1118 }
1119
1120 latch.CountDown();
1121 });
1122
1123 context.AddNativeCallback(
1124 "SignalNativeTest",
1126 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1127
1128 auto engine = builder.LaunchEngine();
1129
1130 // Send a window metrics events so frames may be scheduled.
1131 FlutterWindowMetricsEvent event = {};
1132 event.struct_size = sizeof(event);
1133 event.width = 800;
1134 event.height = 600;
1135 event.pixel_ratio = 1.0;
1137 kSuccess);
1138 ASSERT_TRUE(engine.is_valid());
1139
1140 latch.Wait();
1141
1142 ASSERT_TRUE(
1143 ImageMatchesFixture("compositor_with_root_layer_only.png", scene_image));
1144}
1145
1146//------------------------------------------------------------------------------
1147/// Test the layer structure and pixels rendered when using a custom compositor
1148/// and ensure that a redundant layer is not added.
1149///
1150TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) {
1151 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1152
1154 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1155 builder.SetCompositor();
1156 builder.SetDartEntrypoint(
1157 "can_composite_platform_views_with_platform_layer_on_bottom");
1158
1159 builder.SetRenderTargetType(
1161
1162 fml::CountDownLatch latch(3);
1163
1164 auto scene_image = context.GetNextSceneImage();
1165
1166 context.GetCompositor().SetNextPresentCallback(
1167 [&](FlutterViewId view_id, const FlutterLayer** layers,
1168 size_t layers_count) {
1169 ASSERT_EQ(layers_count, 2u);
1170
1171 // Layer Root
1172 {
1173 FlutterBackingStore backing_store = *layers[0]->backing_store;
1174 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1175 backing_store.did_update = true;
1177
1178 FlutterRect paint_region_rects[] = {
1179 FlutterRectMakeLTRB(0, 0, 800, 600),
1180 };
1181 FlutterRegion paint_region = {
1182 .struct_size = sizeof(FlutterRegion),
1183 .rects_count = 1,
1184 .rects = paint_region_rects,
1185 };
1186 FlutterBackingStorePresentInfo present_info = {
1188 .paint_region = &paint_region,
1189 };
1190
1191 FlutterLayer layer = {};
1192 layer.struct_size = sizeof(layer);
1194 layer.backing_store = &backing_store;
1195 layer.size = FlutterSizeMake(800.0, 600.0);
1196 layer.offset = FlutterPointMake(0.0, 0.0);
1197 layer.backing_store_present_info = &present_info;
1198
1199 ASSERT_EQ(*layers[0], layer);
1200 }
1201
1202 // Layer 1
1203 {
1205 platform_view.struct_size = sizeof(platform_view);
1206 platform_view.identifier = 1;
1207
1208 FlutterLayer layer = {};
1209 layer.struct_size = sizeof(layer);
1212 layer.size = FlutterSizeMake(50.0, 150.0);
1213 layer.offset = FlutterPointMake(20.0, 20.0);
1214
1215 ASSERT_EQ(*layers[1], layer);
1216 }
1217
1218 latch.CountDown();
1219 });
1220
1221 context.GetCompositor().SetPlatformViewRendererCallback(
1222 [&](const FlutterLayer& layer,
1223 GrDirectContext* context) -> sk_sp<SkImage> {
1224 auto surface = CreateRenderSurface(layer, context);
1225 auto canvas = surface->getCanvas();
1226 FML_CHECK(canvas != nullptr);
1227
1228 switch (layer.platform_view->identifier) {
1229 case 1: {
1230 SkPaint paint;
1231 // See dart test for total order.
1232 paint.setColor(SK_ColorGREEN);
1233 paint.setAlpha(127);
1234 const auto& rect =
1235 SkRect::MakeWH(layer.size.width, layer.size.height);
1236 canvas->drawRect(rect, paint);
1237 latch.CountDown();
1238 } break;
1239 default:
1240 // Asked to render an unknown platform view.
1241 FML_CHECK(false)
1242 << "Test was asked to composite an unknown platform view.";
1243 }
1244
1245 return surface->makeImageSnapshot();
1246 });
1247
1248 context.AddNativeCallback(
1249 "SignalNativeTest",
1251 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1252
1253 auto engine = builder.LaunchEngine();
1254
1255 // Send a window metrics events so frames may be scheduled.
1256 FlutterWindowMetricsEvent event = {};
1257 event.struct_size = sizeof(event);
1258 event.width = 800;
1259 event.height = 600;
1260 event.pixel_ratio = 1.0;
1262 kSuccess);
1263 ASSERT_TRUE(engine.is_valid());
1264
1265 latch.Wait();
1266
1267 ASSERT_TRUE(ImageMatchesFixture(
1268 "compositor_with_platform_layer_on_bottom.png", scene_image));
1269
1270 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 1u);
1271}
1272
1273//------------------------------------------------------------------------------
1274/// Test the layer structure and pixels rendered when using a custom compositor
1275/// with a root surface transformation.
1276///
1278 CompositorMustBeAbleToRenderKnownSceneWithRootSurfaceTransformation) {
1279 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1280
1282 builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1283 builder.SetCompositor();
1284 builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
1285
1286 builder.SetRenderTargetType(
1288
1289 // This must match the transformation provided in the
1290 // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1291 // transforms are consistent respected.
1292 const auto root_surface_transformation =
1293 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1294
1295 context.SetRootSurfaceTransformation(root_surface_transformation);
1296
1297 fml::CountDownLatch latch(5);
1298
1299 auto scene_image = context.GetNextSceneImage();
1300
1301 context.GetCompositor().SetNextPresentCallback(
1302 [&](FlutterViewId view_id, const FlutterLayer** layers,
1303 size_t layers_count) {
1304 ASSERT_EQ(layers_count, 5u);
1305
1306 // Layer Root
1307 {
1308 FlutterBackingStore backing_store = *layers[0]->backing_store;
1309 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1310 backing_store.did_update = true;
1312
1313 FlutterRect paint_region_rects[] = {
1314 FlutterRectMakeLTRB(0, 0, 600, 800),
1315 };
1316 FlutterRegion paint_region = {
1317 .struct_size = sizeof(FlutterRegion),
1318 .rects_count = 1,
1319 .rects = paint_region_rects,
1320 };
1321 FlutterBackingStorePresentInfo present_info = {
1323 .paint_region = &paint_region,
1324 };
1325
1326 FlutterLayer layer = {};
1327 layer.struct_size = sizeof(layer);
1329 layer.backing_store = &backing_store;
1330 layer.size = FlutterSizeMake(600.0, 800.0);
1331 layer.offset = FlutterPointMake(0.0, 0.0);
1332 layer.backing_store_present_info = &present_info;
1333
1334 ASSERT_EQ(*layers[0], layer);
1335 }
1336
1337 // Layer 1
1338 {
1340 platform_view.struct_size = sizeof(platform_view);
1341 platform_view.identifier = 1;
1342
1343 FlutterLayer layer = {};
1344 layer.struct_size = sizeof(layer);
1347 layer.size = FlutterSizeMake(150.0, 50.0);
1348 layer.offset = FlutterPointMake(20.0, 730.0);
1349
1350 ASSERT_EQ(*layers[1], layer);
1351 }
1352
1353 // Layer 2
1354 {
1355 FlutterBackingStore backing_store = *layers[2]->backing_store;
1356 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1357 backing_store.did_update = true;
1359
1360 FlutterRect paint_region_rects[] = {
1361 FlutterRectMakeLTRB(30, 720, 180, 770),
1362 };
1363 FlutterRegion paint_region = {
1364 .struct_size = sizeof(FlutterRegion),
1365 .rects_count = 1,
1366 .rects = paint_region_rects,
1367 };
1368 FlutterBackingStorePresentInfo present_info = {
1370 .paint_region = &paint_region,
1371 };
1372
1373 FlutterLayer layer = {};
1374 layer.struct_size = sizeof(layer);
1376 layer.backing_store = &backing_store;
1377 layer.size = FlutterSizeMake(600.0, 800.0);
1378 layer.offset = FlutterPointMake(0.0, 0.0);
1379 layer.backing_store_present_info = &present_info;
1380
1381 ASSERT_EQ(*layers[2], layer);
1382 }
1383
1384 // Layer 3
1385 {
1387 platform_view.struct_size = sizeof(platform_view);
1388 platform_view.identifier = 2;
1389
1390 FlutterLayer layer = {};
1391 layer.struct_size = sizeof(layer);
1394 layer.size = FlutterSizeMake(150.0, 50.0);
1395 layer.offset = FlutterPointMake(40.0, 710.0);
1396
1397 ASSERT_EQ(*layers[3], layer);
1398 }
1399
1400 // Layer 4
1401 {
1402 FlutterBackingStore backing_store = *layers[4]->backing_store;
1403 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1404 backing_store.did_update = true;
1406
1407 FlutterRect paint_region_rects[] = {
1408 FlutterRectMakeLTRB(50, 700, 200, 750),
1409 };
1410 FlutterRegion paint_region = {
1411 .struct_size = sizeof(FlutterRegion),
1412 .rects_count = 1,
1413 .rects = paint_region_rects,
1414 };
1415 FlutterBackingStorePresentInfo present_info = {
1417 .paint_region = &paint_region,
1418 };
1419
1420 FlutterLayer layer = {};
1421 layer.struct_size = sizeof(layer);
1423 layer.backing_store = &backing_store;
1424 layer.size = FlutterSizeMake(600.0, 800.0);
1425 layer.offset = FlutterPointMake(0.0, 0.0);
1426 layer.backing_store_present_info = &present_info;
1427
1428 ASSERT_EQ(*layers[4], layer);
1429 }
1430
1431 latch.CountDown();
1432 });
1433
1434 context.GetCompositor().SetPlatformViewRendererCallback(
1435 [&](const FlutterLayer& layer,
1436 GrDirectContext* context) -> sk_sp<SkImage> {
1437 auto surface = CreateRenderSurface(layer, context);
1438 auto canvas = surface->getCanvas();
1439 FML_CHECK(canvas != nullptr);
1440
1441 switch (layer.platform_view->identifier) {
1442 case 1: {
1443 SkPaint paint;
1444 // See dart test for total order.
1445 paint.setColor(SK_ColorGREEN);
1446 paint.setAlpha(127);
1447 const auto& rect =
1448 SkRect::MakeWH(layer.size.width, layer.size.height);
1449 canvas->drawRect(rect, paint);
1450 latch.CountDown();
1451 } break;
1452 case 2: {
1453 SkPaint paint;
1454 // See dart test for total order.
1455 paint.setColor(SK_ColorMAGENTA);
1456 paint.setAlpha(127);
1457 const auto& rect =
1458 SkRect::MakeWH(layer.size.width, layer.size.height);
1459 canvas->drawRect(rect, paint);
1460 latch.CountDown();
1461 } break;
1462 default:
1463 // Asked to render an unknown platform view.
1464 FML_CHECK(false)
1465 << "Test was asked to composite an unknown platform view.";
1466 }
1467
1468 return surface->makeImageSnapshot();
1469 });
1470
1471 context.AddNativeCallback(
1472 "SignalNativeTest",
1474 [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1475
1476 auto engine = builder.LaunchEngine();
1477
1478 // Send a window metrics events so frames may be scheduled.
1479 FlutterWindowMetricsEvent event = {};
1480 event.struct_size = sizeof(event);
1481 // Flutter still thinks it is 800 x 600. Only the root surface is rotated.
1482 event.width = 800;
1483 event.height = 600;
1484 event.pixel_ratio = 1.0;
1486 kSuccess);
1487 ASSERT_TRUE(engine.is_valid());
1488
1489 latch.Wait();
1490
1491 ASSERT_TRUE(ImageMatchesFixture("compositor_root_surface_xformation.png",
1492 scene_image));
1493}
1494
1495TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositor) {
1496 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1497
1499
1500 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1501 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1502
1503 auto rendered_scene = context.GetNextSceneImage();
1504
1505 auto engine = builder.LaunchEngine();
1506 ASSERT_TRUE(engine.is_valid());
1507
1508 // Send a window metrics events so frames may be scheduled.
1509 FlutterWindowMetricsEvent event = {};
1510 event.struct_size = sizeof(event);
1511 event.width = 800;
1512 event.height = 600;
1513 event.pixel_ratio = 1.0;
1515 kSuccess);
1516
1517 ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png",
1518 rendered_scene));
1519}
1520
1521TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositorWithTransformation) {
1522 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1523
1524 const auto root_surface_transformation =
1525 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1526
1527 context.SetRootSurfaceTransformation(root_surface_transformation);
1528
1530
1531 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1532 builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1533
1534 auto rendered_scene = context.GetNextSceneImage();
1535
1536 auto engine = builder.LaunchEngine();
1537 ASSERT_TRUE(engine.is_valid());
1538
1539 // Send a window metrics events so frames may be scheduled.
1540 FlutterWindowMetricsEvent event = {};
1541 event.struct_size = sizeof(event);
1542
1543 // Flutter still thinks it is 800 x 600.
1544 event.width = 800;
1545 event.height = 600;
1546 event.pixel_ratio = 1.0;
1548 kSuccess);
1549
1550 ASSERT_TRUE(ImageMatchesFixture(
1551 "scene_without_custom_compositor_with_xform.png", rendered_scene));
1552}
1553
1554TEST_P(EmbedderTestMultiBackend, CanRenderGradientWithoutCompositor) {
1555 EmbedderTestContextType backend = GetParam();
1556 auto& context = GetEmbedderContext(backend);
1557
1559
1560 builder.SetDartEntrypoint("render_gradient");
1561 builder.SetRendererConfig(backend, SkISize::Make(800, 600));
1562
1563 auto rendered_scene = context.GetNextSceneImage();
1564
1565 auto engine = builder.LaunchEngine();
1566 ASSERT_TRUE(engine.is_valid());
1567
1568 // Send a window metrics events so frames may be scheduled.
1569 FlutterWindowMetricsEvent event = {};
1570 event.struct_size = sizeof(event);
1571 event.width = 800;
1572 event.height = 600;
1573 event.pixel_ratio = 1.0;
1575 kSuccess);
1576
1577 ASSERT_TRUE(ImageMatchesFixture(
1578 FixtureNameForBackend(backend, "gradient.png"), rendered_scene));
1579}
1580
1581TEST_F(EmbedderTest, CanRenderGradientWithoutCompositorWithXform) {
1582 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1583
1584 const auto root_surface_transformation =
1585 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1586
1587 context.SetRootSurfaceTransformation(root_surface_transformation);
1588
1590
1591 const auto surface_size = SkISize::Make(600, 800);
1592
1593 builder.SetDartEntrypoint("render_gradient");
1594 builder.SetOpenGLRendererConfig(surface_size);
1595
1596 auto rendered_scene = context.GetNextSceneImage();
1597
1598 auto engine = builder.LaunchEngine();
1599 ASSERT_TRUE(engine.is_valid());
1600
1601 // Send a window metrics events so frames may be scheduled.
1602 FlutterWindowMetricsEvent event = {};
1603 event.struct_size = sizeof(event);
1604 // Flutter still thinks it is 800 x 600.
1605 event.width = 800;
1606 event.height = 600;
1607 event.pixel_ratio = 1.0;
1609 kSuccess);
1610
1611 ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1612}
1613
1614TEST_P(EmbedderTestMultiBackend, CanRenderGradientWithCompositor) {
1615 EmbedderTestContextType backend = GetParam();
1616 auto& context = GetEmbedderContext(backend);
1617
1619
1620 builder.SetDartEntrypoint("render_gradient");
1621 builder.SetRendererConfig(backend, SkISize::Make(800, 600));
1622 builder.SetCompositor();
1623 builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, true));
1624
1625 auto rendered_scene = context.GetNextSceneImage();
1626
1627 auto engine = builder.LaunchEngine();
1628 ASSERT_TRUE(engine.is_valid());
1629
1630 // Send a window metrics events so frames may be scheduled.
1631 FlutterWindowMetricsEvent event = {};
1632 event.struct_size = sizeof(event);
1633 event.width = 800;
1634 event.height = 600;
1635 event.pixel_ratio = 1.0;
1637 kSuccess);
1638
1639 ASSERT_TRUE(ImageMatchesFixture(
1640 FixtureNameForBackend(backend, "gradient.png"), rendered_scene));
1641}
1642
1643TEST_F(EmbedderTest, CanRenderGradientWithCompositorWithXform) {
1644 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1645
1646 // This must match the transformation provided in the
1647 // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1648 // transforms are consistent respected.
1649 const auto root_surface_transformation =
1650 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1651
1652 context.SetRootSurfaceTransformation(root_surface_transformation);
1653
1655
1656 builder.SetDartEntrypoint("render_gradient");
1657 builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1658 builder.SetCompositor();
1659 builder.SetRenderTargetType(
1661
1662 auto rendered_scene = context.GetNextSceneImage();
1663
1664 auto engine = builder.LaunchEngine();
1665 ASSERT_TRUE(engine.is_valid());
1666
1667 // Send a window metrics events so frames may be scheduled.
1668 FlutterWindowMetricsEvent event = {};
1669 event.struct_size = sizeof(event);
1670 // Flutter still thinks it is 800 x 600.
1671 event.width = 800;
1672 event.height = 600;
1673 event.pixel_ratio = 1.0;
1675 kSuccess);
1676
1677 ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1678}
1679
1681 CanRenderGradientWithCompositorOnNonRootLayer) {
1682 EmbedderTestContextType backend = GetParam();
1683 auto& context = GetEmbedderContext(backend);
1684
1686
1687 builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1688 builder.SetRendererConfig(backend, SkISize::Make(800, 600));
1689 builder.SetCompositor();
1690 builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, true));
1691
1692 context.GetCompositor().SetNextPresentCallback(
1693 [&](FlutterViewId view_id, const FlutterLayer** layers,
1694 size_t layers_count) {
1695 ASSERT_EQ(layers_count, 3u);
1696
1697 // Layer Root
1698 {
1699 FlutterBackingStore backing_store = *layers[0]->backing_store;
1700 backing_store.did_update = true;
1701 ConfigureBackingStore(backing_store, backend, true);
1702
1703 FlutterRect paint_region_rects[] = {
1704 FlutterRectMakeLTRB(0, 0, 800, 600),
1705 };
1706 FlutterRegion paint_region = {
1707 .struct_size = sizeof(FlutterRegion),
1708 .rects_count = 1,
1709 .rects = paint_region_rects,
1710 };
1711 FlutterBackingStorePresentInfo present_info = {
1713 .paint_region = &paint_region,
1714 };
1715
1716 FlutterLayer layer = {};
1717 layer.struct_size = sizeof(layer);
1719 layer.backing_store = &backing_store;
1720 layer.size = FlutterSizeMake(800.0, 600.0);
1721 layer.offset = FlutterPointMake(0.0, 0.0);
1722 layer.backing_store_present_info = &present_info;
1723
1724 ASSERT_EQ(*layers[0], layer);
1725 }
1726
1727 // Layer 1
1728 {
1730 platform_view.struct_size = sizeof(platform_view);
1731 platform_view.identifier = 1;
1732
1733 FlutterLayer layer = {};
1734 layer.struct_size = sizeof(layer);
1737 layer.size = FlutterSizeMake(100.0, 200.0);
1738 layer.offset = FlutterPointMake(0.0, 0.0);
1739
1740 ASSERT_EQ(*layers[1], layer);
1741 }
1742
1743 // Layer 2
1744 {
1745 FlutterBackingStore backing_store = *layers[2]->backing_store;
1746 backing_store.did_update = true;
1747 ConfigureBackingStore(backing_store, backend, true);
1748
1749 FlutterRect paint_region_rects[] = {
1750 FlutterRectMakeLTRB(0, 0, 800, 600),
1751 };
1752 FlutterRegion paint_region = {
1753 .struct_size = sizeof(FlutterRegion),
1754 .rects_count = 1,
1755 .rects = paint_region_rects,
1756 };
1757 FlutterBackingStorePresentInfo present_info = {
1759 .paint_region = &paint_region,
1760 };
1761
1762 FlutterLayer layer = {};
1763 layer.struct_size = sizeof(layer);
1765 layer.backing_store = &backing_store;
1766 layer.size = FlutterSizeMake(800.0, 600.0);
1767 layer.offset = FlutterPointMake(0.0, 0.0);
1768 layer.backing_store_present_info = &present_info;
1769
1770 ASSERT_EQ(*layers[2], layer);
1771 }
1772 });
1773
1774 context.GetCompositor().SetPlatformViewRendererCallback(
1775 [&](const FlutterLayer& layer,
1776 GrDirectContext* context) -> sk_sp<SkImage> {
1777 auto surface = CreateRenderSurface(layer, context);
1778 auto canvas = surface->getCanvas();
1779 FML_CHECK(canvas != nullptr);
1780
1781 switch (layer.platform_view->identifier) {
1782 case 1: {
1783 FML_CHECK(layer.size.width == 100);
1784 FML_CHECK(layer.size.height == 200);
1785 // This is occluded anyway. We just want to make sure we see this.
1786 } break;
1787 default:
1788 // Asked to render an unknown platform view.
1789 FML_CHECK(false)
1790 << "Test was asked to composite an unknown platform view.";
1791 }
1792
1793 return surface->makeImageSnapshot();
1794 });
1795
1796 auto rendered_scene = context.GetNextSceneImage();
1797
1798 auto engine = builder.LaunchEngine();
1799 ASSERT_TRUE(engine.is_valid());
1800
1801 // Send a window metrics events so frames may be scheduled.
1802 FlutterWindowMetricsEvent event = {};
1803 event.struct_size = sizeof(event);
1804 event.width = 800;
1805 event.height = 600;
1806 event.pixel_ratio = 1.0;
1808 kSuccess);
1809
1810 ASSERT_TRUE(ImageMatchesFixture(
1811 FixtureNameForBackend(backend, "gradient.png"), rendered_scene));
1812}
1813
1814TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) {
1815 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1816
1817 // This must match the transformation provided in the
1818 // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1819 // transforms are consistent respected.
1820 const auto root_surface_transformation =
1821 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1822
1823 context.SetRootSurfaceTransformation(root_surface_transformation);
1824
1826
1827 builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1828 builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1829 builder.SetCompositor();
1830 builder.SetRenderTargetType(
1832
1833 context.GetCompositor().SetNextPresentCallback(
1834 [&](FlutterViewId view_id, const FlutterLayer** layers,
1835 size_t layers_count) {
1836 ASSERT_EQ(layers_count, 3u);
1837
1838 // Layer Root
1839 {
1840 FlutterBackingStore backing_store = *layers[0]->backing_store;
1841 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1842 backing_store.did_update = true;
1844
1845 FlutterRect paint_region_rects[] = {
1846 FlutterRectMakeLTRB(0, 0, 600, 800),
1847 };
1848 FlutterRegion paint_region = {
1849 .struct_size = sizeof(FlutterRegion),
1850 .rects_count = 1,
1851 .rects = paint_region_rects,
1852 };
1853 FlutterBackingStorePresentInfo present_info = {
1855 .paint_region = &paint_region,
1856 };
1857
1858 FlutterLayer layer = {};
1859 layer.struct_size = sizeof(layer);
1861 layer.backing_store = &backing_store;
1862 layer.size = FlutterSizeMake(600.0, 800.0);
1863 layer.offset = FlutterPointMake(0.0, 0.0);
1864 layer.backing_store_present_info = &present_info;
1865
1866 ASSERT_EQ(*layers[0], layer);
1867 }
1868
1869 // Layer 1
1870 {
1872 platform_view.struct_size = sizeof(platform_view);
1873 platform_view.identifier = 1;
1874
1875 FlutterLayer layer = {};
1876 layer.struct_size = sizeof(layer);
1879 layer.size = FlutterSizeMake(200.0, 100.0);
1880 layer.offset = FlutterPointMake(0.0, 700.0);
1881
1882 ASSERT_EQ(*layers[1], layer);
1883 }
1884
1885 // Layer 2
1886 {
1887 FlutterBackingStore backing_store = *layers[2]->backing_store;
1888 backing_store.type = kFlutterBackingStoreTypeOpenGL;
1889 backing_store.did_update = true;
1891
1892 FlutterRect paint_region_rects[] = {
1893 FlutterRectMakeLTRB(0, 0, 600, 800),
1894 };
1895 FlutterRegion paint_region = {
1896 .struct_size = sizeof(FlutterRegion),
1897 .rects_count = 1,
1898 .rects = paint_region_rects,
1899 };
1900 FlutterBackingStorePresentInfo present_info = {
1902 .paint_region = &paint_region,
1903 };
1904
1905 FlutterLayer layer = {};
1906 layer.struct_size = sizeof(layer);
1908 layer.backing_store = &backing_store;
1909 layer.size = FlutterSizeMake(600.0, 800.0);
1910 layer.offset = FlutterPointMake(0.0, 0.0);
1911 layer.backing_store_present_info = &present_info;
1912
1913 ASSERT_EQ(*layers[2], layer);
1914 }
1915 });
1916
1917 context.GetCompositor().SetPlatformViewRendererCallback(
1918 [&](const FlutterLayer& layer,
1919 GrDirectContext* context) -> sk_sp<SkImage> {
1920 auto surface = CreateRenderSurface(layer, context);
1921 auto canvas = surface->getCanvas();
1922 FML_CHECK(canvas != nullptr);
1923
1924 switch (layer.platform_view->identifier) {
1925 case 1: {
1926 FML_CHECK(layer.size.width == 200);
1927 FML_CHECK(layer.size.height == 100);
1928 // This is occluded anyway. We just want to make sure we see this.
1929 } break;
1930 default:
1931 // Asked to render an unknown platform view.
1932 FML_CHECK(false)
1933 << "Test was asked to composite an unknown platform view.";
1934 }
1935
1936 return surface->makeImageSnapshot();
1937 });
1938
1939 auto rendered_scene = context.GetNextSceneImage();
1940
1941 auto engine = builder.LaunchEngine();
1942 ASSERT_TRUE(engine.is_valid());
1943
1944 // Send a window metrics events so frames may be scheduled.
1945 FlutterWindowMetricsEvent event = {};
1946 event.struct_size = sizeof(event);
1947 // Flutter still thinks it is 800 x 600.
1948 event.width = 800;
1949 event.height = 600;
1950 event.pixel_ratio = 1.0;
1952 kSuccess);
1953
1954 ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1955}
1956
1957TEST_F(EmbedderTest, VerifyB141980393) {
1958 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1959
1961
1962 // The Flutter application is 800 x 600 but rendering on a surface that is 600
1963 // x 800 achieved using a root surface transformation.
1964 const auto root_surface_transformation =
1965 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1966 const auto flutter_application_rect = SkRect::MakeWH(800, 600);
1967 const auto root_surface_rect =
1968 root_surface_transformation.mapRect(flutter_application_rect);
1969
1970 ASSERT_DOUBLE_EQ(root_surface_rect.width(), 600.0);
1971 ASSERT_DOUBLE_EQ(root_surface_rect.height(), 800.0);
1972
1973 // Configure the fixture for the surface transformation.
1974 context.SetRootSurfaceTransformation(root_surface_transformation);
1975
1976 // Configure the Flutter project args for the root surface transformation.
1977 builder.SetOpenGLRendererConfig(
1978 SkISize::Make(root_surface_rect.width(), root_surface_rect.height()));
1979
1980 // Use a compositor instead of rendering directly to the surface.
1981 builder.SetCompositor();
1982 builder.SetRenderTargetType(
1984
1985 builder.SetDartEntrypoint("verify_b141980393");
1986
1988
1989 context.GetCompositor().SetNextPresentCallback(
1990 [&](FlutterViewId view_id, const FlutterLayer** layers,
1991 size_t layers_count) {
1992 ASSERT_EQ(layers_count, 1u);
1993
1994 // Layer Root
1995 {
1997 platform_view.struct_size = sizeof(platform_view);
1998 platform_view.identifier = 1337;
1999
2000 FlutterLayer layer = {};
2001 layer.struct_size = sizeof(layer);
2004
2005 // From the Dart side. These dimensions match those specified in Dart
2006 // code and are free of root surface transformations.
2007 const double unxformed_top_margin = 31.0;
2008 const double unxformed_bottom_margin = 37.0;
2009 const auto unxformed_platform_view_rect = SkRect::MakeXYWH(
2010 0.0, // x
2011 unxformed_top_margin, // y (top margin)
2012 800, // width
2013 600 - unxformed_top_margin - unxformed_bottom_margin // height
2014 );
2015
2016 // The platform views are in the coordinate space of the root surface
2017 // with top-left origin. The embedder has specified a transformation
2018 // to this surface which it must account for in the coordinates it
2019 // receives here.
2020 const auto xformed_platform_view_rect =
2021 root_surface_transformation.mapRect(unxformed_platform_view_rect);
2022
2023 // Spell out the value that we are going to be checking below for
2024 // clarity.
2025 ASSERT_EQ(xformed_platform_view_rect,
2026 SkRect::MakeXYWH(31.0, // x
2027 0.0, // y
2028 532.0, // width
2029 800.0 // height
2030 ));
2031
2032 // Verify that the engine is giving us the right size and offset.
2033 layer.offset = FlutterPointMake(xformed_platform_view_rect.x(),
2034 xformed_platform_view_rect.y());
2035 layer.size = FlutterSizeMake(xformed_platform_view_rect.width(),
2036 xformed_platform_view_rect.height());
2037
2038 ASSERT_EQ(*layers[0], layer);
2039 }
2040
2041 latch.Signal();
2042 });
2043
2044 auto engine = builder.LaunchEngine();
2045
2046 // Send a window metrics events so frames may be scheduled.
2047 FlutterWindowMetricsEvent event = {};
2048 event.struct_size = sizeof(event);
2049
2050 // The Flutter application is 800 x 600 rendering on a surface 600 x 800
2051 // achieved via a root surface transformation.
2052 event.width = flutter_application_rect.width();
2053 event.height = flutter_application_rect.height();
2054 event.pixel_ratio = 1.0;
2056 kSuccess);
2057 ASSERT_TRUE(engine.is_valid());
2058
2059 latch.Wait();
2060}
2061
2062//------------------------------------------------------------------------------
2063/// Asserts that embedders can provide a task runner for the render thread.
2064///
2065TEST_F(EmbedderTest, CanCreateEmbedderWithCustomRenderTaskRunner) {
2066 std::mutex engine_mutex;
2068 fml::AutoResetWaitableEvent task_latch;
2069 bool task_executed = false;
2070 EmbedderTestTaskRunner render_task_runner(
2071 CreateNewThread("custom_render_thread"), [&](FlutterTask task) {
2072 std::scoped_lock engine_lock(engine_mutex);
2073 if (engine.is_valid()) {
2074 ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
2075 task_executed = true;
2076 task_latch.Signal();
2077 }
2078 });
2080 GetEmbedderContext(EmbedderTestContextType::kOpenGLContext));
2081 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
2082 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2083 builder.SetRenderTaskRunner(
2084 &render_task_runner.GetFlutterTaskRunnerDescription());
2085
2086 {
2087 std::scoped_lock lock(engine_mutex);
2088 engine = builder.InitializeEngine();
2089 }
2090
2091 ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
2092
2093 ASSERT_TRUE(engine.is_valid());
2094
2095 FlutterWindowMetricsEvent event = {};
2096 event.struct_size = sizeof(event);
2097 event.width = 800;
2098 event.height = 600;
2099 event.pixel_ratio = 1.0;
2101 kSuccess);
2102 task_latch.Wait();
2103 ASSERT_TRUE(task_executed);
2104 ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
2105
2106 {
2107 std::scoped_lock engine_lock(engine_mutex);
2108 engine.reset();
2109 }
2110}
2111
2112//------------------------------------------------------------------------------
2113/// Asserts that the render task runner can be the same as the platform task
2114/// runner.
2115///
2117 CanCreateEmbedderWithCustomRenderTaskRunnerTheSameAsPlatformTaskRunner) {
2118 // A new thread needs to be created for the platform thread because the test
2119 // can't wait for assertions to be completed on the same thread that services
2120 // platform task runner tasks.
2121 auto platform_task_runner = CreateNewThread("platform_thread");
2122
2123 static std::mutex engine_mutex;
2124 static UniqueEngine engine;
2125 fml::AutoResetWaitableEvent task_latch;
2126 bool task_executed = false;
2127 EmbedderTestTaskRunner common_task_runner(
2128 platform_task_runner, [&](FlutterTask task) {
2129 std::scoped_lock engine_lock(engine_mutex);
2130 if (engine.is_valid()) {
2131 ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
2132 task_executed = true;
2133 task_latch.Signal();
2134 }
2135 });
2136
2137 platform_task_runner->PostTask([&]() {
2138 EmbedderTestContextType backend = GetParam();
2139 EmbedderConfigBuilder builder(GetEmbedderContext(backend));
2140 builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
2141 builder.SetRendererConfig(backend, SkISize::Make(800, 600));
2142 builder.SetRenderTaskRunner(
2143 &common_task_runner.GetFlutterTaskRunnerDescription());
2144 builder.SetPlatformTaskRunner(
2145 &common_task_runner.GetFlutterTaskRunnerDescription());
2146
2147 {
2148 std::scoped_lock lock(engine_mutex);
2149 engine = builder.InitializeEngine();
2150 }
2151
2152 ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
2153
2154 ASSERT_TRUE(engine.is_valid());
2155
2156 FlutterWindowMetricsEvent event = {};
2157 event.struct_size = sizeof(event);
2158 event.width = 800;
2159 event.height = 600;
2160 event.pixel_ratio = 1.0;
2162 kSuccess);
2163 });
2164
2165 task_latch.Wait();
2166
2167 // Don't use the task latch because that may be called multiple time
2168 // (including during the shutdown process).
2169 fml::AutoResetWaitableEvent shutdown_latch;
2170
2171 platform_task_runner->PostTask([&]() {
2172 ASSERT_TRUE(task_executed);
2173 ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
2174
2175 {
2176 std::scoped_lock engine_lock(engine_mutex);
2177 engine.reset();
2178 }
2179 shutdown_latch.Signal();
2180 });
2181
2182 shutdown_latch.Wait();
2183
2184 {
2185 std::scoped_lock engine_lock(engine_mutex);
2186 // Engine should have been killed by this point.
2187 ASSERT_FALSE(engine.is_valid());
2188 }
2189}
2190
2192 CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurface) {
2193 EmbedderTestContextType backend = GetParam();
2194 auto& context = GetEmbedderContext(backend);
2195
2197 builder.SetRendererConfig(backend, SkISize::Make(800, 600));
2198 builder.SetCompositor();
2199 builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
2200
2201 builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, false));
2202
2203 fml::CountDownLatch latch(1);
2204
2205 auto rendered_scene = context.GetNextSceneImage();
2206
2207 context.GetCompositor().SetNextPresentCallback(
2208 [&](FlutterViewId view_id, const FlutterLayer** layers,
2209 size_t layers_count) {
2210 ASSERT_EQ(layers_count, 3u);
2211
2212 // Layer 0 (Root)
2213 {
2214 FlutterBackingStore backing_store = *layers[0]->backing_store;
2215 backing_store.did_update = true;
2216 ConfigureBackingStore(backing_store, backend, false);
2217
2218 FlutterRect paint_region_rects[] = {
2219 FlutterRectMakeLTRB(0, 0, 800, 600),
2220 };
2221 FlutterRegion paint_region = {
2222 .struct_size = sizeof(FlutterRegion),
2223 .rects_count = 1,
2224 .rects = paint_region_rects,
2225 };
2226 FlutterBackingStorePresentInfo present_info = {
2228 .paint_region = &paint_region,
2229 };
2230
2231 FlutterLayer layer = {};
2232 layer.struct_size = sizeof(layer);
2234 layer.backing_store = &backing_store;
2235 layer.size = FlutterSizeMake(800.0, 600.0);
2236 layer.offset = FlutterPointMake(0.0, 0.0);
2237 layer.backing_store_present_info = &present_info;
2238
2239 ASSERT_EQ(*layers[0], layer);
2240 }
2241
2242 // Layer 1
2243 {
2245 platform_view.struct_size = sizeof(platform_view);
2246 platform_view.identifier = 42;
2247
2248 FlutterLayer layer = {};
2249 layer.struct_size = sizeof(layer);
2252 layer.size = FlutterSizeMake(800.0, 560.0);
2253 layer.offset = FlutterPointMake(0.0, 40.0);
2254
2255 ASSERT_EQ(*layers[1], layer);
2256 }
2257
2258 // Layer 2
2259 {
2260 FlutterBackingStore backing_store = *layers[2]->backing_store;
2261 backing_store.did_update = true;
2262 ConfigureBackingStore(backing_store, backend, false);
2263
2264 FlutterRect paint_region_rects[] = {
2265 FlutterRectMakeLTRB(0, 0, 800, 600),
2266 };
2267 FlutterRegion paint_region = {
2268 .struct_size = sizeof(FlutterRegion),
2269 .rects_count = 1,
2270 .rects = paint_region_rects,
2271 };
2272 FlutterBackingStorePresentInfo present_info = {
2274 .paint_region = &paint_region,
2275 };
2276
2277 FlutterLayer layer = {};
2278 layer.struct_size = sizeof(layer);
2280 layer.backing_store = &backing_store;
2281 layer.size = FlutterSizeMake(800.0, 600.0);
2282 layer.offset = FlutterPointMake(0.0, 0.0);
2283 layer.backing_store_present_info = &present_info;
2284
2285 ASSERT_EQ(*layers[2], layer);
2286 }
2287
2288 latch.CountDown();
2289 });
2290
2291 auto engine = builder.LaunchEngine();
2292
2293 // Send a window metrics events so frames may be scheduled.
2294 FlutterWindowMetricsEvent event = {};
2295 event.struct_size = sizeof(event);
2296 event.width = 400 * 2.0;
2297 event.height = 300 * 2.0;
2298 event.pixel_ratio = 2.0;
2300 kSuccess);
2301 ASSERT_TRUE(engine.is_valid());
2302
2303 latch.Wait();
2304
2305 ASSERT_TRUE(ImageMatchesFixture(
2306 FixtureNameForBackend(backend, "dpr_noxform.png"), rendered_scene));
2307}
2308
2311 CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurfaceWithRootSurfaceXformation) {
2312 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2313
2315 builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
2316 builder.SetCompositor();
2317 builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
2318
2319 builder.SetRenderTargetType(
2321
2322 const auto root_surface_transformation =
2323 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
2324
2325 context.SetRootSurfaceTransformation(root_surface_transformation);
2326
2327 auto rendered_scene = context.GetNextSceneImage();
2328 fml::CountDownLatch latch(1);
2329
2330 context.GetCompositor().SetNextPresentCallback(
2331 [&](FlutterViewId view_id, const FlutterLayer** layers,
2332 size_t layers_count) {
2333 ASSERT_EQ(layers_count, 3u);
2334
2335 // Layer 0 (Root)
2336 {
2337 FlutterBackingStore backing_store = *layers[0]->backing_store;
2338 backing_store.type = kFlutterBackingStoreTypeOpenGL;
2339 backing_store.did_update = true;
2341
2342 FlutterRect paint_region_rects[] = {
2343 FlutterRectMakeLTRB(0, 0, 600, 800),
2344 };
2345 FlutterRegion paint_region = {
2346 .struct_size = sizeof(FlutterRegion),
2347 .rects_count = 1,
2348 .rects = paint_region_rects,
2349 };
2350 FlutterBackingStorePresentInfo present_info = {
2352 .paint_region = &paint_region,
2353 };
2354
2355 FlutterLayer layer = {};
2356 layer.struct_size = sizeof(layer);
2358 layer.backing_store = &backing_store;
2359 layer.size = FlutterSizeMake(600.0, 800.0);
2360 layer.offset = FlutterPointMake(0.0, 0.0);
2361 layer.backing_store_present_info = &present_info;
2362
2363 ASSERT_EQ(*layers[0], layer);
2364 }
2365
2366 // Layer 1
2367 {
2369 platform_view.struct_size = sizeof(platform_view);
2370 platform_view.identifier = 42;
2371
2372 FlutterLayer layer = {};
2373 layer.struct_size = sizeof(layer);
2376 layer.size = FlutterSizeMake(560.0, 800.0);
2377 layer.offset = FlutterPointMake(40.0, 0.0);
2378
2379 ASSERT_EQ(*layers[1], layer);
2380 }
2381
2382 // Layer 2
2383 {
2384 FlutterBackingStore backing_store = *layers[2]->backing_store;
2385 backing_store.type = kFlutterBackingStoreTypeOpenGL;
2386 backing_store.did_update = true;
2388
2389 FlutterRect paint_region_rects[] = {
2390 FlutterRectMakeLTRB(0, 0, 600, 800),
2391 };
2392 FlutterRegion paint_region = {
2393 .struct_size = sizeof(FlutterRegion),
2394 .rects_count = 1,
2395 .rects = paint_region_rects,
2396 };
2397 FlutterBackingStorePresentInfo present_info = {
2399 .paint_region = &paint_region,
2400 };
2401
2402 FlutterLayer layer = {};
2403 layer.struct_size = sizeof(layer);
2405 layer.backing_store = &backing_store;
2406 layer.size = FlutterSizeMake(600.0, 800.0);
2407 layer.offset = FlutterPointMake(0.0, 0.0);
2408 layer.backing_store_present_info = &present_info;
2409
2410 ASSERT_EQ(*layers[2], layer);
2411 }
2412
2413 latch.CountDown();
2414 });
2415
2416 auto engine = builder.LaunchEngine();
2417
2418 // Send a window metrics events so frames may be scheduled.
2419 FlutterWindowMetricsEvent event = {};
2420 event.struct_size = sizeof(event);
2421 event.width = 400 * 2.0;
2422 event.height = 300 * 2.0;
2423 event.pixel_ratio = 2.0;
2425 kSuccess);
2426 ASSERT_TRUE(engine.is_valid());
2427
2428 latch.Wait();
2429
2430 ASSERT_TRUE(ImageMatchesFixture("dpr_xform.png", rendered_scene));
2431}
2432
2434 PushingMutlipleFramesSetsUpNewRecordingCanvasWithCustomCompositor) {
2435 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2436
2438 builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
2439 builder.SetCompositor();
2440 builder.SetDartEntrypoint("push_frames_over_and_over");
2441
2442 builder.SetRenderTargetType(
2444
2445 const auto root_surface_transformation =
2446 SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
2447
2448 context.SetRootSurfaceTransformation(root_surface_transformation);
2449
2450 auto engine = builder.LaunchEngine();
2451
2452 // Send a window metrics events so frames may be scheduled.
2453 FlutterWindowMetricsEvent event = {};
2454 event.struct_size = sizeof(event);
2455 event.width = 1024;
2456 event.height = 600;
2457 event.pixel_ratio = 1.0;
2459 kSuccess);
2460 ASSERT_TRUE(engine.is_valid());
2461
2462 constexpr size_t frames_expected = 10;
2463 fml::CountDownLatch frame_latch(frames_expected);
2464 std::atomic_size_t frames_seen = 0;
2465 context.AddNativeCallback("SignalNativeTest",
2467 frames_seen++;
2468 frame_latch.CountDown();
2469 }));
2470 frame_latch.Wait();
2471
2472 ASSERT_GE(frames_seen, frames_expected);
2473
2474 FlutterEngineShutdown(engine.release());
2475}
2476
2478 PushingMutlipleFramesSetsUpNewRecordingCanvasWithoutCustomCompositor) {
2479 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2480
2482 builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
2483 builder.SetDartEntrypoint("push_frames_over_and_over");
2484
2485 const auto root_surface_transformation =
2486 SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
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;
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",
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
2522 builder.SetRendererConfig(backend, SkISize::Make(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(
2530 [&](FlutterViewId view_id, const FlutterLayer** layers,
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 {
2567 platform_view.struct_size = sizeof(platform_view);
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 =
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 SkRect::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;
2621 kSuccess);
2622 ASSERT_TRUE(engine.is_valid());
2623
2624 latch.Wait();
2625}
2626
2627TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) {
2628 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2629
2631 builder.SetOpenGLRendererConfig(SkISize::Make(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(
2640 [&](FlutterViewId view_id, const FlutterLayer** layers,
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 {
2678 platform_view.struct_size = sizeof(platform_view);
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 =
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 SkRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2705 break;
2708 mutation.opacity = 128.0 / 255.0;
2709 break;
2712 mutation.transformation =
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;
2732 kSuccess);
2733 ASSERT_TRUE(engine.is_valid());
2734
2735 latch.Wait();
2736}
2737
2739 PlatformViewMutatorsAreValidWithPixelRatioAndRootSurfaceTransformation) {
2740 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2741
2743 builder.SetOpenGLRendererConfig(SkISize::Make(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 SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
2752
2753 context.SetRootSurfaceTransformation(root_surface_transformation);
2754
2755 fml::CountDownLatch latch(1);
2756 context.GetCompositor().SetNextPresentCallback(
2757 [&](FlutterViewId view_id, const FlutterLayer** layers,
2758 size_t layers_count) {
2759 ASSERT_EQ(layers_count, 2u);
2760
2761 // Layer 0 (Root)
2762 {
2763 FlutterBackingStore backing_store = *layers[0]->backing_store;
2764 backing_store.type = kFlutterBackingStoreTypeOpenGL;
2765 backing_store.did_update = true;
2767
2768 FlutterRect paint_region_rects[] = {
2769 FlutterRectMakeLTRB(0, 0, 600, 800),
2770 };
2771 FlutterRegion paint_region = {
2772 .struct_size = sizeof(FlutterRegion),
2773 .rects_count = 1,
2774 .rects = paint_region_rects,
2775 };
2776 FlutterBackingStorePresentInfo present_info = {
2778 .paint_region = &paint_region,
2779 };
2780
2781 FlutterLayer layer = {};
2782 layer.struct_size = sizeof(layer);
2784 layer.backing_store = &backing_store;
2785 layer.size = FlutterSizeMake(600.0, 800.0);
2786 layer.offset = FlutterPointMake(0.0, 0.0);
2787 layer.backing_store_present_info = &present_info;
2788
2789 ASSERT_EQ(*layers[0], layer);
2790 }
2791
2792 // Layer 2
2793 {
2795 platform_view.struct_size = sizeof(platform_view);
2796 platform_view.identifier = 42;
2797 platform_view.mutations_count = 4;
2798
2799 FlutterLayer layer = {};
2800 layer.struct_size = sizeof(layer);
2803 layer.size = FlutterSizeMake(600.0, 800.0);
2804 layer.offset = FlutterPointMake(0.0, 0.0);
2805
2806 ASSERT_EQ(*layers[1], layer);
2807
2808 // There are no ordering guarantees.
2809 for (size_t i = 0; i < platform_view.mutations_count; i++) {
2810 FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2811 switch (mutation.type) {
2813 mutation.clip_rounded_rect =
2815 SkRect::MakeLTRB(5.0, 5.0, 400.0 - 5.0, 300.0 - 5.0),
2816 7.0, 7.0));
2817 break;
2820 mutation.clip_rect = FlutterRectMake(
2821 SkRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2822 break;
2825 mutation.opacity = 128.0 / 255.0;
2826 break;
2829 mutation.transformation =
2830 FlutterTransformationMake(root_surface_transformation);
2831
2832 break;
2833 }
2834
2835 ASSERT_EQ(*platform_view.mutations[i], mutation);
2836 }
2837 }
2838 latch.CountDown();
2839 });
2840
2841 auto engine = builder.LaunchEngine();
2842
2843 // Send a window metrics events so frames may be scheduled.
2844 FlutterWindowMetricsEvent event = {};
2845 event.struct_size = sizeof(event);
2846 event.width = 800;
2847 event.height = 600;
2848 event.pixel_ratio = 2.0;
2850 kSuccess);
2851 ASSERT_TRUE(engine.is_valid());
2852
2853 latch.Wait();
2854}
2855
2856TEST_F(EmbedderTest, EmptySceneIsAcceptable) {
2857 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2858
2860 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2861 builder.SetCompositor();
2862 builder.SetDartEntrypoint("empty_scene");
2864 context.AddNativeCallback(
2865 "SignalNativeTest",
2867
2868 auto engine = builder.LaunchEngine();
2869
2870 ASSERT_TRUE(engine.is_valid());
2871
2872 FlutterWindowMetricsEvent event = {};
2873 event.struct_size = sizeof(event);
2874 event.width = 800;
2875 event.height = 600;
2876 event.pixel_ratio = 1.0;
2878 kSuccess);
2879 latch.Wait();
2880}
2881
2882TEST_F(EmbedderTest, SceneWithNoRootContainerIsAcceptable) {
2883 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2884
2886 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2887 builder.SetCompositor();
2888 builder.SetRenderTargetType(
2890 builder.SetDartEntrypoint("scene_with_no_container");
2892 context.AddNativeCallback(
2893 "SignalNativeTest",
2895
2896 auto engine = builder.LaunchEngine();
2897
2898 ASSERT_TRUE(engine.is_valid());
2899
2900 FlutterWindowMetricsEvent event = {};
2901 event.struct_size = sizeof(event);
2902 event.width = 800;
2903 event.height = 600;
2904 event.pixel_ratio = 1.0;
2906 kSuccess);
2907 latch.Wait();
2908}
2909
2910// Verifies that https://skia-review.googlesource.com/c/skia/+/259174 is pulled
2911// into the engine.
2912TEST_F(EmbedderTest, ArcEndCapsAreDrawnCorrectly) {
2913 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2914
2916 builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
2917 builder.SetCompositor();
2918 builder.SetDartEntrypoint("arc_end_caps_correct");
2919 builder.SetRenderTargetType(
2921
2922 const auto root_surface_transformation = SkMatrix()
2923 .preScale(1.0, -1.0)
2924 .preTranslate(1024.0, -800.0)
2925 .preRotate(90.0);
2926
2927 context.SetRootSurfaceTransformation(root_surface_transformation);
2928
2929 auto engine = builder.LaunchEngine();
2930
2931 auto scene_image = context.GetNextSceneImage();
2932
2933 ASSERT_TRUE(engine.is_valid());
2934
2935 FlutterWindowMetricsEvent event = {};
2936 event.struct_size = sizeof(event);
2937 event.width = 800;
2938 event.height = 1024;
2939 event.pixel_ratio = 1.0;
2941 kSuccess);
2942
2943 ASSERT_TRUE(ImageMatchesFixture("arc_end_caps.png", scene_image));
2944}
2945
2946TEST_F(EmbedderTest, ClipsAreCorrectlyCalculated) {
2947 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2948
2950 builder.SetOpenGLRendererConfig(SkISize::Make(400, 300));
2951 builder.SetCompositor();
2952 builder.SetDartEntrypoint("scene_builder_with_clips");
2953 builder.SetRenderTargetType(
2955
2956 const auto root_surface_transformation =
2957 SkMatrix().preTranslate(0, 400).preRotate(-90, 0, 0);
2958
2959 context.SetRootSurfaceTransformation(root_surface_transformation);
2960
2962 context.GetCompositor().SetNextPresentCallback(
2963 [&](FlutterViewId view_id, const FlutterLayer** layers,
2964 size_t layers_count) {
2965 ASSERT_EQ(layers_count, 2u);
2966
2967 {
2969 platform_view.struct_size = sizeof(platform_view);
2970 platform_view.identifier = 42;
2971
2972 FlutterLayer layer = {};
2973 layer.struct_size = sizeof(layer);
2976 layer.size = FlutterSizeMake(300.0, 400.0);
2977 layer.offset = FlutterPointMake(0.0, 0.0);
2978
2979 ASSERT_EQ(*layers[0], layer);
2980
2981 bool clip_assertions_checked = false;
2982
2983 // The total transformation on the stack upto the platform view.
2984 const auto total_xformation =
2986
2988 layers[0]->platform_view,
2990 [&](const auto& mutation) {
2991 FlutterRect clip = mutation.clip_rect;
2992
2993 // The test is only set up to supply one clip. Make sure it is
2994 // the one we expect.
2995 const auto rect_to_compare =
2996 SkRect::MakeLTRB(10.0, 10.0, 390, 290);
2997 ASSERT_EQ(clip, FlutterRectMake(rect_to_compare));
2998
2999 // This maps the clip from device space into surface space.
3000 SkRect mapped;
3001 ASSERT_TRUE(total_xformation.mapRect(&mapped, rect_to_compare));
3002 ASSERT_EQ(mapped, SkRect::MakeLTRB(10, 10, 290, 390));
3003 clip_assertions_checked = true;
3004 });
3005
3006 ASSERT_TRUE(clip_assertions_checked);
3007 }
3008
3009 latch.Signal();
3010 });
3011
3012 auto engine = builder.LaunchEngine();
3013 ASSERT_TRUE(engine.is_valid());
3014
3015 FlutterWindowMetricsEvent event = {};
3016 event.struct_size = sizeof(event);
3017 event.width = 400;
3018 event.height = 300;
3019 event.pixel_ratio = 1.0;
3021 kSuccess);
3022
3023 latch.Wait();
3024}
3025
3026TEST_F(EmbedderTest, ComplexClipsAreCorrectlyCalculated) {
3027 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3028
3030 builder.SetOpenGLRendererConfig(SkISize::Make(1024, 600));
3031 builder.SetCompositor();
3032 builder.SetDartEntrypoint("scene_builder_with_complex_clips");
3033 builder.SetRenderTargetType(
3035
3036 const auto root_surface_transformation =
3037 SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
3038
3039 context.SetRootSurfaceTransformation(root_surface_transformation);
3040
3042 context.GetCompositor().SetNextPresentCallback(
3043 [&](FlutterViewId view_id, const FlutterLayer** layers,
3044 size_t layers_count) {
3045 ASSERT_EQ(layers_count, 2u);
3046
3047 {
3049 platform_view.struct_size = sizeof(platform_view);
3050 platform_view.identifier = 42;
3051
3052 FlutterLayer layer = {};
3053 layer.struct_size = sizeof(layer);
3056 layer.size = FlutterSizeMake(600.0, 1024.0);
3057 layer.offset = FlutterPointMake(0.0, -256.0);
3058
3059 ASSERT_EQ(*layers[0], layer);
3060
3061 const auto** mutations = platform_view.mutations;
3062
3063 ASSERT_EQ(mutations[0]->type,
3065 ASSERT_EQ(SkMatrixMake(mutations[0]->transformation),
3066 root_surface_transformation);
3067
3068 ASSERT_EQ(mutations[1]->type,
3070 ASSERT_EQ(SkRectMake(mutations[1]->clip_rect),
3071 SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
3072
3073 ASSERT_EQ(mutations[2]->type,
3075 ASSERT_EQ(SkMatrixMake(mutations[2]->transformation),
3076 SkMatrix::Translate(512.0, 0.0));
3077
3078 ASSERT_EQ(mutations[3]->type,
3080 ASSERT_EQ(SkRectMake(mutations[3]->clip_rect),
3081 SkRect::MakeLTRB(0.0, 0.0, 512.0, 600.0));
3082
3083 ASSERT_EQ(mutations[4]->type,
3085 ASSERT_EQ(SkMatrixMake(mutations[4]->transformation),
3086 SkMatrix::Translate(-256.0, 0.0));
3087
3088 ASSERT_EQ(mutations[5]->type,
3090 ASSERT_EQ(SkRectMake(mutations[5]->clip_rect),
3091 SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
3092 }
3093
3094 latch.Signal();
3095 });
3096
3097 auto engine = builder.LaunchEngine();
3098 ASSERT_TRUE(engine.is_valid());
3099
3100 FlutterWindowMetricsEvent event = {};
3101 event.struct_size = sizeof(event);
3102 event.width = 1024;
3103 event.height = 600;
3104 event.pixel_ratio = 1.0;
3106 kSuccess);
3107
3108 latch.Wait();
3109}
3110
3111TEST_F(EmbedderTest, ObjectsCanBePostedViaPorts) {
3112 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3114 builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
3115 builder.SetDartEntrypoint("objects_can_be_posted");
3116
3117 // Synchronously acquire the send port from the Dart end. We will be using
3118 // this to send message. The Dart end will just echo those messages back to us
3119 // for inspection.
3122 context.AddNativeCallback("SignalNativeCount",
3126 event.Signal();
3127 }));
3128 auto engine = builder.LaunchEngine();
3129 ASSERT_TRUE(engine.is_valid());
3130 event.Wait();
3131 ASSERT_NE(port, 0);
3132
3133 using Trampoline = std::function<void(Dart_Handle message)>;
3134 Trampoline trampoline;
3135
3136 context.AddNativeCallback("SendObjectToNativeCode",
3138 FML_CHECK(trampoline);
3139 auto trampoline_copy = trampoline;
3140 trampoline = nullptr;
3141 trampoline_copy(Dart_GetNativeArgument(args, 0));
3142 }));
3143
3144 // Check null.
3145 {
3146 FlutterEngineDartObject object = {};
3148 trampoline = [&](Dart_Handle handle) {
3149 ASSERT_TRUE(Dart_IsNull(handle));
3150 event.Signal();
3151 };
3152 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3153 kSuccess);
3154 event.Wait();
3155 }
3156
3157 // Check bool.
3158 {
3159 FlutterEngineDartObject object = {};
3161 object.bool_value = true;
3162 trampoline = [&](Dart_Handle handle) {
3163 ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(handle));
3164 event.Signal();
3165 };
3166 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3167 kSuccess);
3168 event.Wait();
3169 }
3170
3171 // Check int32.
3172 {
3173 FlutterEngineDartObject object = {};
3175 object.int32_value = 1988;
3176 trampoline = [&](Dart_Handle handle) {
3177 ASSERT_EQ(tonic::DartConverter<int32_t>::FromDart(handle), 1988);
3178 event.Signal();
3179 };
3180 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3181 kSuccess);
3182 event.Wait();
3183 }
3184
3185 // Check int64.
3186 {
3187 FlutterEngineDartObject object = {};
3189 object.int64_value = 1988;
3190 trampoline = [&](Dart_Handle handle) {
3191 ASSERT_EQ(tonic::DartConverter<int64_t>::FromDart(handle), 1988);
3192 event.Signal();
3193 };
3194 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3195 kSuccess);
3196 event.Wait();
3197 }
3198
3199 // Check double.
3200 {
3201 FlutterEngineDartObject object = {};
3203 object.double_value = 1988.0;
3204 trampoline = [&](Dart_Handle handle) {
3205 ASSERT_DOUBLE_EQ(tonic::DartConverter<double>::FromDart(handle), 1988.0);
3206 event.Signal();
3207 };
3208 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3209 kSuccess);
3210 event.Wait();
3211 }
3212
3213 // Check string.
3214 {
3215 const char* message = "Hello. My name is Inigo Montoya.";
3216 FlutterEngineDartObject object = {};
3218 object.string_value = message;
3219 trampoline = [&](Dart_Handle handle) {
3221 std::string{message});
3222 event.Signal();
3223 };
3224 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3225 kSuccess);
3226 event.Wait();
3227 }
3228
3229 // Check buffer (copied out).
3230 {
3231 std::vector<uint8_t> message;
3232 message.resize(1988);
3233
3234 ASSERT_TRUE(MemsetPatternSetOrCheck(
3236
3238
3239 buffer.struct_size = sizeof(buffer);
3240 buffer.user_data = nullptr;
3241 buffer.buffer_collect_callback = nullptr;
3242 buffer.buffer = message.data();
3243 buffer.buffer_size = message.size();
3244
3245 FlutterEngineDartObject object = {};
3247 object.buffer_value = &buffer;
3248 trampoline = [&](Dart_Handle handle) {
3249 intptr_t length = 0;
3250 Dart_ListLength(handle, &length);
3251 ASSERT_EQ(length, 1988);
3252 // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
3253 // DartConvertor in tonic is broken which is preventing the buffer
3254 // being checked here. Fix tonic and strengthen this check. For now, just
3255 // the buffer length is checked.
3256 event.Signal();
3257 };
3258 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3259 kSuccess);
3260 event.Wait();
3261 }
3262
3263 std::vector<uint8_t> message;
3264 fml::AutoResetWaitableEvent buffer_released_latch;
3265
3266 // Check buffer (caller own buffer with zero copy transfer).
3267 {
3268 message.resize(1988);
3269
3270 ASSERT_TRUE(MemsetPatternSetOrCheck(
3272
3274
3275 buffer.struct_size = sizeof(buffer);
3276 buffer.user_data = &buffer_released_latch;
3277 buffer.buffer_collect_callback = +[](void* user_data) {
3278 reinterpret_cast<fml::AutoResetWaitableEvent*>(user_data)->Signal();
3279 };
3280 buffer.buffer = message.data();
3281 buffer.buffer_size = message.size();
3282
3283 FlutterEngineDartObject object = {};
3285 object.buffer_value = &buffer;
3286 trampoline = [&](Dart_Handle handle) {
3287 intptr_t length = 0;
3288 Dart_ListLength(handle, &length);
3289 ASSERT_EQ(length, 1988);
3290 // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
3291 // DartConvertor in tonic is broken which is preventing the buffer
3292 // being checked here. Fix tonic and strengthen this check. For now, just
3293 // the buffer length is checked.
3294 event.Signal();
3295 };
3296 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3297 kSuccess);
3298 event.Wait();
3299 }
3300
3301 engine.reset();
3302
3303 // We cannot determine when the VM will GC objects that might have external
3304 // typed data finalizers. Since we need to ensure that we correctly wired up
3305 // finalizers from the embedders, we force the VM to collect all objects but
3306 // just shutting it down.
3307 buffer_released_latch.Wait();
3308}
3309
3310TEST_F(EmbedderTest, CompositorCanPostZeroLayersForPresentation) {
3311 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3312
3314 builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
3315 builder.SetCompositor();
3316 builder.SetDartEntrypoint("empty_scene_posts_zero_layers_to_compositor");
3317 builder.SetRenderTargetType(
3319
3321
3322 context.GetCompositor().SetNextPresentCallback(
3323 [&](FlutterViewId view_id, const FlutterLayer** layers,
3324 size_t layers_count) {
3325 ASSERT_EQ(layers_count, 0u);
3326 latch.Signal();
3327 });
3328
3329 auto engine = builder.LaunchEngine();
3330
3331 FlutterWindowMetricsEvent event = {};
3332 event.struct_size = sizeof(event);
3333 event.width = 300;
3334 event.height = 200;
3335 event.pixel_ratio = 1.0;
3337 kSuccess);
3338 ASSERT_TRUE(engine.is_valid());
3339 latch.Wait();
3340
3341 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
3342}
3343
3344TEST_F(EmbedderTest, CompositorCanPostOnlyPlatformViews) {
3345 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3346
3348 builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
3349 builder.SetCompositor();
3350 builder.SetDartEntrypoint("compositor_can_post_only_platform_views");
3351 builder.SetRenderTargetType(
3353
3355
3356 context.GetCompositor().SetNextPresentCallback(
3357 [&](FlutterViewId view_id, const FlutterLayer** layers,
3358 size_t layers_count) {
3359 ASSERT_EQ(layers_count, 2u);
3360
3361 // Layer 0
3362 {
3364 platform_view.struct_size = sizeof(platform_view);
3365 platform_view.identifier = 42;
3366 FlutterLayer layer = {};
3367 layer.struct_size = sizeof(layer);
3370 layer.size = FlutterSizeMake(300.0, 200.0);
3371 layer.offset = FlutterPointMake(0.0, 0.0);
3372
3373 ASSERT_EQ(*layers[0], layer);
3374 }
3375
3376 // Layer 1
3377 {
3379 platform_view.struct_size = sizeof(platform_view);
3380 platform_view.identifier = 24;
3381 FlutterLayer layer = {};
3382 layer.struct_size = sizeof(layer);
3385 layer.size = FlutterSizeMake(300.0, 200.0);
3386 layer.offset = FlutterPointMake(0.0, 0.0);
3387
3388 ASSERT_EQ(*layers[1], layer);
3389 }
3390 latch.Signal();
3391 });
3392
3393 auto engine = builder.LaunchEngine();
3394
3395 FlutterWindowMetricsEvent event = {};
3396 event.struct_size = sizeof(event);
3397 event.width = 300;
3398 event.height = 200;
3399 event.pixel_ratio = 1.0;
3401 kSuccess);
3402 ASSERT_TRUE(engine.is_valid());
3403 latch.Wait();
3404
3405 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
3406}
3407
3408TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) {
3409 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3410
3412 builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
3413 builder.SetCompositor();
3414 builder.SetDartEntrypoint("render_targets_are_recycled");
3415 builder.SetRenderTargetType(
3417
3418 fml::CountDownLatch latch(2);
3419
3420 context.AddNativeCallback("SignalNativeTest",
3422 latch.CountDown();
3423 }));
3424
3425 context.GetCompositor().SetNextPresentCallback(
3426 [&](FlutterViewId view_id, const FlutterLayer** layers,
3427 size_t layers_count) {
3428 ASSERT_EQ(layers_count, 20u);
3429 latch.CountDown();
3430 });
3431
3432 auto engine = builder.LaunchEngine();
3433 ASSERT_TRUE(engine.is_valid());
3434
3435 FlutterWindowMetricsEvent event = {};
3436 event.struct_size = sizeof(event);
3437 event.width = 300;
3438 event.height = 200;
3439 event.pixel_ratio = 1.0;
3441 kSuccess);
3442
3443 latch.Wait();
3444 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 10u);
3445 ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
3446 ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 0u);
3447 // Killing the engine should immediately collect all pending render targets.
3448 engine.reset();
3449 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
3450 ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
3451 ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 10u);
3452}
3453
3454TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) {
3455 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3456
3458 builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
3459 builder.SetCompositor();
3460 builder.SetDartEntrypoint("render_targets_are_in_stable_order");
3461 builder.SetRenderTargetType(
3463
3464 fml::CountDownLatch latch(2);
3465
3466 context.AddNativeCallback("SignalNativeTest",
3468 latch.CountDown();
3469 }));
3470
3471 size_t frame_count = 0;
3472 std::vector<void*> first_frame_backing_store_user_data;
3473 context.GetCompositor().SetPresentCallback(
3474 [&](FlutterViewId view_id, const FlutterLayer** layers,
3475 size_t layers_count) {
3476 ASSERT_EQ(layers_count, 20u);
3477
3478 if (first_frame_backing_store_user_data.empty()) {
3479 for (size_t i = 0; i < layers_count; ++i) {
3481 first_frame_backing_store_user_data.push_back(
3482 layers[i]->backing_store->user_data);
3483 }
3484 }
3485 return;
3486 }
3487
3488 ASSERT_EQ(first_frame_backing_store_user_data.size(), 10u);
3489
3490 frame_count++;
3491 std::vector<void*> backing_store_user_data;
3492 for (size_t i = 0; i < layers_count; ++i) {
3494 backing_store_user_data.push_back(
3495 layers[i]->backing_store->user_data);
3496 }
3497 }
3498
3499 ASSERT_EQ(backing_store_user_data.size(), 10u);
3500
3501 ASSERT_EQ(first_frame_backing_store_user_data, backing_store_user_data);
3502
3503 if (frame_count == 20) {
3504 latch.CountDown();
3505 }
3506 },
3507 false // one shot
3508 );
3509
3510 auto engine = builder.LaunchEngine();
3511 ASSERT_TRUE(engine.is_valid());
3512
3513 FlutterWindowMetricsEvent event = {};
3514 event.struct_size = sizeof(event);
3515 event.width = 300;
3516 event.height = 200;
3517 event.pixel_ratio = 1.0;
3519 kSuccess);
3520
3521 latch.Wait();
3522}
3523
3524TEST_F(EmbedderTest, FrameInfoContainsValidWidthAndHeight) {
3525 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3526
3528 builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3529 builder.SetDartEntrypoint("push_frames_over_and_over");
3530
3531 const auto root_surface_transformation =
3532 SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
3533
3534 context.SetRootSurfaceTransformation(root_surface_transformation);
3535
3536 auto engine = builder.LaunchEngine();
3537
3538 // Send a window metrics events so frames may be scheduled.
3539 static FlutterWindowMetricsEvent event = {};
3540 event.struct_size = sizeof(event);
3541 event.width = 1024;
3542 event.height = 600;
3543 event.pixel_ratio = 1.0;
3545 kSuccess);
3546 ASSERT_TRUE(engine.is_valid());
3547
3548 static fml::CountDownLatch frame_latch(10);
3549
3550 context.AddNativeCallback("SignalNativeTest",
3552 /* Nothing to do. */
3553 }));
3554
3555 static_cast<EmbedderTestContextGL&>(context).SetGLGetFBOCallback(
3556 [](FlutterFrameInfo frame_info) {
3557 // width and height are rotated by 90 deg
3558 ASSERT_EQ(frame_info.size.width, event.height);
3559 ASSERT_EQ(frame_info.size.height, event.width);
3560
3561 frame_latch.CountDown();
3562 });
3563
3564 frame_latch.Wait();
3565}
3566
3567TEST_F(EmbedderTest, MustNotRunWithBothFBOCallbacksSet) {
3568 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3569
3571 builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3572 builder.SetOpenGLFBOCallBack();
3573
3574 auto engine = builder.LaunchEngine();
3575 ASSERT_FALSE(engine.is_valid());
3576}
3577
3578TEST_F(EmbedderTest, MustNotRunWithBothPresentCallbacksSet) {
3579 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3580
3582 builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3583 builder.SetOpenGLPresentCallBack();
3584
3585 auto engine = builder.LaunchEngine();
3586 ASSERT_FALSE(engine.is_valid());
3587}
3588
3589TEST_F(EmbedderTest, MustStillRunWhenPopulateExistingDamageIsNotProvided) {
3590 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3591
3593 builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
3594 builder.GetRendererConfig().open_gl.populate_existing_damage = nullptr;
3595
3596 auto engine = builder.LaunchEngine();
3597 ASSERT_TRUE(engine.is_valid());
3598}
3599
3600TEST_F(EmbedderTest, MustRunWhenPopulateExistingDamageIsProvided) {
3601 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3602
3604 builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
3605
3606 builder.GetRendererConfig().open_gl.populate_existing_damage =
3607 [](void* context, const intptr_t id,
3608 FlutterDamage* existing_damage) -> void {
3609 return reinterpret_cast<EmbedderTestContextGL*>(context)
3610 ->GLPopulateExistingDamage(id, existing_damage);
3611 };
3612
3613 auto engine = builder.LaunchEngine();
3614 ASSERT_TRUE(engine.is_valid());
3615}
3616
3617TEST_F(EmbedderTest, MustRunWithPopulateExistingDamageAndFBOCallback) {
3618 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3619
3621 builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
3622 builder.GetRendererConfig().open_gl.fbo_callback =
3623 [](void* context) -> uint32_t { return 0; };
3624 builder.GetRendererConfig().open_gl.fbo_with_frame_info_callback = nullptr;
3625 builder.GetRendererConfig().open_gl.populate_existing_damage =
3626 [](void* context, const intptr_t id,
3627 FlutterDamage* existing_damage) -> void {
3628 return reinterpret_cast<EmbedderTestContextGL*>(context)
3629 ->GLPopulateExistingDamage(id, existing_damage);
3630 };
3631
3632 auto engine = builder.LaunchEngine();
3633 ASSERT_TRUE(engine.is_valid());
3634}
3635
3637 MustNotRunWhenPopulateExistingDamageButNoOtherFBOCallback) {
3638 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3639
3641 builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
3642 builder.GetRendererConfig().open_gl.fbo_callback = nullptr;
3643 builder.GetRendererConfig().open_gl.fbo_with_frame_info_callback = nullptr;
3644 builder.GetRendererConfig().open_gl.populate_existing_damage =
3645 [](void* context, const intptr_t id,
3646 FlutterDamage* existing_damage) -> void {
3647 return reinterpret_cast<EmbedderTestContextGL*>(context)
3648 ->GLPopulateExistingDamage(id, existing_damage);
3649 };
3650
3651 auto engine = builder.LaunchEngine();
3652 ASSERT_FALSE(engine.is_valid());
3653}
3654
3655TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) {
3656 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3657
3659 builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3660 builder.SetDartEntrypoint("push_frames_over_and_over");
3661
3662 const auto root_surface_transformation =
3663 SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
3664
3665 context.SetRootSurfaceTransformation(root_surface_transformation);
3666
3667 auto engine = builder.LaunchEngine();
3668
3669 // Send a window metrics events so frames may be scheduled.
3670 FlutterWindowMetricsEvent event = {};
3671 event.struct_size = sizeof(event);
3672 event.width = 1024;
3673 event.height = 600;
3674 event.pixel_ratio = 1.0;
3676 kSuccess);
3677 ASSERT_TRUE(engine.is_valid());
3678
3679 static fml::CountDownLatch frame_latch(10);
3680
3681 context.AddNativeCallback("SignalNativeTest",
3683 /* Nothing to do. */
3684 }));
3685
3686 const uint32_t window_fbo_id =
3687 static_cast<EmbedderTestContextGL&>(context).GetWindowFBOId();
3688 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3689 [window_fbo_id = window_fbo_id](FlutterPresentInfo present_info) {
3690 ASSERT_EQ(present_info.fbo_id, window_fbo_id);
3691
3692 frame_latch.CountDown();
3693 });
3694
3695 frame_latch.Wait();
3696}
3697
3699 PresentInfoReceivesFullDamageWhenExistingDamageIsWholeScreen) {
3700 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3701
3703 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3704 builder.SetDartEntrypoint("render_gradient_retained");
3705 builder.GetRendererConfig().open_gl.populate_existing_damage =
3706 [](void* context, const intptr_t id,
3707 FlutterDamage* existing_damage) -> void {
3708 return reinterpret_cast<EmbedderTestContextGL*>(context)
3709 ->GLPopulateExistingDamage(id, existing_damage);
3710 };
3711
3712 // Return existing damage as the entire screen on purpose.
3713 static_cast<EmbedderTestContextGL&>(context)
3714 .SetGLPopulateExistingDamageCallback(
3715 [](const intptr_t id, FlutterDamage* existing_damage_ptr) {
3716 const size_t num_rects = 1;
3717 // The array must be valid after the callback returns.
3718 static FlutterRect existing_damage_rects[num_rects] = {
3719 FlutterRect{0, 0, 800, 600}};
3720 existing_damage_ptr->num_rects = num_rects;
3721 existing_damage_ptr->damage = existing_damage_rects;
3722 });
3723
3724 auto engine = builder.LaunchEngine();
3725 ASSERT_TRUE(engine.is_valid());
3726
3728
3729 // First frame should be entirely rerendered.
3730 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3731 [&](FlutterPresentInfo present_info) {
3732 const size_t num_rects = 1;
3733 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3734 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3735 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3736 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
3737 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
3738
3739 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3740 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3741 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3742 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3743 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3744
3745 latch.Signal();
3746 });
3747
3748 // Send a window metrics events so frames may be scheduled.
3749 FlutterWindowMetricsEvent event = {};
3750 event.struct_size = sizeof(event);
3751 event.width = 800;
3752 event.height = 600;
3753 event.pixel_ratio = 1.0;
3755 kSuccess);
3756 latch.Wait();
3757
3758 // Because it's the same as the first frame, the second frame damage should
3759 // be empty but, because there was a full existing buffer damage, the buffer
3760 // damage should be the entire screen.
3761 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3762 [&](FlutterPresentInfo present_info) {
3763 const size_t num_rects = 1;
3764 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3765 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3766 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3767 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
3768 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
3769
3770 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3771 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3772 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3773 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3774 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3775
3776 latch.Signal();
3777 });
3778
3780 kSuccess);
3781 latch.Wait();
3782}
3783
3784TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) {
3785 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3786
3788 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3789 builder.SetDartEntrypoint("render_gradient_retained");
3790 builder.GetRendererConfig().open_gl.populate_existing_damage =
3791 [](void* context, const intptr_t id,
3792 FlutterDamage* existing_damage) -> void {
3793 return reinterpret_cast<EmbedderTestContextGL*>(context)
3794 ->GLPopulateExistingDamage(id, existing_damage);
3795 };
3796
3797 // Return no existing damage on purpose.
3798 static_cast<EmbedderTestContextGL&>(context)
3799 .SetGLPopulateExistingDamageCallback(
3800 [](const intptr_t id, FlutterDamage* existing_damage_ptr) {
3801 const size_t num_rects = 1;
3802 // The array must be valid after the callback returns.
3803 static FlutterRect existing_damage_rects[num_rects] = {
3804 FlutterRect{0, 0, 0, 0}};
3805 existing_damage_ptr->num_rects = num_rects;
3806 existing_damage_ptr->damage = existing_damage_rects;
3807 });
3808
3809 auto engine = builder.LaunchEngine();
3810 ASSERT_TRUE(engine.is_valid());
3811
3813
3814 // First frame should be entirely rerendered.
3815 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3816 [&](FlutterPresentInfo present_info) {
3817 const size_t num_rects = 1;
3818 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3819 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3820 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3821 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
3822 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
3823
3824 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3825 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3826 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3827 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3828 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3829
3830 latch.Signal();
3831 });
3832
3833 // Send a window metrics events so frames may be scheduled.
3834 FlutterWindowMetricsEvent event = {};
3835 event.struct_size = sizeof(event);
3836 event.width = 800;
3837 event.height = 600;
3838 event.pixel_ratio = 1.0;
3840 kSuccess);
3841 latch.Wait();
3842
3843 // Because it's the same as the first frame, the second frame should not be
3844 // rerendered assuming there is no existing damage.
3845 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3846 [&](FlutterPresentInfo present_info) {
3847 const size_t num_rects = 1;
3848 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3849 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3850 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3851 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
3852 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
3853
3854 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3855 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3856 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3857 ASSERT_EQ(present_info.buffer_damage.damage->right, 0);
3858 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 0);
3859
3860 latch.Signal();
3861 });
3862
3864 kSuccess);
3865 latch.Wait();
3866}
3867
3868TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) {
3869 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3870
3872 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3873 builder.SetDartEntrypoint("render_gradient_retained");
3874 builder.GetRendererConfig().open_gl.populate_existing_damage =
3875 [](void* context, const intptr_t id,
3876 FlutterDamage* existing_damage) -> void {
3877 return reinterpret_cast<EmbedderTestContextGL*>(context)
3878 ->GLPopulateExistingDamage(id, existing_damage);
3879 };
3880
3881 // Return existing damage as only part of the screen on purpose.
3882 static_cast<EmbedderTestContextGL&>(context)
3883 .SetGLPopulateExistingDamageCallback(
3884 [&](const intptr_t id, FlutterDamage* existing_damage_ptr) {
3885 const size_t num_rects = 1;
3886 // The array must be valid after the callback returns.
3887 static FlutterRect existing_damage_rects[num_rects] = {
3888 FlutterRect{200, 150, 400, 300}};
3889 existing_damage_ptr->num_rects = num_rects;
3890 existing_damage_ptr->damage = existing_damage_rects;
3891 });
3892
3893 auto engine = builder.LaunchEngine();
3894 ASSERT_TRUE(engine.is_valid());
3895
3897
3898 // First frame should be entirely rerendered.
3899 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3900 [&](FlutterPresentInfo present_info) {
3901 const size_t num_rects = 1;
3902 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3903 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3904 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3905 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
3906 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
3907
3908 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3909 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
3910 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
3911 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
3912 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
3913
3914 latch.Signal();
3915 });
3916
3917 // Send a window metrics events so frames may be scheduled.
3918 FlutterWindowMetricsEvent event = {};
3919 event.struct_size = sizeof(event);
3920 event.width = 800;
3921 event.height = 600;
3922 event.pixel_ratio = 1.0;
3924 kSuccess);
3925 latch.Wait();
3926
3927 // Because it's the same as the first frame, the second frame damage should be
3928 // empty but, because there was a partial existing damage, the buffer damage
3929 // should represent that partial damage area.
3930 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3931 [&](FlutterPresentInfo present_info) {
3932 const size_t num_rects = 1;
3933 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
3934 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
3935 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
3936 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
3937 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
3938
3939 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
3940 ASSERT_EQ(present_info.buffer_damage.damage->left, 200);
3941 ASSERT_EQ(present_info.buffer_damage.damage->top, 150);
3942 ASSERT_EQ(present_info.buffer_damage.damage->right, 400);
3943 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 300);
3944
3945 latch.Signal();
3946 });
3947
3949 kSuccess);
3950 latch.Wait();
3951}
3952
3953TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) {
3954 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3955
3957 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3958 builder.SetDartEntrypoint("render_gradient_retained");
3959 builder.GetRendererConfig().open_gl.populate_existing_damage =
3960 [](void* context, const intptr_t id,
3961 FlutterDamage* existing_damage) -> void {
3962 return reinterpret_cast<EmbedderTestContextGL*>(context)
3963 ->GLPopulateExistingDamage(id, existing_damage);
3964 };
3965
3966 auto engine = builder.LaunchEngine();
3967 ASSERT_TRUE(engine.is_valid());
3968
3969 const uint32_t window_fbo_id =
3970 static_cast<EmbedderTestContextGL&>(context).GetWindowFBOId();
3971 static_cast<EmbedderTestContextGL&>(context)
3972 .SetGLPopulateExistingDamageCallback(
3973 [window_fbo_id = window_fbo_id](intptr_t id,
3974 FlutterDamage* existing_damage) {
3975 ASSERT_EQ(id, window_fbo_id);
3976 existing_damage->num_rects = 0;
3977 existing_damage->damage = nullptr;
3978 });
3979
3980 // Send a window metrics events so frames may be scheduled.
3981 FlutterWindowMetricsEvent event = {};
3982 event.struct_size = sizeof(event);
3983 event.width = 800;
3984 event.height = 600;
3985 event.pixel_ratio = 1.0;
3987 kSuccess);
3988}
3989
3990TEST_F(EmbedderTest, PopulateExistingDamageReceivesInvalidID) {
3991 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3992
3994 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3995 builder.SetDartEntrypoint("render_gradient_retained");
3996 builder.GetRendererConfig().open_gl.populate_existing_damage =
3997 [](void* context, const intptr_t id,
3998 FlutterDamage* existing_damage) -> void {
3999 return reinterpret_cast<EmbedderTestContextGL*>(context)
4000 ->GLPopulateExistingDamage(id, existing_damage);
4001 };
4002
4003 // Return a bad FBO ID on purpose.
4004 builder.GetRendererConfig().open_gl.fbo_with_frame_info_callback =
4005 [](void* context, const FlutterFrameInfo* frame_info) -> uint32_t {
4006 return 123;
4007 };
4008
4009 auto engine = builder.LaunchEngine();
4010 ASSERT_TRUE(engine.is_valid());
4011
4012 context.AddNativeCallback("SignalNativeTest",
4014 /* Nothing to do. */
4015 }));
4016
4017 const uint32_t window_fbo_id =
4018 static_cast<EmbedderTestContextGL&>(context).GetWindowFBOId();
4019 static_cast<EmbedderTestContextGL&>(context)
4020 .SetGLPopulateExistingDamageCallback(
4021 [window_fbo_id = window_fbo_id](intptr_t id,
4022 FlutterDamage* existing_damage) {
4023 ASSERT_NE(id, window_fbo_id);
4024 existing_damage->num_rects = 0;
4025 existing_damage->damage = nullptr;
4026 });
4027
4028 // Send a window metrics events so frames may be scheduled.
4029 FlutterWindowMetricsEvent event = {};
4030 event.struct_size = sizeof(event);
4031 event.width = 800;
4032 event.height = 600;
4033 event.pixel_ratio = 1.0;
4035 kSuccess);
4036}
4037
4038TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithDisplayId) {
4039 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4040
4042 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4043 builder.SetCompositor();
4044 builder.SetDartEntrypoint("empty_scene");
4046 context.AddNativeCallback(
4047 "SignalNativeTest",
4049
4050 auto engine = builder.LaunchEngine();
4051
4052 ASSERT_TRUE(engine.is_valid());
4053
4054 FlutterEngineDisplay display;
4055 display.struct_size = sizeof(FlutterEngineDisplay);
4056 display.display_id = 1;
4057 display.refresh_rate = 20;
4058
4059 std::vector<FlutterEngineDisplay> displays = {display};
4060
4062 engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
4063 displays.size());
4064 ASSERT_EQ(result, kSuccess);
4065
4067 ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
4068
4069 FlutterWindowMetricsEvent event = {};
4070 event.struct_size = sizeof(event);
4071 event.width = 800;
4072 event.height = 600;
4073 event.pixel_ratio = 1.0;
4075 kSuccess);
4076
4077 latch.Wait();
4078}
4079
4080TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithoutDisplayId) {
4081 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4082
4084 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4085 builder.SetCompositor();
4086 builder.SetDartEntrypoint("empty_scene");
4088 context.AddNativeCallback(
4089 "SignalNativeTest",
4091
4092 auto engine = builder.LaunchEngine();
4093
4094 ASSERT_TRUE(engine.is_valid());
4095
4096 FlutterEngineDisplay display;
4097 display.struct_size = sizeof(FlutterEngineDisplay);
4098 display.single_display = true;
4099 display.refresh_rate = 20;
4100
4101 std::vector<FlutterEngineDisplay> displays = {display};
4102
4104 engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
4105 displays.size());
4106 ASSERT_EQ(result, kSuccess);
4107
4109 ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
4110
4111 FlutterWindowMetricsEvent event = {};
4112 event.struct_size = sizeof(event);
4113 event.width = 800;
4114 event.height = 600;
4115 event.pixel_ratio = 1.0;
4117 kSuccess);
4118
4119 latch.Wait();
4120}
4121
4122TEST_F(EmbedderTest, SetValidMultiDisplayConfiguration) {
4123 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4124
4126 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4127 builder.SetCompositor();
4128 builder.SetDartEntrypoint("empty_scene");
4130 context.AddNativeCallback(
4131 "SignalNativeTest",
4133
4134 auto engine = builder.LaunchEngine();
4135
4136 ASSERT_TRUE(engine.is_valid());
4137
4138 FlutterEngineDisplay display_1;
4139 display_1.struct_size = sizeof(FlutterEngineDisplay);
4140 display_1.display_id = 1;
4141 display_1.single_display = false;
4142 display_1.refresh_rate = 20;
4143
4144 FlutterEngineDisplay display_2;
4145 display_2.struct_size = sizeof(FlutterEngineDisplay);
4146 display_2.display_id = 2;
4147 display_2.single_display = false;
4148 display_2.refresh_rate = 60;
4149
4150 std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
4151
4153 engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
4154 displays.size());
4155 ASSERT_EQ(result, kSuccess);
4156
4158 ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display_1.refresh_rate);
4159
4160 FlutterWindowMetricsEvent event = {};
4161 event.struct_size = sizeof(event);
4162 event.width = 800;
4163 event.height = 600;
4164 event.pixel_ratio = 1.0;
4166 kSuccess);
4167
4168 latch.Wait();
4169}
4170
4171TEST_F(EmbedderTest, MultipleDisplaysWithSingleDisplayTrueIsInvalid) {
4172 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4173
4175 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4176 builder.SetCompositor();
4177 builder.SetDartEntrypoint("empty_scene");
4179 context.AddNativeCallback(
4180 "SignalNativeTest",
4182
4183 auto engine = builder.LaunchEngine();
4184
4185 ASSERT_TRUE(engine.is_valid());
4186
4187 FlutterEngineDisplay display_1;
4188 display_1.struct_size = sizeof(FlutterEngineDisplay);
4189 display_1.display_id = 1;
4190 display_1.single_display = true;
4191 display_1.refresh_rate = 20;
4192
4193 FlutterEngineDisplay display_2;
4194 display_2.struct_size = sizeof(FlutterEngineDisplay);
4195 display_2.display_id = 2;
4196 display_2.single_display = true;
4197 display_2.refresh_rate = 60;
4198
4199 std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
4200
4202 engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
4203 displays.size());
4204 ASSERT_NE(result, kSuccess);
4205
4206 FlutterWindowMetricsEvent event = {};
4207 event.struct_size = sizeof(event);
4208 event.width = 800;
4209 event.height = 600;
4210 event.pixel_ratio = 1.0;
4212 kSuccess);
4213
4214 latch.Wait();
4215}
4216
4217TEST_F(EmbedderTest, MultipleDisplaysWithSameDisplayIdIsInvalid) {
4218 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4219
4221 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4222 builder.SetCompositor();
4223 builder.SetDartEntrypoint("empty_scene");
4225 context.AddNativeCallback(
4226 "SignalNativeTest",
4228
4229 auto engine = builder.LaunchEngine();
4230
4231 ASSERT_TRUE(engine.is_valid());
4232
4233 FlutterEngineDisplay display_1;
4234 display_1.struct_size = sizeof(FlutterEngineDisplay);
4235 display_1.display_id = 1;
4236 display_1.single_display = false;
4237 display_1.refresh_rate = 20;
4238
4239 FlutterEngineDisplay display_2;
4240 display_2.struct_size = sizeof(FlutterEngineDisplay);
4241 display_2.display_id = 1;
4242 display_2.single_display = false;
4243 display_2.refresh_rate = 60;
4244
4245 std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
4246
4248 engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
4249 displays.size());
4250 ASSERT_NE(result, kSuccess);
4251
4252 FlutterWindowMetricsEvent event = {};
4253 event.struct_size = sizeof(event);
4254 event.width = 800;
4255 event.height = 600;
4256 event.pixel_ratio = 1.0;
4258 kSuccess);
4259
4260 latch.Wait();
4261}
4262
4263TEST_F(EmbedderTest, CompositorRenderTargetsNotRecycledWhenAvoidsCacheSet) {
4264 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4265
4267 builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
4268 builder.SetCompositor(/*avoid_backing_store_cache=*/true);
4269 builder.SetDartEntrypoint("render_targets_are_recycled");
4270 builder.SetRenderTargetType(
4272
4273 const unsigned num_frames = 8;
4274 const unsigned num_engine_layers = 10;
4275 const unsigned num_backing_stores = num_frames * num_engine_layers;
4276 fml::CountDownLatch latch(1 + num_frames); // 1 for native test signal.
4277
4278 context.AddNativeCallback("SignalNativeTest",
4280 latch.CountDown();
4281 }));
4282
4283 context.GetCompositor().SetPresentCallback(
4284 [&](FlutterViewId view_id, const FlutterLayer** layers,
4285 size_t layers_count) {
4286 ASSERT_EQ(layers_count, 20u);
4287 latch.CountDown();
4288 },
4289 /*one_shot=*/false);
4290
4291 auto engine = builder.LaunchEngine();
4292 ASSERT_TRUE(engine.is_valid());
4293
4294 FlutterWindowMetricsEvent event = {};
4295 event.struct_size = sizeof(event);
4296 event.width = 300;
4297 event.height = 200;
4298 event.pixel_ratio = 1.0;
4300 kSuccess);
4301
4302 latch.Wait();
4303
4304 ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(),
4305 num_backing_stores);
4306 // Killing the engine should collect all the frames.
4307 engine.reset();
4308 ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
4309}
4310
4311TEST_F(EmbedderTest, SnapshotRenderTargetScalesDownToDriverMax) {
4312 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4313
4315 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4316 builder.SetCompositor();
4317
4318 auto max_size = context.GetCompositor().GetGrContext()->maxRenderTargetSize();
4319
4320 context.AddIsolateCreateCallback([&]() {
4321 Dart_Handle snapshot_large_scene = Dart_GetField(
4322 Dart_RootLibrary(), tonic::ToDart("snapshot_large_scene"));
4323 tonic::DartInvoke(snapshot_large_scene, {tonic::ToDart<int64_t>(max_size)});
4324 });
4325
4327 context.AddNativeCallback(
4328 "SnapshotsCallback", CREATE_NATIVE_ENTRY(([&](Dart_NativeArguments args) {
4329 auto get_arg = [&args](int index) {
4330 Dart_Handle dart_image = Dart_GetNativeArgument(args, index);
4331 Dart_Handle internal_image =
4332 Dart_GetField(dart_image, tonic::ToDart("_image"));
4334 internal_image);
4335 };
4336
4337 CanvasImage* big_image = get_arg(0);
4338 ASSERT_EQ(big_image->width(), max_size);
4339 ASSERT_EQ(big_image->height(), max_size / 2);
4340
4341 CanvasImage* small_image = get_arg(1);
4342 ASSERT_TRUE(ImageMatchesFixture("snapshot_large_scene.png",
4343 small_image->image()->skia_image()));
4344
4345 latch.Signal();
4346 })));
4347
4348 UniqueEngine engine = builder.LaunchEngine();
4349 ASSERT_TRUE(engine.is_valid());
4350
4351 latch.Wait();
4352}
4353
4354TEST_F(EmbedderTest, ObjectsPostedViaPortsServicedOnSecondaryTaskHeap) {
4355 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4357 builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
4358 builder.SetDartEntrypoint("objects_can_be_posted");
4359
4360 // Synchronously acquire the send port from the Dart end. We will be using
4361 // this to send message. The Dart end will just echo those messages back to us
4362 // for inspection.
4365 context.AddNativeCallback("SignalNativeCount",
4369 event.Signal();
4370 }));
4371 auto engine = builder.LaunchEngine();
4372 ASSERT_TRUE(engine.is_valid());
4373 event.Wait();
4374 ASSERT_NE(port, 0);
4375
4376 using Trampoline = std::function<void(Dart_Handle message)>;
4377 Trampoline trampoline;
4378
4379 context.AddNativeCallback("SendObjectToNativeCode",
4381 FML_CHECK(trampoline);
4382 auto trampoline_copy = trampoline;
4383 trampoline = nullptr;
4384 trampoline_copy(Dart_GetNativeArgument(args, 0));
4385 }));
4386
4387 // Send a boolean value and assert that it's received by the right heap.
4388 {
4389 FlutterEngineDartObject object = {};
4391 object.bool_value = true;
4392 trampoline = [&](Dart_Handle handle) {
4393 ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(handle));
4395 EXPECT_EQ(task_grade, fml::TaskSourceGrade::kDartEventLoop);
4396 event.Signal();
4397 };
4398 ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
4399 kSuccess);
4400 event.Wait();
4401 }
4402}
4403
4404TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLTexture) {
4405 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4407 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4408 builder.SetCompositor();
4409 builder.SetRenderTargetType(
4411 builder.SetDartEntrypoint("invalid_backingstore");
4412
4413 class TestCollectOnce {
4414 public:
4415 // Collect() should only be called once
4416 void Collect() {
4417 ASSERT_FALSE(collected_);
4418 collected_ = true;
4419 }
4420
4421 private:
4422 bool collected_ = false;
4423 };
4425
4426 builder.GetCompositor().create_backing_store_callback =
4427 [](const FlutterBackingStoreConfig* config, //
4428 FlutterBackingStore* backing_store_out, //
4429 void* user_data //
4430 ) {
4431 backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
4432 // Deliberately set this to be invalid
4433 backing_store_out->user_data = nullptr;
4434 backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeTexture;
4435 backing_store_out->open_gl.texture.target = 0;
4436 backing_store_out->open_gl.texture.name = 0;
4437 backing_store_out->open_gl.texture.format = 0;
4438 static TestCollectOnce collect_once_user_data;
4439 collect_once_user_data = {};
4440 backing_store_out->open_gl.texture.user_data = &collect_once_user_data;
4441 backing_store_out->open_gl.texture.destruction_callback =
4442 [](void* user_data) {
4443 reinterpret_cast<TestCollectOnce*>(user_data)->Collect();
4444 };
4445 return true;
4446 };
4447
4448 context.AddNativeCallback(
4449 "SignalNativeTest",
4451 [&latch](Dart_NativeArguments args) { latch.Signal(); }));
4452
4453 auto engine = builder.LaunchEngine();
4454
4455 // Send a window metrics events so frames may be scheduled.
4456 FlutterWindowMetricsEvent event = {};
4457 event.struct_size = sizeof(event);
4458 event.width = 800;
4459 event.height = 600;
4460 event.pixel_ratio = 1.0;
4462 kSuccess);
4463 ASSERT_TRUE(engine.is_valid());
4464 latch.Wait();
4465}
4466
4467TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLFramebuffer) {
4468 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4470 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4471 builder.SetCompositor();
4472 builder.SetRenderTargetType(
4474 builder.SetDartEntrypoint("invalid_backingstore");
4475
4476 class TestCollectOnce {
4477 public:
4478 // Collect() should only be called once
4479 void Collect() {
4480 ASSERT_FALSE(collected_);
4481 collected_ = true;
4482 }
4483
4484 private:
4485 bool collected_ = false;
4486 };
4488
4489 builder.GetCompositor().create_backing_store_callback =
4490 [](const FlutterBackingStoreConfig* config, //
4491 FlutterBackingStore* backing_store_out, //
4492 void* user_data //
4493 ) {
4494 backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
4495 // Deliberately set this to be invalid
4496 backing_store_out->user_data = nullptr;
4497 backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
4498 backing_store_out->open_gl.framebuffer.target = 0;
4499 backing_store_out->open_gl.framebuffer.name = 0;
4500 static TestCollectOnce collect_once_user_data;
4501 collect_once_user_data = {};
4502 backing_store_out->open_gl.framebuffer.user_data =
4503 &collect_once_user_data;
4504 backing_store_out->open_gl.framebuffer.destruction_callback =
4505 [](void* user_data) {
4506 reinterpret_cast<TestCollectOnce*>(user_data)->Collect();
4507 };
4508 return true;
4509 };
4510
4511 context.AddNativeCallback(
4512 "SignalNativeTest",
4514 [&latch](Dart_NativeArguments args) { latch.Signal(); }));
4515
4516 auto engine = builder.LaunchEngine();
4517
4518 // Send a window metrics events so frames may be scheduled.
4519 FlutterWindowMetricsEvent event = {};
4520 event.struct_size = sizeof(event);
4521 event.width = 800;
4522 event.height = 600;
4523 event.pixel_ratio = 1.0;
4525 kSuccess);
4526 ASSERT_TRUE(engine.is_valid());
4527 latch.Wait();
4528}
4529
4530TEST_F(EmbedderTest, ExternalTextureGLRefreshedTooOften) {
4532 auto context = surface.GetGrContext();
4533
4534 typedef void (*glGenTexturesProc)(uint32_t n, uint32_t* textures);
4535 typedef void (*glFinishProc)();
4536
4537 glGenTexturesProc glGenTextures;
4538 glFinishProc glFinish;
4539
4540 glGenTextures = reinterpret_cast<glGenTexturesProc>(
4541 surface.GetProcAddress("glGenTextures"));
4542 glFinish = reinterpret_cast<glFinishProc>(surface.GetProcAddress("glFinish"));
4543
4544 uint32_t name;
4545 glGenTextures(1, &name);
4546
4547 bool resolve_called = false;
4548
4550 [&](int64_t, size_t, size_t) {
4551 resolve_called = true;
4552 auto res = std::make_unique<FlutterOpenGLTexture>();
4553 res->target = GL_TEXTURE_2D;
4554 res->name = name;
4555 res->format = GL_RGBA8;
4556 res->user_data = nullptr;
4557 res->destruction_callback = [](void*) {};
4558 res->width = res->height = 100;
4559 return res;
4560 });
4562
4563 auto skia_surface = surface.GetOnscreenSurface();
4564 DlSkCanvasAdapter canvas(skia_surface->getCanvas());
4565
4566 Texture* texture_ = &texture;
4568 .canvas = &canvas,
4569 .gr_context = context.get(),
4570 };
4571 texture_->Paint(ctx, SkRect::MakeXYWH(0, 0, 100, 100), false,
4573
4574 EXPECT_TRUE(resolve_called);
4575 resolve_called = false;
4576
4577 texture_->Paint(ctx, SkRect::MakeXYWH(0, 0, 100, 100), false,
4579
4580 EXPECT_FALSE(resolve_called);
4581
4582 texture_->MarkNewFrameAvailable();
4583 texture_->Paint(ctx, SkRect::MakeXYWH(0, 0, 100, 100), false,
4585
4586 EXPECT_TRUE(resolve_called);
4587
4588 glFinish();
4589}
4590
4593 PresentInfoReceivesFullScreenDamageWhenPopulateExistingDamageIsNotProvided) {
4594 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4595
4597 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4598 builder.SetDartEntrypoint("render_gradient_retained");
4599 builder.GetRendererConfig().open_gl.populate_existing_damage = nullptr;
4600
4601 auto engine = builder.LaunchEngine();
4602 ASSERT_TRUE(engine.is_valid());
4603
4605
4606 // First frame should be entirely rerendered.
4607 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
4608 [&](FlutterPresentInfo present_info) {
4609 const size_t num_rects = 1;
4610 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4611 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4612 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4613 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
4614 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
4615
4616 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4617 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
4618 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
4619 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
4620 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
4621
4622 latch.Signal();
4623 });
4624
4625 // Send a window metrics events so frames may be scheduled.
4626 FlutterWindowMetricsEvent event = {};
4627 event.struct_size = sizeof(event);
4628 event.width = 800;
4629 event.height = 600;
4630 event.pixel_ratio = 1.0;
4632 kSuccess);
4633 latch.Wait();
4634
4635 // Since populate_existing_damage is not provided, the partial repaint
4636 // functionality is actually disabled. So, the next frame should be entirely
4637 // new frame.
4638 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
4639 [&](FlutterPresentInfo present_info) {
4640 const size_t num_rects = 1;
4641 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4642 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4643 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4644 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
4645 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
4646
4647 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4648 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
4649 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
4650 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
4651 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
4652
4653 latch.Signal();
4654 });
4655
4657 kSuccess);
4658 latch.Wait();
4659}
4660
4662 PresentInfoReceivesJoinedDamageWhenExistingDamageContainsMultipleRects) {
4663 auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4664
4666 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4667 builder.SetDartEntrypoint("render_gradient_retained");
4668 builder.GetRendererConfig().open_gl.populate_existing_damage =
4669 [](void* context, const intptr_t id,
4670 FlutterDamage* existing_damage) -> void {
4671 return reinterpret_cast<EmbedderTestContextGL*>(context)
4672 ->GLPopulateExistingDamage(id, existing_damage);
4673 };
4674
4675 // Return existing damage as the entire screen on purpose.
4676 static_cast<EmbedderTestContextGL&>(context)
4677 .SetGLPopulateExistingDamageCallback(
4678 [](const intptr_t id, FlutterDamage* existing_damage_ptr) {
4679 const size_t num_rects = 2;
4680 // The array must be valid after the callback returns.
4681 static FlutterRect existing_damage_rects[num_rects] = {
4682 FlutterRect{100, 150, 200, 250},
4683 FlutterRect{200, 250, 300, 350},
4684 };
4685 existing_damage_ptr->num_rects = num_rects;
4686 existing_damage_ptr->damage = existing_damage_rects;
4687 });
4688
4689 auto engine = builder.LaunchEngine();
4690 ASSERT_TRUE(engine.is_valid());
4691
4693
4694 // First frame should be entirely rerendered.
4695 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
4696 [&](FlutterPresentInfo present_info) {
4697 const size_t num_rects = 1;
4698 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4699 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4700 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4701 ASSERT_EQ(present_info.frame_damage.damage->right, 800);
4702 ASSERT_EQ(present_info.frame_damage.damage->bottom, 600);
4703
4704 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4705 ASSERT_EQ(present_info.buffer_damage.damage->left, 0);
4706 ASSERT_EQ(present_info.buffer_damage.damage->top, 0);
4707 ASSERT_EQ(present_info.buffer_damage.damage->right, 800);
4708 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600);
4709
4710 latch.Signal();
4711 });
4712
4713 // Send a window metrics events so frames may be scheduled.
4714 FlutterWindowMetricsEvent event = {};
4715 event.struct_size = sizeof(event);
4716 event.width = 800;
4717 event.height = 600;
4718 event.pixel_ratio = 1.0;
4720 kSuccess);
4721 latch.Wait();
4722
4723 // Because it's the same as the first frame, the second frame damage should
4724 // be empty but, because there was a full existing buffer damage, the buffer
4725 // damage should be the entire screen.
4726 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
4727 [&](FlutterPresentInfo present_info) {
4728 const size_t num_rects = 1;
4729 ASSERT_EQ(present_info.frame_damage.num_rects, num_rects);
4730 ASSERT_EQ(present_info.frame_damage.damage->left, 0);
4731 ASSERT_EQ(present_info.frame_damage.damage->top, 0);
4732 ASSERT_EQ(present_info.frame_damage.damage->right, 0);
4733 ASSERT_EQ(present_info.frame_damage.damage->bottom, 0);
4734
4735 ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects);
4736 ASSERT_EQ(present_info.buffer_damage.damage->left, 100);
4737 ASSERT_EQ(present_info.buffer_damage.damage->top, 150);
4738 ASSERT_EQ(present_info.buffer_damage.damage->right, 300);
4739 ASSERT_EQ(present_info.buffer_damage.damage->bottom, 350);
4740
4741 latch.Signal();
4742 });
4743
4745 kSuccess);
4746 latch.Wait();
4747}
4748
4749TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
4750 EmbedderTestContextGL& context = static_cast<EmbedderTestContextGL&>(
4751 GetEmbedderContext(EmbedderTestContextType::kOpenGLContext));
4753
4754 bool present_called = false;
4755 static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
4756 [&present_called](FlutterPresentInfo present_info) {
4757 present_called = true;
4758 });
4759
4760 builder.AddCommandLineArgument("--enable-impeller");
4761 builder.SetDartEntrypoint("render_impeller_gl_test");
4762 builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
4763 builder.SetCompositor();
4764 builder.SetRenderTargetType(
4766
4767 auto rendered_scene = context.GetNextSceneImage();
4768
4769 auto engine = builder.LaunchEngine();
4770 ASSERT_TRUE(engine.is_valid());
4771
4772 // Bind to an arbitrary FBO in order to verify that Impeller binds to the
4773 // provided FBO during rendering.
4774 typedef void (*glGenFramebuffersProc)(GLsizei n, GLuint* ids);
4775 typedef void (*glBindFramebufferProc)(GLenum target, GLuint framebuffer);
4776 auto glGenFramebuffers = reinterpret_cast<glGenFramebuffersProc>(
4777 context.GLGetProcAddress("glGenFramebuffers"));
4778 auto glBindFramebuffer = reinterpret_cast<glBindFramebufferProc>(
4779 context.GLGetProcAddress("glBindFramebuffer"));
4781 fml::AutoResetWaitableEvent raster_event;
4782 shell.GetTaskRunners().GetRasterTaskRunner()->PostTask([&] {
4783 GLuint fbo;
4784 glGenFramebuffers(1, &fbo);
4785 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4786 raster_event.Signal();
4787 });
4788 raster_event.Wait();
4789
4790 // Send a window metrics events so frames may be scheduled.
4791 FlutterWindowMetricsEvent event = {};
4792 event.struct_size = sizeof(event);
4793 event.width = 800;
4794 event.height = 600;
4795 event.pixel_ratio = 1.0;
4797 kSuccess);
4798
4799 ASSERT_TRUE(ImageMatchesFixture(
4801 "impeller_gl_test.png"),
4802 rendered_scene));
4803
4804 // The scene will be rendered by the compositor, and the surface present
4805 // callback should not be invoked.
4806 ASSERT_FALSE(present_called);
4807}
4808
4810 EmbedderTestGlVk,
4814
4815} // namespace testing
4816} // namespace flutter
4817
4818// NOLINTEND(clang-analyzer-core.StackAddressEscape)
const char * backend
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
std::unique_ptr< flutter::PlatformViewIOS > platform_view
constexpr SkColor SK_ColorMAGENTA
Definition: SkColor.h:147
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
GLenum type
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:263
SkMatrix & preRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:462
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:315
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.h:180
sk_sp< DlImage > image() const
Definition: image.h:42
Backend implementation of |DlCanvas| for |SkCanvas|.
Definition: dl_sk_canvas.h:20
std::function< std::unique_ptr< FlutterOpenGLTexture >(int64_t, size_t, size_t)> ExternalTextureCallback
size_t GetCachedEntriesCount() const
virtual void MarkNewFrameAvailable()=0
virtual void Paint(PaintContext &context, const SkRect &bounds, bool freeze, const DlImageSampling sampling)=0
std::future< sk_sp< SkImage > > GetNextSceneImage()
A task runner that we expect the embedder to provide but whose implementation is a real FML task runn...
static TaskSourceGrade GetCurrentTaskSourceGrade()
const Paint & paint
Definition: color_source.cc:38
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
struct _Dart_NativeArguments * Dart_NativeArguments
Definition: dart_api.h:3019
DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t *length)
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name)
DART_EXPORT Dart_Handle Dart_RootLibrary(void)
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 engine via the FlutterTa...
Definition: embedder.cc:2959
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterWindowMetricsEvent *flutter_metrics)
Definition: embedder.cc:2320
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:3067
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:2297
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:2309
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:3252
FlutterEngineResult FlutterEngineRunInitialized(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Runs an initialized engine instance. An engine can be initialized via FlutterEngineInitialize....
Definition: embedder.cc:2154
@ kFlutterLayerContentTypePlatformView
Indicates that the contents of this layer are determined by the embedder.
Definition: embedder.h:1795
@ kFlutterLayerContentTypeBackingStore
Definition: embedder.h:1793
@ kFlutterPlatformViewMutationTypeClipRoundedRect
Definition: embedder.h:1697
@ kFlutterPlatformViewMutationTypeClipRect
Definition: embedder.h:1694
@ kFlutterPlatformViewMutationTypeTransformation
Definition: embedder.h:1700
@ kFlutterPlatformViewMutationTypeOpacity
Definition: embedder.h:1691
@ kFlutterEngineDartObjectTypeString
Definition: embedder.h:2018
@ kFlutterEngineDartObjectTypeBool
Definition: embedder.h:2014
@ kFlutterEngineDartObjectTypeDouble
Definition: embedder.h:2017
@ kFlutterEngineDartObjectTypeInt32
Definition: embedder.h:2015
@ kFlutterEngineDartObjectTypeBuffer
Definition: embedder.h:2021
@ kFlutterEngineDartObjectTypeInt64
Definition: embedder.h:2016
@ kFlutterEngineDartObjectTypeNull
Definition: embedder.h:2013
FlutterEngineResult
Definition: embedder.h:72
@ kSuccess
Definition: embedder.h:73
@ kFlutterEngineDisplaysUpdateTypeStartup
Definition: embedder.h:2006
int64_t FlutterEngineDartPort
Definition: embedder.h:2010
@ kFlutterOpenGLTargetTypeFramebuffer
Definition: embedder.h:306
@ kFlutterOpenGLTargetTypeTexture
Definition: embedder.h:303
@ kFlutterBackingStoreTypeSoftware
Specified an software allocation for Flutter to render into using the CPU.
Definition: embedder.h:1744
@ kFlutterBackingStoreTypeOpenGL
Definition: embedder.h:1742
FlutterSize FlutterSizeMake(double width, double height)
FlutterTransformation FlutterTransformationMake(const SkMatrix &matrix)
FlutterRect FlutterRectMake(const SkRect &rect)
SkMatrix SkMatrixMake(const FlutterTransformation &xformation)
FlutterRect FlutterRectMakeLTRB(double l, double t, double r, double b)
FlutterPoint FlutterPointMake(double x, double y)
SkRect SkRectMake(const FlutterRect &rect)
flutter::EmbedderEngine * ToEmbedderEngine(const FlutterEngine &engine)
FlutterRoundedRect FlutterRoundedRectMake(const SkRRect &rect)
FlutterEngine engine
Definition: main.cc:68
VkSurfaceKHR surface
Definition: main.cc:49
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
GAsyncResult * result
uint32_t * target
#define FML_CHECK(condition)
Definition: logging.h:85
Dart_NativeFunction function
Definition: fuchsia.cc:51
size_t length
Win32Message message
FlTexture * texture
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
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:79
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.
testing::EmbedderTest EmbedderTest
INSTANTIATE_TEST_SUITE_P(EmbedderTestGlVk, EmbedderTestMultiBackend, ::testing::Values(EmbedderTestContextType::kOpenGLContext, EmbedderTestContextType::kVulkanContext))
TEST_P(DlGoldenTest, TextBlurMaskFilterRespectCTM)
SkMatrix GetTotalMutationTransformationMatrix(const FlutterPlatformViewMutation **mutations, size_t count)
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...
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 vm service port
Definition: switches.h:87
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
int64_t FlutterViewId
Definition: flutter_view.h:13
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 vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
Definition: setup.py:1
Dart_Handle ToDart(const T &object)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:20
FlutterBackingStoreType type
Specifies the type of backing store.
Definition: embedder.h:1762
FlutterOpenGLBackingStore open_gl
The description of the OpenGL backing store.
Definition: embedder.h:1768
FlutterSoftwareBackingStore software
The description of the software backing store.
Definition: embedder.h:1770
size_t struct_size
The size of this struct. Must be sizeof(FlutterBackingStore).
Definition: embedder.h:1756
A structure to represent a damage region.
Definition: embedder.h:460
size_t num_rects
The number of rectangles within the damage region.
Definition: embedder.h:464
FlutterRect * damage
The actual damage region(s) in question.
Definition: embedder.h:466
FlutterEngineDartObjectType type
Definition: embedder.h:2069
size_t struct_size
This size of this struct. Must be sizeof(FlutterDisplay).
Definition: embedder.h:1973
FlutterEngineDisplayId display_id
Definition: embedder.h:1975
FlutterUIntSize size
The size of the surface that will be backed by the fbo.
Definition: embedder.h:479
FlutterPoint offset
Definition: embedder.h:1835
FlutterLayerContentType type
Definition: embedder.h:1824
const FlutterBackingStore * backing_store
Definition: embedder.h:1828
FlutterBackingStorePresentInfo * backing_store_present_info
Definition: embedder.h:1841
const FlutterPlatformView * platform_view
Definition: embedder.h:1831
size_t struct_size
This size of this struct. Must be sizeof(FlutterLayer).
Definition: embedder.h:1821
FlutterSize size
The size of the layer (in physical pixels).
Definition: embedder.h:1837
FlutterOpenGLTargetType type
Definition: embedder.h:1610
FlutterTransformation transformation
Definition: embedder.h:1710
FlutterPlatformViewMutationType type
The type of the mutation described by the subsequent union.
Definition: embedder.h:1705
FlutterRoundedRect clip_rounded_rect
Definition: embedder.h:1709
FlutterPlatformViewIdentifier identifier
Definition: embedder.h:1720
uint32_t fbo_id
Id of the fbo backing the surface that was presented.
Definition: embedder.h:501
FlutterDamage frame_damage
Damage representing the area that the compositor needs to render.
Definition: embedder.h:503
FlutterDamage buffer_damage
Damage used to set the buffer's damage region.
Definition: embedder.h:505
A structure to represent a rectangle.
Definition: embedder.h:437
double bottom
Definition: embedder.h:441
double top
Definition: embedder.h:439
double left
Definition: embedder.h:438
double right
Definition: embedder.h:440
A region represented by a collection of non-overlapping rectangles.
Definition: embedder.h:1799
size_t struct_size
The size of this struct. Must be sizeof(FlutterRegion).
Definition: embedder.h:1801
double height
Definition: embedder.h:425
double width
Definition: embedder.h:424
size_t row_bytes
The number of bytes in a single row of the allocation.
Definition: embedder.h:1625
size_t height
The number of rows in the allocation.
Definition: embedder.h:1627
uint32_t height
Definition: embedder.h:433
uint32_t width
Definition: embedder.h:432
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition: embedder.h:843
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
#define CREATE_NATIVE_ENTRY(native_entry)
void * user_data
const uintptr_t id
static void setup(SkCanvas *canvas, SkPaint *paint, const SkBitmap &bm, SkFilterMode fm, SkTileMode tmx, SkTileMode tmy)
Definition: tilemodes.cpp:52
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678