Flutter Engine
embedder_unittests_gl.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #define FML_USED_ON_EMBEDDER
6 
7 #include <string>
8 #include <vector>
9 
10 #include "embedder.h"
11 #include "embedder_engine.h"
12 #include "flutter/flow/raster_cache.h"
13 #include "flutter/fml/file.h"
14 #include "flutter/fml/make_copyable.h"
15 #include "flutter/fml/mapping.h"
16 #include "flutter/fml/message_loop.h"
17 #include "flutter/fml/message_loop_task_queues.h"
18 #include "flutter/fml/paths.h"
19 #include "flutter/fml/synchronization/count_down_latch.h"
20 #include "flutter/fml/synchronization/waitable_event.h"
21 #include "flutter/fml/task_source.h"
22 #include "flutter/fml/thread.h"
23 #include "flutter/lib/ui/painting/image.h"
24 #include "flutter/runtime/dart_vm.h"
25 #include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
26 #include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"
27 #include "flutter/shell/platform/embedder/tests/embedder_test.h"
28 #include "flutter/shell/platform/embedder/tests/embedder_test_context_gl.h"
29 #include "flutter/shell/platform/embedder/tests/embedder_unittests_util.h"
30 #include "flutter/testing/assertions_skia.h"
31 #include "flutter/testing/test_gl_surface.h"
32 #include "flutter/testing/testing.h"
33 #include "third_party/skia/include/core/SkSurface.h"
34 #include "third_party/skia/src/gpu/gl/GrGLDefines.h"
36 
37 namespace flutter {
38 namespace testing {
39 
41 
42 TEST_F(EmbedderTest, CanCreateOpenGLRenderingEngine) {
43  EmbedderConfigBuilder builder(
44  GetEmbedderContext(EmbedderTestContextType::kOpenGLContext));
45  builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
46  auto engine = builder.LaunchEngine();
47  ASSERT_TRUE(engine.is_valid());
48 }
49 
50 //------------------------------------------------------------------------------
51 /// If an incorrectly configured compositor is set on the engine, the engine
52 /// must fail to launch instead of failing to render a frame at a later point in
53 /// time.
54 ///
56  MustPreventEngineLaunchWhenRequiredCompositorArgsAreAbsent) {
57  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
58  EmbedderConfigBuilder builder(context);
59  builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
60  builder.SetCompositor();
61  builder.GetCompositor().create_backing_store_callback = nullptr;
62  builder.GetCompositor().collect_backing_store_callback = nullptr;
63  builder.GetCompositor().present_layers_callback = nullptr;
64  auto engine = builder.LaunchEngine();
65  ASSERT_FALSE(engine.is_valid());
66 }
67 
68 //------------------------------------------------------------------------------
69 /// Must be able to render to a custom compositor whose render targets are fully
70 /// complete OpenGL textures.
71 ///
72 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) {
73  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
74 
75  EmbedderConfigBuilder builder(context);
76  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
77  builder.SetCompositor();
78  builder.SetDartEntrypoint("can_composite_platform_views");
79 
80  builder.SetRenderTargetType(
82 
83  fml::CountDownLatch latch(3);
84  context.GetCompositor().SetNextPresentCallback(
85  [&](const FlutterLayer** layers, size_t layers_count) {
86  ASSERT_EQ(layers_count, 3u);
87 
88  {
89  FlutterBackingStore backing_store = *layers[0]->backing_store;
90  backing_store.struct_size = sizeof(backing_store);
91  backing_store.type = kFlutterBackingStoreTypeOpenGL;
92  backing_store.did_update = true;
94 
95  FlutterLayer layer = {};
96  layer.struct_size = sizeof(layer);
98  layer.backing_store = &backing_store;
99  layer.size = FlutterSizeMake(800.0, 600.0);
100  layer.offset = FlutterPointMake(0, 0);
101 
102  ASSERT_EQ(*layers[0], layer);
103  }
104 
105  {
107  platform_view.struct_size = sizeof(platform_view);
108  platform_view.identifier = 42;
109 
110  FlutterLayer layer = {};
111  layer.struct_size = sizeof(layer);
113  layer.platform_view = &platform_view;
114  layer.size = FlutterSizeMake(123.0, 456.0);
115  layer.offset = FlutterPointMake(1.0, 2.0);
116 
117  ASSERT_EQ(*layers[1], layer);
118  }
119 
120  {
121  FlutterBackingStore backing_store = *layers[2]->backing_store;
122  backing_store.struct_size = sizeof(backing_store);
123  backing_store.type = kFlutterBackingStoreTypeOpenGL;
124  backing_store.did_update = true;
126 
127  FlutterLayer layer = {};
128  layer.struct_size = sizeof(layer);
130  layer.backing_store = &backing_store;
131  layer.size = FlutterSizeMake(800.0, 600.0);
132  layer.offset = FlutterPointMake(0.0, 0.0);
133 
134  ASSERT_EQ(*layers[2], layer);
135  }
136 
137  latch.CountDown();
138  });
139 
140  context.AddNativeCallback(
141  "SignalNativeTest",
143  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
144 
145  auto engine = builder.LaunchEngine();
146 
147  // Send a window metrics events so frames may be scheduled.
148  FlutterWindowMetricsEvent event = {};
149  event.struct_size = sizeof(event);
150  event.width = 800;
151  event.height = 600;
152  event.pixel_ratio = 1.0;
154  kSuccess);
155  ASSERT_TRUE(engine.is_valid());
156 
157  latch.Wait();
158 }
159 
160 //------------------------------------------------------------------------------
161 /// Layers in a hierarchy containing a platform view should not be cached. The
162 /// other layers in the hierarchy should be, however.
163 TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) {
164  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
165 
166  EmbedderConfigBuilder builder(context);
167  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
168  builder.SetCompositor();
169  builder.SetDartEntrypoint("can_composite_platform_views_with_opacity");
170 
171  builder.SetRenderTargetType(
173 
174  fml::CountDownLatch setup(3);
175  fml::CountDownLatch verify(1);
176 
177  context.GetCompositor().SetNextPresentCallback(
178  [&](const FlutterLayer** layers, size_t layers_count) {
179  ASSERT_EQ(layers_count, 3u);
180 
181  {
182  FlutterBackingStore backing_store = *layers[0]->backing_store;
183  backing_store.struct_size = sizeof(backing_store);
184  backing_store.type = kFlutterBackingStoreTypeOpenGL;
185  backing_store.did_update = true;
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);
194 
195  ASSERT_EQ(*layers[0], layer);
196  }
197 
198  {
200  platform_view.struct_size = sizeof(platform_view);
201  platform_view.identifier = 42;
202 
203  FlutterLayer layer = {};
204  layer.struct_size = sizeof(layer);
206  layer.platform_view = &platform_view;
207  layer.size = FlutterSizeMake(123.0, 456.0);
208  layer.offset = FlutterPointMake(1.0, 2.0);
209 
210  ASSERT_EQ(*layers[1], layer);
211  }
212 
213  {
214  FlutterBackingStore backing_store = *layers[2]->backing_store;
215  backing_store.struct_size = sizeof(backing_store);
216  backing_store.type = kFlutterBackingStoreTypeOpenGL;
217  backing_store.did_update = true;
219 
220  FlutterLayer layer = {};
221  layer.struct_size = sizeof(layer);
223  layer.backing_store = &backing_store;
224  layer.size = FlutterSizeMake(800.0, 600.0);
225  layer.offset = FlutterPointMake(0.0, 0.0);
226 
227  ASSERT_EQ(*layers[2], layer);
228  }
229 
230  setup.CountDown();
231  });
232 
233  context.AddNativeCallback(
234  "SignalNativeTest",
236  [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
237 
238  UniqueEngine engine = builder.LaunchEngine();
239 
240  // Send a window metrics events so frames may be scheduled.
241  FlutterWindowMetricsEvent event = {};
242  event.struct_size = sizeof(event);
243  event.width = 800;
244  event.height = 600;
245  event.pixel_ratio = 1.0;
246  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
247  kSuccess);
248  ASSERT_TRUE(engine.is_valid());
249 
250  setup.Wait();
251  const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
253  const flutter::RasterCache& raster_cache =
254  shell.GetRasterizer()->compositor_context()->raster_cache();
255  // 3 layers total, but one of them had the platform view. So the cache
256  // should only have 2 entries.
257  ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 2u);
258  verify.CountDown();
259  });
260 
261  verify.Wait();
262 }
263 
264 //------------------------------------------------------------------------------
265 /// The RasterCache should normally be enabled.
266 ///
267 TEST_F(EmbedderTest, RasterCacheEnabled) {
268  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
269 
270  EmbedderConfigBuilder builder(context);
271  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
272  builder.SetCompositor();
273  builder.SetDartEntrypoint("can_composite_with_opacity");
274 
275  builder.SetRenderTargetType(
277 
278  fml::CountDownLatch setup(3);
279  fml::CountDownLatch verify(1);
280 
281  context.GetCompositor().SetNextPresentCallback(
282  [&](const FlutterLayer** layers, size_t layers_count) {
283  ASSERT_EQ(layers_count, 1u);
284 
285  {
286  FlutterBackingStore backing_store = *layers[0]->backing_store;
287  backing_store.struct_size = sizeof(backing_store);
288  backing_store.type = kFlutterBackingStoreTypeOpenGL;
289  backing_store.did_update = true;
291 
292  FlutterLayer layer = {};
293  layer.struct_size = sizeof(layer);
295  layer.backing_store = &backing_store;
296  layer.size = FlutterSizeMake(800.0, 600.0);
297  layer.offset = FlutterPointMake(0, 0);
298 
299  ASSERT_EQ(*layers[0], layer);
300  }
301 
302  setup.CountDown();
303  });
304 
305  context.AddNativeCallback(
306  "SignalNativeTest",
308  [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
309 
310  UniqueEngine engine = builder.LaunchEngine();
311 
312  // Send a window metrics events so frames may be scheduled.
313  FlutterWindowMetricsEvent event = {};
314  event.struct_size = sizeof(event);
315  event.width = 800;
316  event.height = 600;
317  event.pixel_ratio = 1.0;
318  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
319  kSuccess);
320  ASSERT_TRUE(engine.is_valid());
321 
322  setup.Wait();
323  const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
325  const flutter::RasterCache& raster_cache =
326  shell.GetRasterizer()->compositor_context()->raster_cache();
327  ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 1u);
328  verify.CountDown();
329  });
330 
331  verify.Wait();
332 }
333 
334 //------------------------------------------------------------------------------
335 /// Must be able to render using a custom compositor whose render targets for
336 /// the individual layers are OpenGL textures.
337 ///
338 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) {
339  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
340 
341  EmbedderConfigBuilder builder(context);
342  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
343  builder.SetCompositor();
344  builder.SetDartEntrypoint("can_composite_platform_views");
345 
346  builder.SetRenderTargetType(
348 
349  fml::CountDownLatch latch(3);
350  context.GetCompositor().SetNextPresentCallback(
351  [&](const FlutterLayer** layers, size_t layers_count) {
352  ASSERT_EQ(layers_count, 3u);
353 
354  {
355  FlutterBackingStore backing_store = *layers[0]->backing_store;
356  backing_store.struct_size = sizeof(backing_store);
357  backing_store.type = kFlutterBackingStoreTypeOpenGL;
358  backing_store.did_update = true;
360 
361  FlutterLayer layer = {};
362  layer.struct_size = sizeof(layer);
364  layer.backing_store = &backing_store;
365  layer.size = FlutterSizeMake(800.0, 600.0);
366  layer.offset = FlutterPointMake(0, 0);
367 
368  ASSERT_EQ(*layers[0], layer);
369  }
370 
371  {
373  platform_view.struct_size = sizeof(platform_view);
374  platform_view.identifier = 42;
375 
376  FlutterLayer layer = {};
377  layer.struct_size = sizeof(layer);
379  layer.platform_view = &platform_view;
380  layer.size = FlutterSizeMake(123.0, 456.0);
381  layer.offset = FlutterPointMake(1.0, 2.0);
382 
383  ASSERT_EQ(*layers[1], layer);
384  }
385 
386  {
387  FlutterBackingStore backing_store = *layers[2]->backing_store;
388  backing_store.struct_size = sizeof(backing_store);
389  backing_store.type = kFlutterBackingStoreTypeOpenGL;
390  backing_store.did_update = true;
392 
393  FlutterLayer layer = {};
394  layer.struct_size = sizeof(layer);
396  layer.backing_store = &backing_store;
397  layer.size = FlutterSizeMake(800.0, 600.0);
398  layer.offset = FlutterPointMake(0.0, 0.0);
399 
400  ASSERT_EQ(*layers[2], layer);
401  }
402 
403  latch.CountDown();
404  });
405 
406  context.AddNativeCallback(
407  "SignalNativeTest",
409  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
410 
411  auto engine = builder.LaunchEngine();
412 
413  // Send a window metrics events so frames may be scheduled.
414  FlutterWindowMetricsEvent event = {};
415  event.struct_size = sizeof(event);
416  event.width = 800;
417  event.height = 600;
418  event.pixel_ratio = 1.0;
420  kSuccess);
421  ASSERT_TRUE(engine.is_valid());
422 
423  latch.Wait();
424 }
425 
426 //------------------------------------------------------------------------------
427 /// Must be able to render using a custom compositor whose render target for the
428 /// individual layers are software buffers.
429 ///
430 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) {
431  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
432 
433  EmbedderConfigBuilder builder(context);
434  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
435  builder.SetCompositor();
436  builder.SetDartEntrypoint("can_composite_platform_views");
437 
438  builder.SetRenderTargetType(
440 
441  fml::CountDownLatch latch(3);
442  context.GetCompositor().SetNextPresentCallback(
443  [&](const FlutterLayer** layers, size_t layers_count) {
444  ASSERT_EQ(layers_count, 3u);
445 
446  {
447  FlutterBackingStore backing_store = *layers[0]->backing_store;
448  backing_store.struct_size = sizeof(backing_store);
449  backing_store.type = kFlutterBackingStoreTypeSoftware;
450  backing_store.did_update = true;
451  ASSERT_FLOAT_EQ(
452  backing_store.software.row_bytes * backing_store.software.height,
453  800 * 4 * 600.0);
454 
455  FlutterLayer layer = {};
456  layer.struct_size = sizeof(layer);
458  layer.backing_store = &backing_store;
459  layer.size = FlutterSizeMake(800.0, 600.0);
460  layer.offset = FlutterPointMake(0, 0);
461 
462  ASSERT_EQ(*layers[0], layer);
463  }
464 
465  {
467  platform_view.struct_size = sizeof(platform_view);
468  platform_view.identifier = 42;
469 
470  FlutterLayer layer = {};
471  layer.struct_size = sizeof(layer);
473  layer.platform_view = &platform_view;
474  layer.size = FlutterSizeMake(123.0, 456.0);
475  layer.offset = FlutterPointMake(1.0, 2.0);
476 
477  ASSERT_EQ(*layers[1], layer);
478  }
479 
480  {
481  FlutterBackingStore backing_store = *layers[2]->backing_store;
482  backing_store.struct_size = sizeof(backing_store);
483  backing_store.type = kFlutterBackingStoreTypeSoftware;
484  backing_store.did_update = true;
485  FlutterLayer layer = {};
486  layer.struct_size = sizeof(layer);
488  layer.backing_store = &backing_store;
489  layer.size = FlutterSizeMake(800.0, 600.0);
490  layer.offset = FlutterPointMake(0.0, 0.0);
491 
492  ASSERT_EQ(*layers[2], layer);
493  }
494 
495  latch.CountDown();
496  });
497 
498  context.AddNativeCallback(
499  "SignalNativeTest",
501  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
502 
503  auto engine = builder.LaunchEngine();
504 
505  // Send a window metrics events so frames may be scheduled.
506  FlutterWindowMetricsEvent event = {};
507  event.struct_size = sizeof(event);
508  event.width = 800;
509  event.height = 600;
510  event.pixel_ratio = 1.0;
512  kSuccess);
513  ASSERT_TRUE(engine.is_valid());
514 
515  latch.Wait();
516 }
517 
518 //------------------------------------------------------------------------------
519 /// Test the layer structure and pixels rendered when using a custom compositor.
520 ///
521 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) {
522  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
523 
524  EmbedderConfigBuilder builder(context);
525  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
526  builder.SetCompositor();
527  builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
528 
529  builder.SetRenderTargetType(
531 
532  fml::CountDownLatch latch(5);
533 
534  auto scene_image = context.GetNextSceneImage();
535 
536  context.GetCompositor().SetNextPresentCallback(
537  [&](const FlutterLayer** layers, size_t layers_count) {
538  ASSERT_EQ(layers_count, 5u);
539 
540  // Layer Root
541  {
542  FlutterBackingStore backing_store = *layers[0]->backing_store;
543  backing_store.type = kFlutterBackingStoreTypeOpenGL;
544  backing_store.did_update = true;
546 
547  FlutterLayer layer = {};
548  layer.struct_size = sizeof(layer);
550  layer.backing_store = &backing_store;
551  layer.size = FlutterSizeMake(800.0, 600.0);
552  layer.offset = FlutterPointMake(0.0, 0.0);
553 
554  ASSERT_EQ(*layers[0], layer);
555  }
556 
557  // Layer 1
558  {
560  platform_view.struct_size = sizeof(platform_view);
561  platform_view.identifier = 1;
562 
563  FlutterLayer layer = {};
564  layer.struct_size = sizeof(layer);
566  layer.platform_view = &platform_view;
567  layer.size = FlutterSizeMake(50.0, 150.0);
568  layer.offset = FlutterPointMake(20.0, 20.0);
569 
570  ASSERT_EQ(*layers[1], layer);
571  }
572 
573  // Layer 2
574  {
575  FlutterBackingStore backing_store = *layers[2]->backing_store;
576  backing_store.type = kFlutterBackingStoreTypeOpenGL;
577  backing_store.did_update = true;
579 
580  FlutterLayer layer = {};
581  layer.struct_size = sizeof(layer);
583  layer.backing_store = &backing_store;
584  layer.size = FlutterSizeMake(800.0, 600.0);
585  layer.offset = FlutterPointMake(0.0, 0.0);
586 
587  ASSERT_EQ(*layers[2], layer);
588  }
589 
590  // Layer 3
591  {
593  platform_view.struct_size = sizeof(platform_view);
594  platform_view.identifier = 2;
595 
596  FlutterLayer layer = {};
597  layer.struct_size = sizeof(layer);
599  layer.platform_view = &platform_view;
600  layer.size = FlutterSizeMake(50.0, 150.0);
601  layer.offset = FlutterPointMake(40.0, 40.0);
602 
603  ASSERT_EQ(*layers[3], layer);
604  }
605 
606  // Layer 4
607  {
608  FlutterBackingStore backing_store = *layers[4]->backing_store;
609  backing_store.type = kFlutterBackingStoreTypeOpenGL;
610  backing_store.did_update = true;
612 
613  FlutterLayer layer = {};
614  layer.struct_size = sizeof(layer);
616  layer.backing_store = &backing_store;
617  layer.size = FlutterSizeMake(800.0, 600.0);
618  layer.offset = FlutterPointMake(0.0, 0.0);
619 
620  ASSERT_EQ(*layers[4], layer);
621  }
622 
623  latch.CountDown();
624  });
625 
626  context.GetCompositor().SetPlatformViewRendererCallback(
627  [&](const FlutterLayer& layer,
628  GrDirectContext* context) -> sk_sp<SkImage> {
629  auto surface = CreateRenderSurface(layer, context);
630  auto canvas = surface->getCanvas();
631  FML_CHECK(canvas != nullptr);
632 
633  switch (layer.platform_view->identifier) {
634  case 1: {
635  SkPaint paint;
636  // See dart test for total order.
637  paint.setColor(SK_ColorGREEN);
638  paint.setAlpha(127);
639  const auto& rect =
640  SkRect::MakeWH(layer.size.width, layer.size.height);
641  canvas->drawRect(rect, paint);
642  latch.CountDown();
643  } break;
644  case 2: {
645  SkPaint paint;
646  // See dart test for total order.
647  paint.setColor(SK_ColorMAGENTA);
648  paint.setAlpha(127);
649  const auto& rect =
650  SkRect::MakeWH(layer.size.width, layer.size.height);
651  canvas->drawRect(rect, paint);
652  latch.CountDown();
653  } break;
654  default:
655  // Asked to render an unknown platform view.
656  FML_CHECK(false)
657  << "Test was asked to composite an unknown platform view.";
658  }
659 
660  return surface->makeImageSnapshot();
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  ASSERT_TRUE(ImageMatchesFixture("compositor.png", scene_image));
683 
684  // There should no present calls on the root surface.
685  ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
686 }
687 
688 //------------------------------------------------------------------------------
689 /// Custom compositor must play nicely with a custom task runner. The raster
690 /// thread merging mechanism must not interfere with the custom compositor.
691 ///
692 TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) {
693  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
694 
695  EmbedderConfigBuilder builder(context);
696 
697  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
698  builder.SetCompositor();
699  builder.SetDartEntrypoint("can_composite_platform_views");
700 
701  auto platform_task_runner = CreateNewThread("test_platform_thread");
702  static std::mutex engine_mutex;
704  fml::AutoResetWaitableEvent sync_latch;
705 
706  EmbedderTestTaskRunner test_task_runner(
707  platform_task_runner, [&](FlutterTask task) {
708  std::scoped_lock lock(engine_mutex);
709  if (!engine.is_valid()) {
710  return;
711  }
712  ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
713  });
714 
715  builder.SetRenderTargetType(
717 
718  fml::CountDownLatch latch(3);
719  context.GetCompositor().SetNextPresentCallback(
720  [&](const FlutterLayer** layers, size_t layers_count) {
721  ASSERT_EQ(layers_count, 3u);
722 
723  {
724  FlutterBackingStore backing_store = *layers[0]->backing_store;
725  backing_store.struct_size = sizeof(backing_store);
726  backing_store.type = kFlutterBackingStoreTypeOpenGL;
727  backing_store.did_update = true;
729 
730  FlutterLayer layer = {};
731  layer.struct_size = sizeof(layer);
733  layer.backing_store = &backing_store;
734  layer.size = FlutterSizeMake(800.0, 600.0);
735  layer.offset = FlutterPointMake(0, 0);
736 
737  ASSERT_EQ(*layers[0], layer);
738  }
739 
740  {
742  platform_view.struct_size = sizeof(platform_view);
743  platform_view.identifier = 42;
744 
745  FlutterLayer layer = {};
746  layer.struct_size = sizeof(layer);
748  layer.platform_view = &platform_view;
749  layer.size = FlutterSizeMake(123.0, 456.0);
750  layer.offset = FlutterPointMake(1.0, 2.0);
751 
752  ASSERT_EQ(*layers[1], layer);
753  }
754 
755  {
756  FlutterBackingStore backing_store = *layers[2]->backing_store;
757  backing_store.struct_size = sizeof(backing_store);
758  backing_store.type = kFlutterBackingStoreTypeOpenGL;
759  backing_store.did_update = true;
761 
762  FlutterLayer layer = {};
763  layer.struct_size = sizeof(layer);
765  layer.backing_store = &backing_store;
766  layer.size = FlutterSizeMake(800.0, 600.0);
767  layer.offset = FlutterPointMake(0.0, 0.0);
768 
769  ASSERT_EQ(*layers[2], layer);
770  }
771 
772  latch.CountDown();
773  });
774 
775  const auto task_runner_description =
776  test_task_runner.GetFlutterTaskRunnerDescription();
777 
778  builder.SetPlatformTaskRunner(&task_runner_description);
779 
780  context.AddNativeCallback(
781  "SignalNativeTest",
783  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
784 
785  platform_task_runner->PostTask([&]() {
786  std::scoped_lock lock(engine_mutex);
787  engine = builder.LaunchEngine();
788  ASSERT_TRUE(engine.is_valid());
789 
790  // Send a window metrics events so frames may be scheduled.
791  FlutterWindowMetricsEvent event = {};
792  event.struct_size = sizeof(event);
793  event.width = 800;
794  event.height = 600;
795  event.pixel_ratio = 1.0;
796  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
797  kSuccess);
798  ASSERT_TRUE(engine.is_valid());
799  sync_latch.Signal();
800  });
801  sync_latch.Wait();
802 
803  latch.Wait();
804 
805  platform_task_runner->PostTask([&]() {
806  std::scoped_lock lock(engine_mutex);
807  engine.reset();
808  sync_latch.Signal();
809  });
810  sync_latch.Wait();
811 }
812 
813 //------------------------------------------------------------------------------
814 /// Test the layer structure and pixels rendered when using a custom compositor
815 /// and a single layer.
816 ///
817 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) {
818  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
819 
820  EmbedderConfigBuilder builder(context);
821  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
822  builder.SetCompositor();
823  builder.SetDartEntrypoint(
824  "can_composite_platform_views_with_root_layer_only");
825 
826  builder.SetRenderTargetType(
828 
829  fml::CountDownLatch latch(3);
830 
831  auto scene_image = context.GetNextSceneImage();
832 
833  context.GetCompositor().SetNextPresentCallback(
834  [&](const FlutterLayer** layers, size_t layers_count) {
835  ASSERT_EQ(layers_count, 1u);
836 
837  // Layer Root
838  {
839  FlutterBackingStore backing_store = *layers[0]->backing_store;
840  backing_store.type = kFlutterBackingStoreTypeOpenGL;
841  backing_store.did_update = true;
843 
844  FlutterLayer layer = {};
845  layer.struct_size = sizeof(layer);
847  layer.backing_store = &backing_store;
848  layer.size = FlutterSizeMake(800.0, 600.0);
849  layer.offset = FlutterPointMake(0.0, 0.0);
850 
851  ASSERT_EQ(*layers[0], layer);
852  }
853 
854  latch.CountDown();
855  });
856 
857  context.AddNativeCallback(
858  "SignalNativeTest",
860  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
861 
862  auto engine = builder.LaunchEngine();
863 
864  // Send a window metrics events so frames may be scheduled.
865  FlutterWindowMetricsEvent event = {};
866  event.struct_size = sizeof(event);
867  event.width = 800;
868  event.height = 600;
869  event.pixel_ratio = 1.0;
871  kSuccess);
872  ASSERT_TRUE(engine.is_valid());
873 
874  latch.Wait();
875 
876  ASSERT_TRUE(
877  ImageMatchesFixture("compositor_with_root_layer_only.png", scene_image));
878 }
879 
880 //------------------------------------------------------------------------------
881 /// Test the layer structure and pixels rendered when using a custom compositor
882 /// and ensure that a redundant layer is not added.
883 ///
884 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) {
885  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
886 
887  EmbedderConfigBuilder builder(context);
888  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
889  builder.SetCompositor();
890  builder.SetDartEntrypoint(
891  "can_composite_platform_views_with_platform_layer_on_bottom");
892 
893  builder.SetRenderTargetType(
895 
896  fml::CountDownLatch latch(3);
897 
898  auto scene_image = context.GetNextSceneImage();
899 
900  context.GetCompositor().SetNextPresentCallback(
901  [&](const FlutterLayer** layers, size_t layers_count) {
902  ASSERT_EQ(layers_count, 2u);
903 
904  // Layer Root
905  {
906  FlutterBackingStore backing_store = *layers[0]->backing_store;
907  backing_store.type = kFlutterBackingStoreTypeOpenGL;
908  backing_store.did_update = true;
910 
911  FlutterLayer layer = {};
912  layer.struct_size = sizeof(layer);
914  layer.backing_store = &backing_store;
915  layer.size = FlutterSizeMake(800.0, 600.0);
916  layer.offset = FlutterPointMake(0.0, 0.0);
917 
918  ASSERT_EQ(*layers[0], layer);
919  }
920 
921  // Layer 1
922  {
924  platform_view.struct_size = sizeof(platform_view);
925  platform_view.identifier = 1;
926 
927  FlutterLayer layer = {};
928  layer.struct_size = sizeof(layer);
930  layer.platform_view = &platform_view;
931  layer.size = FlutterSizeMake(50.0, 150.0);
932  layer.offset = FlutterPointMake(20.0, 20.0);
933 
934  ASSERT_EQ(*layers[1], layer);
935  }
936 
937  latch.CountDown();
938  });
939 
940  context.GetCompositor().SetPlatformViewRendererCallback(
941  [&](const FlutterLayer& layer,
942  GrDirectContext* context) -> sk_sp<SkImage> {
943  auto surface = CreateRenderSurface(layer, context);
944  auto canvas = surface->getCanvas();
945  FML_CHECK(canvas != nullptr);
946 
947  switch (layer.platform_view->identifier) {
948  case 1: {
949  SkPaint paint;
950  // See dart test for total order.
951  paint.setColor(SK_ColorGREEN);
952  paint.setAlpha(127);
953  const auto& rect =
954  SkRect::MakeWH(layer.size.width, layer.size.height);
955  canvas->drawRect(rect, paint);
956  latch.CountDown();
957  } break;
958  default:
959  // Asked to render an unknown platform view.
960  FML_CHECK(false)
961  << "Test was asked to composite an unknown platform view.";
962  }
963 
964  return surface->makeImageSnapshot();
965  });
966 
967  context.AddNativeCallback(
968  "SignalNativeTest",
970  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
971 
972  auto engine = builder.LaunchEngine();
973 
974  // Send a window metrics events so frames may be scheduled.
975  FlutterWindowMetricsEvent event = {};
976  event.struct_size = sizeof(event);
977  event.width = 800;
978  event.height = 600;
979  event.pixel_ratio = 1.0;
981  kSuccess);
982  ASSERT_TRUE(engine.is_valid());
983 
984  latch.Wait();
985 
986  ASSERT_TRUE(ImageMatchesFixture(
987  "compositor_with_platform_layer_on_bottom.png", scene_image));
988 
989  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 1u);
990 }
991 
992 //------------------------------------------------------------------------------
993 /// Test the layer structure and pixels rendered when using a custom compositor
994 /// with a root surface transformation.
995 ///
997  CompositorMustBeAbleToRenderKnownSceneWithRootSurfaceTransformation) {
998  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
999 
1000  EmbedderConfigBuilder builder(context);
1001  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1002  builder.SetCompositor();
1003  builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
1004 
1005  builder.SetRenderTargetType(
1007 
1008  // This must match the transformation provided in the
1009  // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1010  // transforms are consistent respected.
1011  const auto root_surface_transformation =
1012  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1013 
1014  context.SetRootSurfaceTransformation(root_surface_transformation);
1015 
1016  fml::CountDownLatch latch(5);
1017 
1018  auto scene_image = context.GetNextSceneImage();
1019 
1020  context.GetCompositor().SetNextPresentCallback(
1021  [&](const FlutterLayer** layers, size_t layers_count) {
1022  ASSERT_EQ(layers_count, 5u);
1023 
1024  // Layer Root
1025  {
1026  FlutterBackingStore backing_store = *layers[0]->backing_store;
1027  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1028  backing_store.did_update = true;
1030 
1031  FlutterLayer layer = {};
1032  layer.struct_size = sizeof(layer);
1034  layer.backing_store = &backing_store;
1035  layer.size = FlutterSizeMake(600.0, 800.0);
1036  layer.offset = FlutterPointMake(0.0, 0.0);
1037 
1038  ASSERT_EQ(*layers[0], layer);
1039  }
1040 
1041  // Layer 1
1042  {
1044  platform_view.struct_size = sizeof(platform_view);
1045  platform_view.identifier = 1;
1046 
1047  FlutterLayer layer = {};
1048  layer.struct_size = sizeof(layer);
1050  layer.platform_view = &platform_view;
1051  layer.size = FlutterSizeMake(150.0, 50.0);
1052  layer.offset = FlutterPointMake(20.0, 730.0);
1053 
1054  ASSERT_EQ(*layers[1], layer);
1055  }
1056 
1057  // Layer 2
1058  {
1059  FlutterBackingStore backing_store = *layers[2]->backing_store;
1060  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1061  backing_store.did_update = true;
1063 
1064  FlutterLayer layer = {};
1065  layer.struct_size = sizeof(layer);
1067  layer.backing_store = &backing_store;
1068  layer.size = FlutterSizeMake(600.0, 800.0);
1069  layer.offset = FlutterPointMake(0.0, 0.0);
1070 
1071  ASSERT_EQ(*layers[2], layer);
1072  }
1073 
1074  // Layer 3
1075  {
1077  platform_view.struct_size = sizeof(platform_view);
1078  platform_view.identifier = 2;
1079 
1080  FlutterLayer layer = {};
1081  layer.struct_size = sizeof(layer);
1083  layer.platform_view = &platform_view;
1084  layer.size = FlutterSizeMake(150.0, 50.0);
1085  layer.offset = FlutterPointMake(40.0, 710.0);
1086 
1087  ASSERT_EQ(*layers[3], layer);
1088  }
1089 
1090  // Layer 4
1091  {
1092  FlutterBackingStore backing_store = *layers[4]->backing_store;
1093  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1094  backing_store.did_update = true;
1096 
1097  FlutterLayer layer = {};
1098  layer.struct_size = sizeof(layer);
1100  layer.backing_store = &backing_store;
1101  layer.size = FlutterSizeMake(600.0, 800.0);
1102  layer.offset = FlutterPointMake(0.0, 0.0);
1103 
1104  ASSERT_EQ(*layers[4], layer);
1105  }
1106 
1107  latch.CountDown();
1108  });
1109 
1110  context.GetCompositor().SetPlatformViewRendererCallback(
1111  [&](const FlutterLayer& layer,
1112  GrDirectContext* context) -> sk_sp<SkImage> {
1113  auto surface = CreateRenderSurface(layer, context);
1114  auto canvas = surface->getCanvas();
1115  FML_CHECK(canvas != nullptr);
1116 
1117  switch (layer.platform_view->identifier) {
1118  case 1: {
1119  SkPaint paint;
1120  // See dart test for total order.
1121  paint.setColor(SK_ColorGREEN);
1122  paint.setAlpha(127);
1123  const auto& rect =
1124  SkRect::MakeWH(layer.size.width, layer.size.height);
1125  canvas->drawRect(rect, paint);
1126  latch.CountDown();
1127  } break;
1128  case 2: {
1129  SkPaint paint;
1130  // See dart test for total order.
1131  paint.setColor(SK_ColorMAGENTA);
1132  paint.setAlpha(127);
1133  const auto& rect =
1134  SkRect::MakeWH(layer.size.width, layer.size.height);
1135  canvas->drawRect(rect, paint);
1136  latch.CountDown();
1137  } break;
1138  default:
1139  // Asked to render an unknown platform view.
1140  FML_CHECK(false)
1141  << "Test was asked to composite an unknown platform view.";
1142  }
1143 
1144  return surface->makeImageSnapshot();
1145  });
1146 
1147  context.AddNativeCallback(
1148  "SignalNativeTest",
1150  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1151 
1152  auto engine = builder.LaunchEngine();
1153 
1154  // Send a window metrics events so frames may be scheduled.
1155  FlutterWindowMetricsEvent event = {};
1156  event.struct_size = sizeof(event);
1157  // Flutter still thinks it is 800 x 600. Only the root surface is rotated.
1158  event.width = 800;
1159  event.height = 600;
1160  event.pixel_ratio = 1.0;
1162  kSuccess);
1163  ASSERT_TRUE(engine.is_valid());
1164 
1165  latch.Wait();
1166 
1167  ASSERT_TRUE(ImageMatchesFixture("compositor_root_surface_xformation.png",
1168  scene_image));
1169 }
1170 
1171 TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositor) {
1172  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1173 
1174  EmbedderConfigBuilder builder(context);
1175 
1176  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1177  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1178 
1179  auto rendered_scene = context.GetNextSceneImage();
1180 
1181  auto engine = builder.LaunchEngine();
1182  ASSERT_TRUE(engine.is_valid());
1183 
1184  // Send a window metrics events so frames may be scheduled.
1185  FlutterWindowMetricsEvent event = {};
1186  event.struct_size = sizeof(event);
1187  event.width = 800;
1188  event.height = 600;
1189  event.pixel_ratio = 1.0;
1191  kSuccess);
1192 
1193  ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png",
1194  rendered_scene));
1195 }
1196 
1197 TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositorWithTransformation) {
1198  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1199 
1200  const auto root_surface_transformation =
1201  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1202 
1203  context.SetRootSurfaceTransformation(root_surface_transformation);
1204 
1205  EmbedderConfigBuilder builder(context);
1206 
1207  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1208  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1209 
1210  auto rendered_scene = context.GetNextSceneImage();
1211 
1212  auto engine = builder.LaunchEngine();
1213  ASSERT_TRUE(engine.is_valid());
1214 
1215  // Send a window metrics events so frames may be scheduled.
1216  FlutterWindowMetricsEvent event = {};
1217  event.struct_size = sizeof(event);
1218 
1219  // Flutter still thinks it is 800 x 600.
1220  event.width = 800;
1221  event.height = 600;
1222  event.pixel_ratio = 1.0;
1224  kSuccess);
1225 
1226  ASSERT_TRUE(ImageMatchesFixture(
1227  "scene_without_custom_compositor_with_xform.png", rendered_scene));
1228 }
1229 
1230 TEST_F(EmbedderTest, CanRenderGradientWithoutCompositor) {
1231  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1232 
1233  EmbedderConfigBuilder builder(context);
1234 
1235  builder.SetDartEntrypoint("render_gradient");
1236  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1237 
1238  auto rendered_scene = context.GetNextSceneImage();
1239 
1240  auto engine = builder.LaunchEngine();
1241  ASSERT_TRUE(engine.is_valid());
1242 
1243  // Send a window metrics events so frames may be scheduled.
1244  FlutterWindowMetricsEvent event = {};
1245  event.struct_size = sizeof(event);
1246  event.width = 800;
1247  event.height = 600;
1248  event.pixel_ratio = 1.0;
1250  kSuccess);
1251 
1252  ASSERT_TRUE(ImageMatchesFixture("gradient.png", rendered_scene));
1253 }
1254 
1255 TEST_F(EmbedderTest, CanRenderGradientWithoutCompositorWithXform) {
1256  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1257 
1258  const auto root_surface_transformation =
1259  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1260 
1261  context.SetRootSurfaceTransformation(root_surface_transformation);
1262 
1263  EmbedderConfigBuilder builder(context);
1264 
1265  const auto surface_size = SkISize::Make(600, 800);
1266 
1267  builder.SetDartEntrypoint("render_gradient");
1268  builder.SetOpenGLRendererConfig(surface_size);
1269 
1270  auto rendered_scene = context.GetNextSceneImage();
1271 
1272  auto engine = builder.LaunchEngine();
1273  ASSERT_TRUE(engine.is_valid());
1274 
1275  // Send a window metrics events so frames may be scheduled.
1276  FlutterWindowMetricsEvent event = {};
1277  event.struct_size = sizeof(event);
1278  // Flutter still thinks it is 800 x 600.
1279  event.width = 800;
1280  event.height = 600;
1281  event.pixel_ratio = 1.0;
1283  kSuccess);
1284 
1285  ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1286 }
1287 
1288 TEST_F(EmbedderTest, CanRenderGradientWithCompositor) {
1289  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1290 
1291  EmbedderConfigBuilder builder(context);
1292 
1293  builder.SetDartEntrypoint("render_gradient");
1294  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1295  builder.SetCompositor();
1296  builder.SetRenderTargetType(
1298 
1299  auto rendered_scene = context.GetNextSceneImage();
1300 
1301  auto engine = builder.LaunchEngine();
1302  ASSERT_TRUE(engine.is_valid());
1303 
1304  // Send a window metrics events so frames may be scheduled.
1305  FlutterWindowMetricsEvent event = {};
1306  event.struct_size = sizeof(event);
1307  event.width = 800;
1308  event.height = 600;
1309  event.pixel_ratio = 1.0;
1311  kSuccess);
1312 
1313  ASSERT_TRUE(ImageMatchesFixture("gradient.png", rendered_scene));
1314 }
1315 
1316 TEST_F(EmbedderTest, CanRenderGradientWithCompositorWithXform) {
1317  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1318 
1319  // This must match the transformation provided in the
1320  // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1321  // transforms are consistent respected.
1322  const auto root_surface_transformation =
1323  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1324 
1325  context.SetRootSurfaceTransformation(root_surface_transformation);
1326 
1327  EmbedderConfigBuilder builder(context);
1328 
1329  builder.SetDartEntrypoint("render_gradient");
1330  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1331  builder.SetCompositor();
1332  builder.SetRenderTargetType(
1334 
1335  auto rendered_scene = context.GetNextSceneImage();
1336 
1337  auto engine = builder.LaunchEngine();
1338  ASSERT_TRUE(engine.is_valid());
1339 
1340  // Send a window metrics events so frames may be scheduled.
1341  FlutterWindowMetricsEvent event = {};
1342  event.struct_size = sizeof(event);
1343  // Flutter still thinks it is 800 x 600.
1344  event.width = 800;
1345  event.height = 600;
1346  event.pixel_ratio = 1.0;
1348  kSuccess);
1349 
1350  ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1351 }
1352 
1353 TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayer) {
1354  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1355 
1356  EmbedderConfigBuilder builder(context);
1357 
1358  builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1359  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1360  builder.SetCompositor();
1361  builder.SetRenderTargetType(
1363 
1364  context.GetCompositor().SetNextPresentCallback(
1365  [&](const FlutterLayer** layers, size_t layers_count) {
1366  ASSERT_EQ(layers_count, 3u);
1367 
1368  // Layer Root
1369  {
1370  FlutterBackingStore backing_store = *layers[0]->backing_store;
1371  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1372  backing_store.did_update = true;
1374 
1375  FlutterLayer layer = {};
1376  layer.struct_size = sizeof(layer);
1378  layer.backing_store = &backing_store;
1379  layer.size = FlutterSizeMake(800.0, 600.0);
1380  layer.offset = FlutterPointMake(0.0, 0.0);
1381 
1382  ASSERT_EQ(*layers[0], layer);
1383  }
1384 
1385  // Layer 1
1386  {
1388  platform_view.struct_size = sizeof(platform_view);
1389  platform_view.identifier = 1;
1390 
1391  FlutterLayer layer = {};
1392  layer.struct_size = sizeof(layer);
1394  layer.platform_view = &platform_view;
1395  layer.size = FlutterSizeMake(100.0, 200.0);
1396  layer.offset = FlutterPointMake(0.0, 0.0);
1397 
1398  ASSERT_EQ(*layers[1], layer);
1399  }
1400 
1401  // Layer 2
1402  {
1403  FlutterBackingStore backing_store = *layers[2]->backing_store;
1404  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1405  backing_store.did_update = true;
1407 
1408  FlutterLayer layer = {};
1409  layer.struct_size = sizeof(layer);
1411  layer.backing_store = &backing_store;
1412  layer.size = FlutterSizeMake(800.0, 600.0);
1413  layer.offset = FlutterPointMake(0.0, 0.0);
1414 
1415  ASSERT_EQ(*layers[2], layer);
1416  }
1417  });
1418 
1419  context.GetCompositor().SetPlatformViewRendererCallback(
1420  [&](const FlutterLayer& layer,
1421  GrDirectContext* context) -> sk_sp<SkImage> {
1422  auto surface = CreateRenderSurface(layer, context);
1423  auto canvas = surface->getCanvas();
1424  FML_CHECK(canvas != nullptr);
1425 
1426  switch (layer.platform_view->identifier) {
1427  case 1: {
1428  FML_CHECK(layer.size.width == 100);
1429  FML_CHECK(layer.size.height == 200);
1430  // This is occluded anyway. We just want to make sure we see this.
1431  } break;
1432  default:
1433  // Asked to render an unknown platform view.
1434  FML_CHECK(false)
1435  << "Test was asked to composite an unknown platform view.";
1436  }
1437 
1438  return surface->makeImageSnapshot();
1439  });
1440 
1441  auto rendered_scene = context.GetNextSceneImage();
1442 
1443  auto engine = builder.LaunchEngine();
1444  ASSERT_TRUE(engine.is_valid());
1445 
1446  // Send a window metrics events so frames may be scheduled.
1447  FlutterWindowMetricsEvent event = {};
1448  event.struct_size = sizeof(event);
1449  event.width = 800;
1450  event.height = 600;
1451  event.pixel_ratio = 1.0;
1453  kSuccess);
1454 
1455  ASSERT_TRUE(ImageMatchesFixture("gradient.png", rendered_scene));
1456 }
1457 
1458 TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) {
1459  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1460 
1461  // This must match the transformation provided in the
1462  // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1463  // transforms are consistent respected.
1464  const auto root_surface_transformation =
1465  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1466 
1467  context.SetRootSurfaceTransformation(root_surface_transformation);
1468 
1469  EmbedderConfigBuilder builder(context);
1470 
1471  builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1472  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1473  builder.SetCompositor();
1474  builder.SetRenderTargetType(
1476 
1477  context.GetCompositor().SetNextPresentCallback(
1478  [&](const FlutterLayer** layers, size_t layers_count) {
1479  ASSERT_EQ(layers_count, 3u);
1480 
1481  // Layer Root
1482  {
1483  FlutterBackingStore backing_store = *layers[0]->backing_store;
1484  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1485  backing_store.did_update = true;
1487 
1488  FlutterLayer layer = {};
1489  layer.struct_size = sizeof(layer);
1491  layer.backing_store = &backing_store;
1492  layer.size = FlutterSizeMake(600.0, 800.0);
1493  layer.offset = FlutterPointMake(0.0, 0.0);
1494 
1495  ASSERT_EQ(*layers[0], layer);
1496  }
1497 
1498  // Layer 1
1499  {
1501  platform_view.struct_size = sizeof(platform_view);
1502  platform_view.identifier = 1;
1503 
1504  FlutterLayer layer = {};
1505  layer.struct_size = sizeof(layer);
1507  layer.platform_view = &platform_view;
1508  layer.size = FlutterSizeMake(200.0, 100.0);
1509  layer.offset = FlutterPointMake(0.0, 700.0);
1510 
1511  ASSERT_EQ(*layers[1], layer);
1512  }
1513 
1514  // Layer 2
1515  {
1516  FlutterBackingStore backing_store = *layers[2]->backing_store;
1517  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1518  backing_store.did_update = true;
1520 
1521  FlutterLayer layer = {};
1522  layer.struct_size = sizeof(layer);
1524  layer.backing_store = &backing_store;
1525  layer.size = FlutterSizeMake(600.0, 800.0);
1526  layer.offset = FlutterPointMake(0.0, 0.0);
1527 
1528  ASSERT_EQ(*layers[2], layer);
1529  }
1530  });
1531 
1532  context.GetCompositor().SetPlatformViewRendererCallback(
1533  [&](const FlutterLayer& layer,
1534  GrDirectContext* context) -> sk_sp<SkImage> {
1535  auto surface = CreateRenderSurface(layer, context);
1536  auto canvas = surface->getCanvas();
1537  FML_CHECK(canvas != nullptr);
1538 
1539  switch (layer.platform_view->identifier) {
1540  case 1: {
1541  FML_CHECK(layer.size.width == 200);
1542  FML_CHECK(layer.size.height == 100);
1543  // This is occluded anyway. We just want to make sure we see this.
1544  } break;
1545  default:
1546  // Asked to render an unknown platform view.
1547  FML_CHECK(false)
1548  << "Test was asked to composite an unknown platform view.";
1549  }
1550 
1551  return surface->makeImageSnapshot();
1552  });
1553 
1554  auto rendered_scene = context.GetNextSceneImage();
1555 
1556  auto engine = builder.LaunchEngine();
1557  ASSERT_TRUE(engine.is_valid());
1558 
1559  // Send a window metrics events so frames may be scheduled.
1560  FlutterWindowMetricsEvent event = {};
1561  event.struct_size = sizeof(event);
1562  // Flutter still thinks it is 800 x 600.
1563  event.width = 800;
1564  event.height = 600;
1565  event.pixel_ratio = 1.0;
1567  kSuccess);
1568 
1569  ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", rendered_scene));
1570 }
1571 
1572 TEST_F(EmbedderTest, VerifyB141980393) {
1573  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1574 
1575  EmbedderConfigBuilder builder(context);
1576 
1577  // The Flutter application is 800 x 600 but rendering on a surface that is 600
1578  // x 800 achieved using a root surface transformation.
1579  const auto root_surface_transformation =
1580  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1581  const auto flutter_application_rect = SkRect::MakeWH(800, 600);
1582  const auto root_surface_rect =
1583  root_surface_transformation.mapRect(flutter_application_rect);
1584 
1585  ASSERT_DOUBLE_EQ(root_surface_rect.width(), 600.0);
1586  ASSERT_DOUBLE_EQ(root_surface_rect.height(), 800.0);
1587 
1588  // Configure the fixture for the surface transformation.
1589  context.SetRootSurfaceTransformation(root_surface_transformation);
1590 
1591  // Configure the Flutter project args for the root surface transformation.
1592  builder.SetOpenGLRendererConfig(
1593  SkISize::Make(root_surface_rect.width(), root_surface_rect.height()));
1594 
1595  // Use a compositor instead of rendering directly to the surface.
1596  builder.SetCompositor();
1597  builder.SetRenderTargetType(
1599 
1600  builder.SetDartEntrypoint("verify_b141980393");
1601 
1603 
1604  context.GetCompositor().SetNextPresentCallback(
1605  [&](const FlutterLayer** layers, size_t layers_count) {
1606  ASSERT_EQ(layers_count, 1u);
1607 
1608  // Layer Root
1609  {
1611  platform_view.struct_size = sizeof(platform_view);
1612  platform_view.identifier = 1337;
1613 
1614  FlutterLayer layer = {};
1615  layer.struct_size = sizeof(layer);
1617  layer.platform_view = &platform_view;
1618 
1619  // From the Dart side. These dimensions match those specified in Dart
1620  // code and are free of root surface transformations.
1621  const double unxformed_top_margin = 31.0;
1622  const double unxformed_bottom_margin = 37.0;
1623  const auto unxformed_platform_view_rect = SkRect::MakeXYWH(
1624  0.0, // x
1625  unxformed_top_margin, // y (top margin)
1626  800, // width
1627  600 - unxformed_top_margin - unxformed_bottom_margin // height
1628  );
1629 
1630  // The platform views are in the coordinate space of the root surface
1631  // with top-left origin. The embedder has specified a transformation
1632  // to this surface which it must account for in the coordinates it
1633  // receives here.
1634  const auto xformed_platform_view_rect =
1635  root_surface_transformation.mapRect(unxformed_platform_view_rect);
1636 
1637  // Spell out the value that we are going to be checking below for
1638  // clarity.
1639  ASSERT_EQ(xformed_platform_view_rect,
1640  SkRect::MakeXYWH(31.0, // x
1641  0.0, // y
1642  532.0, // width
1643  800.0 // height
1644  ));
1645 
1646  // Verify that the engine is giving us the right size and offset.
1647  layer.offset = FlutterPointMake(xformed_platform_view_rect.x(),
1648  xformed_platform_view_rect.y());
1649  layer.size = FlutterSizeMake(xformed_platform_view_rect.width(),
1650  xformed_platform_view_rect.height());
1651 
1652  ASSERT_EQ(*layers[0], layer);
1653  }
1654 
1655  latch.Signal();
1656  });
1657 
1658  auto engine = builder.LaunchEngine();
1659 
1660  // Send a window metrics events so frames may be scheduled.
1661  FlutterWindowMetricsEvent event = {};
1662  event.struct_size = sizeof(event);
1663 
1664  // The Flutter application is 800 x 600 rendering on a surface 600 x 800
1665  // achieved via a root surface transformation.
1666  event.width = flutter_application_rect.width();
1667  event.height = flutter_application_rect.height();
1668  event.pixel_ratio = 1.0;
1670  kSuccess);
1671  ASSERT_TRUE(engine.is_valid());
1672 
1673  latch.Wait();
1674 }
1675 
1676 //------------------------------------------------------------------------------
1677 /// Asserts that embedders can provide a task runner for the render thread.
1678 ///
1679 TEST_F(EmbedderTest, CanCreateEmbedderWithCustomRenderTaskRunner) {
1680  std::mutex engine_mutex;
1682  fml::AutoResetWaitableEvent task_latch;
1683  bool task_executed = false;
1684  EmbedderTestTaskRunner render_task_runner(
1685  CreateNewThread("custom_render_thread"), [&](FlutterTask task) {
1686  std::scoped_lock engine_lock(engine_mutex);
1687  if (engine.is_valid()) {
1688  ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
1689  task_executed = true;
1690  task_latch.Signal();
1691  }
1692  });
1693  EmbedderConfigBuilder builder(
1694  GetEmbedderContext(EmbedderTestContextType::kOpenGLContext));
1695  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1696  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1697  builder.SetRenderTaskRunner(
1698  &render_task_runner.GetFlutterTaskRunnerDescription());
1699 
1700  {
1701  std::scoped_lock lock(engine_mutex);
1702  engine = builder.InitializeEngine();
1703  }
1704 
1705  ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
1706 
1707  ASSERT_TRUE(engine.is_valid());
1708 
1709  FlutterWindowMetricsEvent event = {};
1710  event.struct_size = sizeof(event);
1711  event.width = 800;
1712  event.height = 600;
1713  event.pixel_ratio = 1.0;
1714  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1715  kSuccess);
1716  task_latch.Wait();
1717  ASSERT_TRUE(task_executed);
1718  ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
1719 
1720  {
1721  std::scoped_lock engine_lock(engine_mutex);
1722  engine.reset();
1723  }
1724 }
1725 
1726 //------------------------------------------------------------------------------
1727 /// Asserts that the render task runner can be the same as the platform task
1728 /// runner.
1729 ///
1731  CanCreateEmbedderWithCustomRenderTaskRunnerTheSameAsPlatformTaskRunner) {
1732  // A new thread needs to be created for the platform thread because the test
1733  // can't wait for assertions to be completed on the same thread that services
1734  // platform task runner tasks.
1735  auto platform_task_runner = CreateNewThread("platform_thread");
1736 
1737  static std::mutex engine_mutex;
1738  static UniqueEngine engine;
1739  fml::AutoResetWaitableEvent task_latch;
1740  bool task_executed = false;
1741  EmbedderTestTaskRunner common_task_runner(
1742  platform_task_runner, [&](FlutterTask task) {
1743  std::scoped_lock engine_lock(engine_mutex);
1744  if (engine.is_valid()) {
1745  ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
1746  task_executed = true;
1747  task_latch.Signal();
1748  }
1749  });
1750 
1751  platform_task_runner->PostTask([&]() {
1752  EmbedderConfigBuilder builder(
1753  GetEmbedderContext(EmbedderTestContextType::kOpenGLContext));
1754  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1755  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1756  builder.SetRenderTaskRunner(
1757  &common_task_runner.GetFlutterTaskRunnerDescription());
1758  builder.SetPlatformTaskRunner(
1759  &common_task_runner.GetFlutterTaskRunnerDescription());
1760 
1761  {
1762  std::scoped_lock lock(engine_mutex);
1763  engine = builder.InitializeEngine();
1764  }
1765 
1766  ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
1767 
1768  ASSERT_TRUE(engine.is_valid());
1769 
1770  FlutterWindowMetricsEvent event = {};
1771  event.struct_size = sizeof(event);
1772  event.width = 800;
1773  event.height = 600;
1774  event.pixel_ratio = 1.0;
1775  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1776  kSuccess);
1777  });
1778 
1779  task_latch.Wait();
1780 
1781  // Don't use the task latch because that may be called multiple time
1782  // (including during the shutdown process).
1783  fml::AutoResetWaitableEvent shutdown_latch;
1784 
1785  platform_task_runner->PostTask([&]() {
1786  ASSERT_TRUE(task_executed);
1787  ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
1788 
1789  {
1790  std::scoped_lock engine_lock(engine_mutex);
1791  engine.reset();
1792  }
1793  shutdown_latch.Signal();
1794  });
1795 
1796  shutdown_latch.Wait();
1797 
1798  {
1799  std::scoped_lock engine_lock(engine_mutex);
1800  // Engine should have been killed by this point.
1801  ASSERT_FALSE(engine.is_valid());
1802  }
1803 }
1804 
1806  CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurface) {
1807  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1808 
1809  EmbedderConfigBuilder builder(context);
1810  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1811  builder.SetCompositor();
1812  builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
1813 
1814  builder.SetRenderTargetType(
1816 
1817  fml::CountDownLatch latch(1);
1818 
1819  auto rendered_scene = context.GetNextSceneImage();
1820 
1821  context.GetCompositor().SetNextPresentCallback(
1822  [&](const FlutterLayer** layers, size_t layers_count) {
1823  ASSERT_EQ(layers_count, 3u);
1824 
1825  // Layer 0 (Root)
1826  {
1827  FlutterBackingStore backing_store = *layers[0]->backing_store;
1828  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1829  backing_store.did_update = true;
1831 
1832  FlutterLayer layer = {};
1833  layer.struct_size = sizeof(layer);
1835  layer.backing_store = &backing_store;
1836  layer.size = FlutterSizeMake(800.0, 600.0);
1837  layer.offset = FlutterPointMake(0.0, 0.0);
1838 
1839  ASSERT_EQ(*layers[0], layer);
1840  }
1841 
1842  // Layer 1
1843  {
1845  platform_view.struct_size = sizeof(platform_view);
1846  platform_view.identifier = 42;
1847 
1848  FlutterLayer layer = {};
1849  layer.struct_size = sizeof(layer);
1851  layer.platform_view = &platform_view;
1852  layer.size = FlutterSizeMake(800.0, 560.0);
1853  layer.offset = FlutterPointMake(0.0, 40.0);
1854 
1855  ASSERT_EQ(*layers[1], layer);
1856  }
1857 
1858  // Layer 2
1859  {
1860  FlutterBackingStore backing_store = *layers[2]->backing_store;
1861  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1862  backing_store.did_update = true;
1864 
1865  FlutterLayer layer = {};
1866  layer.struct_size = sizeof(layer);
1868  layer.backing_store = &backing_store;
1869  layer.size = FlutterSizeMake(800.0, 600.0);
1870  layer.offset = FlutterPointMake(0.0, 0.0);
1871 
1872  ASSERT_EQ(*layers[2], layer);
1873  }
1874 
1875  latch.CountDown();
1876  });
1877 
1878  auto engine = builder.LaunchEngine();
1879 
1880  // Send a window metrics events so frames may be scheduled.
1881  FlutterWindowMetricsEvent event = {};
1882  event.struct_size = sizeof(event);
1883  event.width = 400 * 2.0;
1884  event.height = 300 * 2.0;
1885  event.pixel_ratio = 2.0;
1887  kSuccess);
1888  ASSERT_TRUE(engine.is_valid());
1889 
1890  latch.Wait();
1891 
1892  ASSERT_TRUE(ImageMatchesFixture("dpr_noxform.png", rendered_scene));
1893 }
1894 
1896  EmbedderTest,
1897  CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurfaceWithRootSurfaceXformation) {
1898  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1899 
1900  EmbedderConfigBuilder builder(context);
1901  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1902  builder.SetCompositor();
1903  builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
1904 
1905  builder.SetRenderTargetType(
1907 
1908  const auto root_surface_transformation =
1909  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1910 
1911  context.SetRootSurfaceTransformation(root_surface_transformation);
1912 
1913  auto rendered_scene = context.GetNextSceneImage();
1914  fml::CountDownLatch latch(1);
1915 
1916  context.GetCompositor().SetNextPresentCallback(
1917  [&](const FlutterLayer** layers, size_t layers_count) {
1918  ASSERT_EQ(layers_count, 3u);
1919 
1920  // Layer 0 (Root)
1921  {
1922  FlutterBackingStore backing_store = *layers[0]->backing_store;
1923  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1924  backing_store.did_update = true;
1926 
1927  FlutterLayer layer = {};
1928  layer.struct_size = sizeof(layer);
1930  layer.backing_store = &backing_store;
1931  layer.size = FlutterSizeMake(600.0, 800.0);
1932  layer.offset = FlutterPointMake(0.0, 0.0);
1933 
1934  ASSERT_EQ(*layers[0], layer);
1935  }
1936 
1937  // Layer 1
1938  {
1940  platform_view.struct_size = sizeof(platform_view);
1941  platform_view.identifier = 42;
1942 
1943  FlutterLayer layer = {};
1944  layer.struct_size = sizeof(layer);
1946  layer.platform_view = &platform_view;
1947  layer.size = FlutterSizeMake(560.0, 800.0);
1948  layer.offset = FlutterPointMake(40.0, 0.0);
1949 
1950  ASSERT_EQ(*layers[1], layer);
1951  }
1952 
1953  // Layer 2
1954  {
1955  FlutterBackingStore backing_store = *layers[2]->backing_store;
1956  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1957  backing_store.did_update = true;
1959 
1960  FlutterLayer layer = {};
1961  layer.struct_size = sizeof(layer);
1963  layer.backing_store = &backing_store;
1964  layer.size = FlutterSizeMake(600.0, 800.0);
1965  layer.offset = FlutterPointMake(0.0, 0.0);
1966 
1967  ASSERT_EQ(*layers[2], layer);
1968  }
1969 
1970  latch.CountDown();
1971  });
1972 
1973  auto engine = builder.LaunchEngine();
1974 
1975  // Send a window metrics events so frames may be scheduled.
1976  FlutterWindowMetricsEvent event = {};
1977  event.struct_size = sizeof(event);
1978  event.width = 400 * 2.0;
1979  event.height = 300 * 2.0;
1980  event.pixel_ratio = 2.0;
1982  kSuccess);
1983  ASSERT_TRUE(engine.is_valid());
1984 
1985  latch.Wait();
1986 
1987  ASSERT_TRUE(ImageMatchesFixture("dpr_xform.png", rendered_scene));
1988 }
1989 
1991  PushingMutlipleFramesSetsUpNewRecordingCanvasWithCustomCompositor) {
1992  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
1993 
1994  EmbedderConfigBuilder builder(context);
1995  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
1996  builder.SetCompositor();
1997  builder.SetDartEntrypoint("push_frames_over_and_over");
1998 
1999  builder.SetRenderTargetType(
2001 
2002  const auto root_surface_transformation =
2003  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
2004 
2005  context.SetRootSurfaceTransformation(root_surface_transformation);
2006 
2007  auto engine = builder.LaunchEngine();
2008 
2009  // Send a window metrics events so frames may be scheduled.
2010  FlutterWindowMetricsEvent event = {};
2011  event.struct_size = sizeof(event);
2012  event.width = 1024;
2013  event.height = 600;
2014  event.pixel_ratio = 1.0;
2016  kSuccess);
2017  ASSERT_TRUE(engine.is_valid());
2018 
2019  constexpr size_t frames_expected = 10;
2020  fml::CountDownLatch frame_latch(frames_expected);
2021  static size_t frames_seen;
2022  frames_seen = 0;
2023  context.AddNativeCallback("SignalNativeTest",
2024  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2025  frames_seen++;
2026  frame_latch.CountDown();
2027  }));
2028  frame_latch.Wait();
2029 
2030  ASSERT_EQ(frames_expected, frames_seen);
2031 
2032  FlutterEngineShutdown(engine.release());
2033 }
2034 
2036  PushingMutlipleFramesSetsUpNewRecordingCanvasWithoutCustomCompositor) {
2037  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2038 
2039  EmbedderConfigBuilder builder(context);
2040  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
2041  builder.SetDartEntrypoint("push_frames_over_and_over");
2042 
2043  const auto root_surface_transformation =
2044  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
2045 
2046  context.SetRootSurfaceTransformation(root_surface_transformation);
2047 
2048  auto engine = builder.LaunchEngine();
2049 
2050  // Send a window metrics events so frames may be scheduled.
2051  FlutterWindowMetricsEvent event = {};
2052  event.struct_size = sizeof(event);
2053  event.width = 1024;
2054  event.height = 600;
2055  event.pixel_ratio = 1.0;
2057  kSuccess);
2058  ASSERT_TRUE(engine.is_valid());
2059 
2060  constexpr size_t frames_expected = 10;
2061  fml::CountDownLatch frame_latch(frames_expected);
2062  static size_t frames_seen;
2063  frames_seen = 0;
2064  context.AddNativeCallback("SignalNativeTest",
2065  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2066  frames_seen++;
2067  frame_latch.CountDown();
2068  }));
2069  frame_latch.Wait();
2070 
2071  ASSERT_EQ(frames_expected, frames_seen);
2072 
2073  FlutterEngineShutdown(engine.release());
2074 }
2075 
2076 TEST_F(EmbedderTest, PlatformViewMutatorsAreValid) {
2077  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2078 
2079  EmbedderConfigBuilder builder(context);
2080  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2081  builder.SetCompositor();
2082  builder.SetDartEntrypoint("platform_view_mutators");
2083 
2084  builder.SetRenderTargetType(
2086 
2087  fml::CountDownLatch latch(1);
2088  context.GetCompositor().SetNextPresentCallback(
2089  [&](const FlutterLayer** layers, size_t layers_count) {
2090  ASSERT_EQ(layers_count, 2u);
2091 
2092  // Layer 0 (Root)
2093  {
2094  FlutterBackingStore backing_store = *layers[0]->backing_store;
2095  backing_store.type = kFlutterBackingStoreTypeOpenGL;
2096  backing_store.did_update = true;
2098 
2099  FlutterLayer layer = {};
2100  layer.struct_size = sizeof(layer);
2102  layer.backing_store = &backing_store;
2103  layer.size = FlutterSizeMake(800.0, 600.0);
2104  layer.offset = FlutterPointMake(0.0, 0.0);
2105 
2106  ASSERT_EQ(*layers[0], layer);
2107  }
2108 
2109  // Layer 2
2110  {
2112  platform_view.struct_size = sizeof(platform_view);
2113  platform_view.identifier = 42;
2114  platform_view.mutations_count = 3;
2115 
2116  FlutterLayer layer = {};
2117  layer.struct_size = sizeof(layer);
2119  layer.platform_view = &platform_view;
2120  layer.size = FlutterSizeMake(800.0, 600.0);
2121  layer.offset = FlutterPointMake(0.0, 0.0);
2122 
2123  ASSERT_EQ(*layers[1], layer);
2124 
2125  // There are no ordering guarantees.
2126  for (size_t i = 0; i < platform_view.mutations_count; i++) {
2127  FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2128  switch (mutation.type) {
2130  mutation.clip_rounded_rect =
2131  FlutterRoundedRectMake(SkRRect::MakeRectXY(
2132  SkRect::MakeLTRB(10.0, 10.0, 800.0 - 10.0,
2133  600.0 - 10.0),
2134  14.0, 14.0));
2135  break;
2138  mutation.clip_rect = FlutterRectMake(
2139  SkRect::MakeXYWH(10.0, 10.0, 800.0 - 20.0, 600.0 - 20.0));
2140  break;
2143  mutation.opacity = 128.0 / 255.0;
2144  break;
2146  FML_CHECK(false)
2147  << "There should be no transformation in the test.";
2148  break;
2149  }
2150 
2151  ASSERT_EQ(*platform_view.mutations[i], mutation);
2152  }
2153  }
2154  latch.CountDown();
2155  });
2156 
2157  auto engine = builder.LaunchEngine();
2158 
2159  // Send a window metrics events so frames may be scheduled.
2160  FlutterWindowMetricsEvent event = {};
2161  event.struct_size = sizeof(event);
2162  event.width = 800;
2163  event.height = 600;
2164  event.pixel_ratio = 1.0;
2166  kSuccess);
2167  ASSERT_TRUE(engine.is_valid());
2168 
2169  latch.Wait();
2170 }
2171 
2172 TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) {
2173  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2174 
2175  EmbedderConfigBuilder builder(context);
2176  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2177  builder.SetCompositor();
2178  builder.SetDartEntrypoint("platform_view_mutators_with_pixel_ratio");
2179 
2180  builder.SetRenderTargetType(
2182 
2183  fml::CountDownLatch latch(1);
2184  context.GetCompositor().SetNextPresentCallback(
2185  [&](const FlutterLayer** layers, size_t layers_count) {
2186  ASSERT_EQ(layers_count, 2u);
2187 
2188  // Layer 0 (Root)
2189  {
2190  FlutterBackingStore backing_store = *layers[0]->backing_store;
2191  backing_store.type = kFlutterBackingStoreTypeOpenGL;
2192  backing_store.did_update = true;
2194 
2195  FlutterLayer layer = {};
2196  layer.struct_size = sizeof(layer);
2198  layer.backing_store = &backing_store;
2199  layer.size = FlutterSizeMake(800.0, 600.0);
2200  layer.offset = FlutterPointMake(0.0, 0.0);
2201 
2202  ASSERT_EQ(*layers[0], layer);
2203  }
2204 
2205  // Layer 2
2206  {
2208  platform_view.struct_size = sizeof(platform_view);
2209  platform_view.identifier = 42;
2210  platform_view.mutations_count = 3;
2211 
2212  FlutterLayer layer = {};
2213  layer.struct_size = sizeof(layer);
2215  layer.platform_view = &platform_view;
2216  layer.size = FlutterSizeMake(800.0, 600.0);
2217  layer.offset = FlutterPointMake(0.0, 0.0);
2218 
2219  ASSERT_EQ(*layers[1], layer);
2220 
2221  // There are no ordering guarantees.
2222  for (size_t i = 0; i < platform_view.mutations_count; i++) {
2223  FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2224  switch (mutation.type) {
2226  mutation.clip_rounded_rect =
2227  FlutterRoundedRectMake(SkRRect::MakeRectXY(
2228  SkRect::MakeLTRB(5.0, 5.0, 400.0 - 5.0, 300.0 - 5.0),
2229  7.0, 7.0));
2230  break;
2233  mutation.clip_rect = FlutterRectMake(
2234  SkRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2235  break;
2238  mutation.opacity = 128.0 / 255.0;
2239  break;
2242  mutation.transformation =
2243  FlutterTransformationMake(SkMatrix::Scale(2.0, 2.0));
2244  break;
2245  }
2246 
2247  ASSERT_EQ(*platform_view.mutations[i], mutation);
2248  }
2249  }
2250  latch.CountDown();
2251  });
2252 
2253  auto engine = builder.LaunchEngine();
2254 
2255  // Send a window metrics events so frames may be scheduled.
2256  FlutterWindowMetricsEvent event = {};
2257  event.struct_size = sizeof(event);
2258  event.width = 800;
2259  event.height = 600;
2260  event.pixel_ratio = 2.0;
2262  kSuccess);
2263  ASSERT_TRUE(engine.is_valid());
2264 
2265  latch.Wait();
2266 }
2267 
2269  PlatformViewMutatorsAreValidWithPixelRatioAndRootSurfaceTransformation) {
2270  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2271 
2272  EmbedderConfigBuilder builder(context);
2273  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2274  builder.SetCompositor();
2275  builder.SetDartEntrypoint("platform_view_mutators_with_pixel_ratio");
2276 
2277  builder.SetRenderTargetType(
2279 
2280  static const auto root_surface_transformation =
2281  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
2282 
2283  context.SetRootSurfaceTransformation(root_surface_transformation);
2284 
2285  fml::CountDownLatch latch(1);
2286  context.GetCompositor().SetNextPresentCallback(
2287  [&](const FlutterLayer** layers, size_t layers_count) {
2288  ASSERT_EQ(layers_count, 2u);
2289 
2290  // Layer 0 (Root)
2291  {
2292  FlutterBackingStore backing_store = *layers[0]->backing_store;
2293  backing_store.type = kFlutterBackingStoreTypeOpenGL;
2294  backing_store.did_update = true;
2296 
2297  FlutterLayer layer = {};
2298  layer.struct_size = sizeof(layer);
2300  layer.backing_store = &backing_store;
2301  layer.size = FlutterSizeMake(600.0, 800.0);
2302  layer.offset = FlutterPointMake(0.0, 0.0);
2303 
2304  ASSERT_EQ(*layers[0], layer);
2305  }
2306 
2307  // Layer 2
2308  {
2310  platform_view.struct_size = sizeof(platform_view);
2311  platform_view.identifier = 42;
2312  platform_view.mutations_count = 4;
2313 
2314  FlutterLayer layer = {};
2315  layer.struct_size = sizeof(layer);
2317  layer.platform_view = &platform_view;
2318  layer.size = FlutterSizeMake(600.0, 800.0);
2319  layer.offset = FlutterPointMake(0.0, 0.0);
2320 
2321  ASSERT_EQ(*layers[1], layer);
2322 
2323  // There are no ordering guarantees.
2324  for (size_t i = 0; i < platform_view.mutations_count; i++) {
2325  FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2326  switch (mutation.type) {
2328  mutation.clip_rounded_rect =
2329  FlutterRoundedRectMake(SkRRect::MakeRectXY(
2330  SkRect::MakeLTRB(5.0, 5.0, 400.0 - 5.0, 300.0 - 5.0),
2331  7.0, 7.0));
2332  break;
2335  mutation.clip_rect = FlutterRectMake(
2336  SkRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2337  break;
2340  mutation.opacity = 128.0 / 255.0;
2341  break;
2344  mutation.transformation =
2345  FlutterTransformationMake(root_surface_transformation);
2346 
2347  break;
2348  }
2349 
2350  ASSERT_EQ(*platform_view.mutations[i], mutation);
2351  }
2352  }
2353  latch.CountDown();
2354  });
2355 
2356  auto engine = builder.LaunchEngine();
2357 
2358  // Send a window metrics events so frames may be scheduled.
2359  FlutterWindowMetricsEvent event = {};
2360  event.struct_size = sizeof(event);
2361  event.width = 800;
2362  event.height = 600;
2363  event.pixel_ratio = 2.0;
2365  kSuccess);
2366  ASSERT_TRUE(engine.is_valid());
2367 
2368  latch.Wait();
2369 }
2370 
2371 TEST_F(EmbedderTest, EmptySceneIsAcceptable) {
2372  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2373 
2374  EmbedderConfigBuilder builder(context);
2375  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2376  builder.SetCompositor();
2377  builder.SetDartEntrypoint("empty_scene");
2379  context.AddNativeCallback(
2380  "SignalNativeTest",
2381  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
2382 
2383  auto engine = builder.LaunchEngine();
2384 
2385  ASSERT_TRUE(engine.is_valid());
2386 
2387  FlutterWindowMetricsEvent event = {};
2388  event.struct_size = sizeof(event);
2389  event.width = 800;
2390  event.height = 600;
2391  event.pixel_ratio = 1.0;
2393  kSuccess);
2394  latch.Wait();
2395 }
2396 
2397 TEST_F(EmbedderTest, SceneWithNoRootContainerIsAcceptable) {
2398  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2399 
2400  EmbedderConfigBuilder builder(context);
2401  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2402  builder.SetCompositor();
2403  builder.SetRenderTargetType(
2405  builder.SetDartEntrypoint("scene_with_no_container");
2407  context.AddNativeCallback(
2408  "SignalNativeTest",
2409  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
2410 
2411  auto engine = builder.LaunchEngine();
2412 
2413  ASSERT_TRUE(engine.is_valid());
2414 
2415  FlutterWindowMetricsEvent event = {};
2416  event.struct_size = sizeof(event);
2417  event.width = 800;
2418  event.height = 600;
2419  event.pixel_ratio = 1.0;
2421  kSuccess);
2422  latch.Wait();
2423 }
2424 
2425 // Verifies that https://skia-review.googlesource.com/c/skia/+/259174 is pulled
2426 // into the engine.
2427 TEST_F(EmbedderTest, ArcEndCapsAreDrawnCorrectly) {
2428  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2429 
2430  EmbedderConfigBuilder builder(context);
2431  builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
2432  builder.SetCompositor();
2433  builder.SetDartEntrypoint("arc_end_caps_correct");
2434  builder.SetRenderTargetType(
2436 
2437  const auto root_surface_transformation = SkMatrix()
2438  .preScale(1.0, -1.0)
2439  .preTranslate(1024.0, -800.0)
2440  .preRotate(90.0);
2441 
2442  context.SetRootSurfaceTransformation(root_surface_transformation);
2443 
2444  auto engine = builder.LaunchEngine();
2445 
2446  auto scene_image = context.GetNextSceneImage();
2447 
2448  ASSERT_TRUE(engine.is_valid());
2449 
2450  FlutterWindowMetricsEvent event = {};
2451  event.struct_size = sizeof(event);
2452  event.width = 1024;
2453  event.height = 800;
2454  event.pixel_ratio = 1.0;
2456  kSuccess);
2457 
2458  ASSERT_TRUE(ImageMatchesFixture("arc_end_caps.png", scene_image));
2459 }
2460 
2461 TEST_F(EmbedderTest, ClipsAreCorrectlyCalculated) {
2462  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2463 
2464  EmbedderConfigBuilder builder(context);
2465  builder.SetOpenGLRendererConfig(SkISize::Make(400, 300));
2466  builder.SetCompositor();
2467  builder.SetDartEntrypoint("scene_builder_with_clips");
2468  builder.SetRenderTargetType(
2470 
2471  const auto root_surface_transformation =
2472  SkMatrix().preTranslate(0, 400).preRotate(-90, 0, 0);
2473 
2474  context.SetRootSurfaceTransformation(root_surface_transformation);
2475 
2477  context.GetCompositor().SetNextPresentCallback(
2478  [&](const FlutterLayer** layers, size_t layers_count) {
2479  ASSERT_EQ(layers_count, 2u);
2480 
2481  {
2483  platform_view.struct_size = sizeof(platform_view);
2484  platform_view.identifier = 42;
2485 
2486  FlutterLayer layer = {};
2487  layer.struct_size = sizeof(layer);
2489  layer.platform_view = &platform_view;
2490  layer.size = FlutterSizeMake(300.0, 400.0);
2491  layer.offset = FlutterPointMake(0.0, 0.0);
2492 
2493  ASSERT_EQ(*layers[0], layer);
2494 
2495  bool clip_assertions_checked = false;
2496 
2497  // The total transformation on the stack upto the platform view.
2498  const auto total_xformation =
2499  GetTotalMutationTransformationMatrix(layers[0]->platform_view);
2500 
2502  layers[0]->platform_view,
2504  [&](const auto& mutation) {
2505  FlutterRect clip = mutation.clip_rect;
2506 
2507  // The test is only set up to supply one clip. Make sure it is
2508  // the one we expect.
2509  const auto rect_to_compare =
2510  SkRect::MakeLTRB(10.0, 10.0, 390, 290);
2511  ASSERT_EQ(clip, FlutterRectMake(rect_to_compare));
2512 
2513  // This maps the clip from device space into surface space.
2514  SkRect mapped;
2515  ASSERT_TRUE(total_xformation.mapRect(&mapped, rect_to_compare));
2516  ASSERT_EQ(mapped, SkRect::MakeLTRB(10, 10, 290, 390));
2517  clip_assertions_checked = true;
2518  });
2519 
2520  ASSERT_TRUE(clip_assertions_checked);
2521  }
2522 
2523  latch.Signal();
2524  });
2525 
2526  auto engine = builder.LaunchEngine();
2527  ASSERT_TRUE(engine.is_valid());
2528 
2529  FlutterWindowMetricsEvent event = {};
2530  event.struct_size = sizeof(event);
2531  event.width = 400;
2532  event.height = 300;
2533  event.pixel_ratio = 1.0;
2535  kSuccess);
2536 
2537  latch.Wait();
2538 }
2539 
2540 TEST_F(EmbedderTest, ComplexClipsAreCorrectlyCalculated) {
2541  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2542 
2543  EmbedderConfigBuilder builder(context);
2544  builder.SetOpenGLRendererConfig(SkISize::Make(1024, 600));
2545  builder.SetCompositor();
2546  builder.SetDartEntrypoint("scene_builder_with_complex_clips");
2547  builder.SetRenderTargetType(
2549 
2550  const auto root_surface_transformation =
2551  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
2552 
2553  context.SetRootSurfaceTransformation(root_surface_transformation);
2554 
2556  context.GetCompositor().SetNextPresentCallback(
2557  [&](const FlutterLayer** layers, size_t layers_count) {
2558  ASSERT_EQ(layers_count, 2u);
2559 
2560  {
2562  platform_view.struct_size = sizeof(platform_view);
2563  platform_view.identifier = 42;
2564 
2565  FlutterLayer layer = {};
2566  layer.struct_size = sizeof(layer);
2568  layer.platform_view = &platform_view;
2569  layer.size = FlutterSizeMake(600.0, 1024.0);
2570  layer.offset = FlutterPointMake(0.0, -256.0);
2571 
2572  ASSERT_EQ(*layers[0], layer);
2573 
2574  const auto** mutations = platform_view.mutations;
2575 
2576  ASSERT_EQ(mutations[0]->type,
2578  ASSERT_EQ(SkMatrixMake(mutations[0]->transformation),
2579  root_surface_transformation);
2580 
2581  ASSERT_EQ(mutations[1]->type,
2583  ASSERT_EQ(SkRectMake(mutations[1]->clip_rect),
2584  SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
2585 
2586  ASSERT_EQ(mutations[2]->type,
2588  ASSERT_EQ(SkMatrixMake(mutations[2]->transformation),
2589  SkMatrix::Translate(512.0, 0.0));
2590 
2591  ASSERT_EQ(mutations[3]->type,
2593  ASSERT_EQ(SkRectMake(mutations[3]->clip_rect),
2594  SkRect::MakeLTRB(0.0, 0.0, 512.0, 600.0));
2595 
2596  ASSERT_EQ(mutations[4]->type,
2598  ASSERT_EQ(SkMatrixMake(mutations[4]->transformation),
2599  SkMatrix::Translate(-256.0, 0.0));
2600 
2601  ASSERT_EQ(mutations[5]->type,
2603  ASSERT_EQ(SkRectMake(mutations[5]->clip_rect),
2604  SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
2605  }
2606 
2607  latch.Signal();
2608  });
2609 
2610  auto engine = builder.LaunchEngine();
2611  ASSERT_TRUE(engine.is_valid());
2612 
2613  FlutterWindowMetricsEvent event = {};
2614  event.struct_size = sizeof(event);
2615  event.width = 1024;
2616  event.height = 600;
2617  event.pixel_ratio = 1.0;
2619  kSuccess);
2620 
2621  latch.Wait();
2622 }
2623 
2624 TEST_F(EmbedderTest, ObjectsCanBePostedViaPorts) {
2625  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2626  EmbedderConfigBuilder builder(context);
2627  builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
2628  builder.SetDartEntrypoint("objects_can_be_posted");
2629 
2630  // Synchronously acquire the send port from the Dart end. We will be using
2631  // this to send message. The Dart end will just echo those messages back to us
2632  // for inspection.
2635  context.AddNativeCallback("SignalNativeCount",
2636  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2638  Dart_GetNativeArgument(args, 0));
2639  event.Signal();
2640  }));
2641  auto engine = builder.LaunchEngine();
2642  ASSERT_TRUE(engine.is_valid());
2643  event.Wait();
2644  ASSERT_NE(port, 0);
2645 
2646  using Trampoline = std::function<void(Dart_Handle message)>;
2647  Trampoline trampoline;
2648 
2649  context.AddNativeCallback("SendObjectToNativeCode",
2650  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2651  FML_CHECK(trampoline);
2652  auto trampoline_copy = trampoline;
2653  trampoline = nullptr;
2654  trampoline_copy(Dart_GetNativeArgument(args, 0));
2655  }));
2656 
2657  // Check null.
2658  {
2659  FlutterEngineDartObject object = {};
2661  trampoline = [&](Dart_Handle handle) {
2662  ASSERT_TRUE(Dart_IsNull(handle));
2663  event.Signal();
2664  };
2665  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2666  kSuccess);
2667  event.Wait();
2668  }
2669 
2670  // Check bool.
2671  {
2672  FlutterEngineDartObject object = {};
2674  object.bool_value = true;
2675  trampoline = [&](Dart_Handle handle) {
2676  ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(handle));
2677  event.Signal();
2678  };
2679  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2680  kSuccess);
2681  event.Wait();
2682  }
2683 
2684  // Check int32.
2685  {
2686  FlutterEngineDartObject object = {};
2688  object.int32_value = 1988;
2689  trampoline = [&](Dart_Handle handle) {
2690  ASSERT_EQ(tonic::DartConverter<int32_t>::FromDart(handle), 1988);
2691  event.Signal();
2692  };
2693  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2694  kSuccess);
2695  event.Wait();
2696  }
2697 
2698  // Check int64.
2699  {
2700  FlutterEngineDartObject object = {};
2702  object.int64_value = 1988;
2703  trampoline = [&](Dart_Handle handle) {
2704  ASSERT_EQ(tonic::DartConverter<int64_t>::FromDart(handle), 1988);
2705  event.Signal();
2706  };
2707  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2708  kSuccess);
2709  event.Wait();
2710  }
2711 
2712  // Check double.
2713  {
2714  FlutterEngineDartObject object = {};
2716  object.double_value = 1988.0;
2717  trampoline = [&](Dart_Handle handle) {
2718  ASSERT_DOUBLE_EQ(tonic::DartConverter<double>::FromDart(handle), 1988.0);
2719  event.Signal();
2720  };
2721  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2722  kSuccess);
2723  event.Wait();
2724  }
2725 
2726  // Check string.
2727  {
2728  const char* message = "Hello. My name is Inigo Montoya.";
2729  FlutterEngineDartObject object = {};
2731  object.string_value = message;
2732  trampoline = [&](Dart_Handle handle) {
2734  std::string{message});
2735  event.Signal();
2736  };
2737  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2738  kSuccess);
2739  event.Wait();
2740  }
2741 
2742  // Check buffer (copied out).
2743  {
2744  std::vector<uint8_t> message;
2745  message.resize(1988);
2746 
2747  ASSERT_TRUE(MemsetPatternSetOrCheck(
2749 
2751 
2752  buffer.struct_size = sizeof(buffer);
2753  buffer.user_data = nullptr;
2754  buffer.buffer_collect_callback = nullptr;
2755  buffer.buffer = message.data();
2756  buffer.buffer_size = message.size();
2757 
2758  FlutterEngineDartObject object = {};
2760  object.buffer_value = &buffer;
2761  trampoline = [&](Dart_Handle handle) {
2762  intptr_t length = 0;
2763  Dart_ListLength(handle, &length);
2764  ASSERT_EQ(length, 1988);
2765  // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
2766  // DartConvertor in tonic is broken which is preventing the buffer
2767  // being checked here. Fix tonic and strengthen this check. For now, just
2768  // the buffer length is checked.
2769  event.Signal();
2770  };
2771  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2772  kSuccess);
2773  event.Wait();
2774  }
2775 
2776  std::vector<uint8_t> message;
2777  fml::AutoResetWaitableEvent buffer_released_latch;
2778 
2779  // Check buffer (caller own buffer with zero copy transfer).
2780  {
2781  message.resize(1988);
2782 
2783  ASSERT_TRUE(MemsetPatternSetOrCheck(
2785 
2787 
2788  buffer.struct_size = sizeof(buffer);
2789  buffer.user_data = &buffer_released_latch;
2790  buffer.buffer_collect_callback = +[](void* user_data) {
2791  reinterpret_cast<fml::AutoResetWaitableEvent*>(user_data)->Signal();
2792  };
2793  buffer.buffer = message.data();
2794  buffer.buffer_size = message.size();
2795 
2796  FlutterEngineDartObject object = {};
2798  object.buffer_value = &buffer;
2799  trampoline = [&](Dart_Handle handle) {
2800  intptr_t length = 0;
2801  Dart_ListLength(handle, &length);
2802  ASSERT_EQ(length, 1988);
2803  // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
2804  // DartConvertor in tonic is broken which is preventing the buffer
2805  // being checked here. Fix tonic and strengthen this check. For now, just
2806  // the buffer length is checked.
2807  event.Signal();
2808  };
2809  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2810  kSuccess);
2811  event.Wait();
2812  }
2813 
2814  engine.reset();
2815 
2816  // We cannot determine when the VM will GC objects that might have external
2817  // typed data finalizers. Since we need to ensure that we correctly wired up
2818  // finalizers from the embedders, we force the VM to collect all objects but
2819  // just shutting it down.
2820  buffer_released_latch.Wait();
2821 }
2822 
2823 TEST_F(EmbedderTest, CompositorCanPostZeroLayersForPresentation) {
2824  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2825 
2826  EmbedderConfigBuilder builder(context);
2827  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2828  builder.SetCompositor();
2829  builder.SetDartEntrypoint("empty_scene_posts_zero_layers_to_compositor");
2830  builder.SetRenderTargetType(
2832 
2834 
2835  context.GetCompositor().SetNextPresentCallback(
2836  [&](const FlutterLayer** layers, size_t layers_count) {
2837  ASSERT_EQ(layers_count, 0u);
2838  latch.Signal();
2839  });
2840 
2841  auto engine = builder.LaunchEngine();
2842 
2843  FlutterWindowMetricsEvent event = {};
2844  event.struct_size = sizeof(event);
2845  event.width = 300;
2846  event.height = 200;
2847  event.pixel_ratio = 1.0;
2849  kSuccess);
2850  ASSERT_TRUE(engine.is_valid());
2851  latch.Wait();
2852 
2853  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
2854 }
2855 
2856 TEST_F(EmbedderTest, CompositorCanPostOnlyPlatformViews) {
2857  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2858 
2859  EmbedderConfigBuilder builder(context);
2860  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2861  builder.SetCompositor();
2862  builder.SetDartEntrypoint("compositor_can_post_only_platform_views");
2863  builder.SetRenderTargetType(
2865 
2867 
2868  context.GetCompositor().SetNextPresentCallback(
2869  [&](const FlutterLayer** layers, size_t layers_count) {
2870  ASSERT_EQ(layers_count, 2u);
2871 
2872  // Layer 0
2873  {
2875  platform_view.struct_size = sizeof(platform_view);
2876  platform_view.identifier = 42;
2877  FlutterLayer layer = {};
2878  layer.struct_size = sizeof(layer);
2880  layer.platform_view = &platform_view;
2881  layer.size = FlutterSizeMake(300.0, 200.0);
2882  layer.offset = FlutterPointMake(0.0, 0.0);
2883 
2884  ASSERT_EQ(*layers[0], layer);
2885  }
2886 
2887  // Layer 1
2888  {
2890  platform_view.struct_size = sizeof(platform_view);
2891  platform_view.identifier = 24;
2892  FlutterLayer layer = {};
2893  layer.struct_size = sizeof(layer);
2895  layer.platform_view = &platform_view;
2896  layer.size = FlutterSizeMake(300.0, 200.0);
2897  layer.offset = FlutterPointMake(0.0, 0.0);
2898 
2899  ASSERT_EQ(*layers[1], layer);
2900  }
2901  latch.Signal();
2902  });
2903 
2904  auto engine = builder.LaunchEngine();
2905 
2906  FlutterWindowMetricsEvent event = {};
2907  event.struct_size = sizeof(event);
2908  event.width = 300;
2909  event.height = 200;
2910  event.pixel_ratio = 1.0;
2912  kSuccess);
2913  ASSERT_TRUE(engine.is_valid());
2914  latch.Wait();
2915 
2916  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
2917 }
2918 
2919 TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) {
2920  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2921 
2922  EmbedderConfigBuilder builder(context);
2923  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2924  builder.SetCompositor();
2925  builder.SetDartEntrypoint("render_targets_are_recycled");
2926  builder.SetRenderTargetType(
2928 
2929  fml::CountDownLatch latch(2);
2930 
2931  context.AddNativeCallback("SignalNativeTest",
2932  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2933  latch.CountDown();
2934  }));
2935 
2936  context.GetCompositor().SetNextPresentCallback(
2937  [&](const FlutterLayer** layers, size_t layers_count) {
2938  ASSERT_EQ(layers_count, 20u);
2939  latch.CountDown();
2940  });
2941 
2942  auto engine = builder.LaunchEngine();
2943  ASSERT_TRUE(engine.is_valid());
2944 
2945  FlutterWindowMetricsEvent event = {};
2946  event.struct_size = sizeof(event);
2947  event.width = 300;
2948  event.height = 200;
2949  event.pixel_ratio = 1.0;
2951  kSuccess);
2952 
2953  latch.Wait();
2954  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 10u);
2955  ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
2956  ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 0u);
2957  // Killing the engine should immediately collect all pending render targets.
2958  engine.reset();
2959  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
2960  ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
2961  ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 10u);
2962 }
2963 
2964 TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) {
2965  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
2966 
2967  EmbedderConfigBuilder builder(context);
2968  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2969  builder.SetCompositor();
2970  builder.SetDartEntrypoint("render_targets_are_recycled");
2971  builder.SetRenderTargetType(
2973 
2974  fml::CountDownLatch latch(2);
2975 
2976  context.AddNativeCallback("SignalNativeTest",
2977  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2978  latch.CountDown();
2979  }));
2980 
2981  size_t frame_count = 0;
2982  std::vector<void*> first_frame_backing_store_user_data;
2983  context.GetCompositor().SetPresentCallback(
2984  [&](const FlutterLayer** layers, size_t layers_count) {
2985  ASSERT_EQ(layers_count, 20u);
2986 
2987  if (first_frame_backing_store_user_data.size() == 0u) {
2988  for (size_t i = 0; i < layers_count; ++i) {
2989  if (layers[i]->type == kFlutterLayerContentTypeBackingStore) {
2990  first_frame_backing_store_user_data.push_back(
2991  layers[i]->backing_store->user_data);
2992  }
2993  }
2994  return;
2995  }
2996 
2997  ASSERT_EQ(first_frame_backing_store_user_data.size(), 10u);
2998 
2999  frame_count++;
3000  std::vector<void*> backing_store_user_data;
3001  for (size_t i = 0; i < layers_count; ++i) {
3002  if (layers[i]->type == kFlutterLayerContentTypeBackingStore) {
3003  backing_store_user_data.push_back(
3004  layers[i]->backing_store->user_data);
3005  }
3006  }
3007 
3008  ASSERT_EQ(backing_store_user_data.size(), 10u);
3009 
3010  ASSERT_EQ(first_frame_backing_store_user_data, backing_store_user_data);
3011 
3012  if (frame_count == 20) {
3013  latch.CountDown();
3014  }
3015  },
3016  false // one shot
3017  );
3018 
3019  auto engine = builder.LaunchEngine();
3020  ASSERT_TRUE(engine.is_valid());
3021 
3022  FlutterWindowMetricsEvent event = {};
3023  event.struct_size = sizeof(event);
3024  event.width = 300;
3025  event.height = 200;
3026  event.pixel_ratio = 1.0;
3028  kSuccess);
3029 
3030  latch.Wait();
3031 }
3032 
3033 TEST_F(EmbedderTest, FrameInfoContainsValidWidthAndHeight) {
3034  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3035 
3036  EmbedderConfigBuilder builder(context);
3037  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3038  builder.SetDartEntrypoint("push_frames_over_and_over");
3039 
3040  const auto root_surface_transformation =
3041  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
3042 
3043  context.SetRootSurfaceTransformation(root_surface_transformation);
3044 
3045  auto engine = builder.LaunchEngine();
3046 
3047  // Send a window metrics events so frames may be scheduled.
3048  FlutterWindowMetricsEvent event = {};
3049  event.struct_size = sizeof(event);
3050  event.width = 1024;
3051  event.height = 600;
3052  event.pixel_ratio = 1.0;
3054  kSuccess);
3055  ASSERT_TRUE(engine.is_valid());
3056 
3057  fml::CountDownLatch frame_latch(10);
3058 
3059  context.AddNativeCallback("SignalNativeTest",
3060  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3061  /* Nothing to do. */
3062  }));
3063 
3064  static_cast<EmbedderTestContextGL&>(context).SetGLGetFBOCallback(
3065  [&event, &frame_latch](FlutterFrameInfo frame_info) {
3066  // width and height are rotated by 90 deg
3067  ASSERT_EQ(frame_info.size.width, event.height);
3068  ASSERT_EQ(frame_info.size.height, event.width);
3069 
3070  frame_latch.CountDown();
3071  });
3072 
3073  frame_latch.Wait();
3074 }
3075 
3076 TEST_F(EmbedderTest, MustNotRunWithBothFBOCallbacksSet) {
3077  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3078 
3079  EmbedderConfigBuilder builder(context);
3080  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3081  builder.SetOpenGLFBOCallBack();
3082 
3083  auto engine = builder.LaunchEngine();
3084  ASSERT_FALSE(engine.is_valid());
3085 }
3086 
3087 TEST_F(EmbedderTest, MustNotRunWithBothPresentCallbacksSet) {
3088  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3089 
3090  EmbedderConfigBuilder builder(context);
3091  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3092  builder.SetOpenGLPresentCallBack();
3093 
3094  auto engine = builder.LaunchEngine();
3095  ASSERT_FALSE(engine.is_valid());
3096 }
3097 
3098 TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) {
3099  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3100 
3101  EmbedderConfigBuilder builder(context);
3102  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3103  builder.SetDartEntrypoint("push_frames_over_and_over");
3104 
3105  const auto root_surface_transformation =
3106  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
3107 
3108  context.SetRootSurfaceTransformation(root_surface_transformation);
3109 
3110  auto engine = builder.LaunchEngine();
3111 
3112  // Send a window metrics events so frames may be scheduled.
3113  FlutterWindowMetricsEvent event = {};
3114  event.struct_size = sizeof(event);
3115  event.width = 1024;
3116  event.height = 600;
3117  event.pixel_ratio = 1.0;
3119  kSuccess);
3120  ASSERT_TRUE(engine.is_valid());
3121 
3122  fml::CountDownLatch frame_latch(10);
3123 
3124  context.AddNativeCallback("SignalNativeTest",
3125  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3126  /* Nothing to do. */
3127  }));
3128 
3129  const uint32_t window_fbo_id =
3130  static_cast<EmbedderTestContextGL&>(context).GetWindowFBOId();
3131  static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3132  [window_fbo_id = window_fbo_id, &frame_latch](uint32_t fbo_id) {
3133  ASSERT_EQ(fbo_id, window_fbo_id);
3134 
3135  frame_latch.CountDown();
3136  });
3137 
3138  frame_latch.Wait();
3139 }
3140 
3141 TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithDisplayId) {
3142  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3143 
3144  EmbedderConfigBuilder builder(context);
3145  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3146  builder.SetCompositor();
3147  builder.SetDartEntrypoint("empty_scene");
3149  context.AddNativeCallback(
3150  "SignalNativeTest",
3151  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3152 
3153  auto engine = builder.LaunchEngine();
3154 
3155  ASSERT_TRUE(engine.is_valid());
3156 
3157  FlutterEngineDisplay display;
3158  display.struct_size = sizeof(FlutterEngineDisplay);
3159  display.display_id = 1;
3160  display.refresh_rate = 20;
3161 
3162  std::vector<FlutterEngineDisplay> displays = {display};
3163 
3165  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3166  displays.size());
3167  ASSERT_EQ(result, kSuccess);
3168 
3169  flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
3170  ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
3171 
3172  FlutterWindowMetricsEvent event = {};
3173  event.struct_size = sizeof(event);
3174  event.width = 800;
3175  event.height = 600;
3176  event.pixel_ratio = 1.0;
3178  kSuccess);
3179 
3180  latch.Wait();
3181 }
3182 
3183 TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithoutDisplayId) {
3184  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3185 
3186  EmbedderConfigBuilder builder(context);
3187  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3188  builder.SetCompositor();
3189  builder.SetDartEntrypoint("empty_scene");
3191  context.AddNativeCallback(
3192  "SignalNativeTest",
3193  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3194 
3195  auto engine = builder.LaunchEngine();
3196 
3197  ASSERT_TRUE(engine.is_valid());
3198 
3199  FlutterEngineDisplay display;
3200  display.struct_size = sizeof(FlutterEngineDisplay);
3201  display.single_display = true;
3202  display.refresh_rate = 20;
3203 
3204  std::vector<FlutterEngineDisplay> displays = {display};
3205 
3207  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3208  displays.size());
3209  ASSERT_EQ(result, kSuccess);
3210 
3211  flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
3212  ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
3213 
3214  FlutterWindowMetricsEvent event = {};
3215  event.struct_size = sizeof(event);
3216  event.width = 800;
3217  event.height = 600;
3218  event.pixel_ratio = 1.0;
3220  kSuccess);
3221 
3222  latch.Wait();
3223 }
3224 
3225 TEST_F(EmbedderTest, SetValidMultiDisplayConfiguration) {
3226  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3227 
3228  EmbedderConfigBuilder builder(context);
3229  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3230  builder.SetCompositor();
3231  builder.SetDartEntrypoint("empty_scene");
3233  context.AddNativeCallback(
3234  "SignalNativeTest",
3235  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3236 
3237  auto engine = builder.LaunchEngine();
3238 
3239  ASSERT_TRUE(engine.is_valid());
3240 
3241  FlutterEngineDisplay display_1;
3242  display_1.struct_size = sizeof(FlutterEngineDisplay);
3243  display_1.display_id = 1;
3244  display_1.single_display = false;
3245  display_1.refresh_rate = 20;
3246 
3247  FlutterEngineDisplay display_2;
3248  display_2.struct_size = sizeof(FlutterEngineDisplay);
3249  display_2.display_id = 2;
3250  display_2.single_display = false;
3251  display_2.refresh_rate = 60;
3252 
3253  std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
3254 
3256  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3257  displays.size());
3258  ASSERT_EQ(result, kSuccess);
3259 
3260  flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
3261  ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display_1.refresh_rate);
3262 
3263  FlutterWindowMetricsEvent event = {};
3264  event.struct_size = sizeof(event);
3265  event.width = 800;
3266  event.height = 600;
3267  event.pixel_ratio = 1.0;
3269  kSuccess);
3270 
3271  latch.Wait();
3272 }
3273 
3274 TEST_F(EmbedderTest, MultipleDisplaysWithSingleDisplayTrueIsInvalid) {
3275  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3276 
3277  EmbedderConfigBuilder builder(context);
3278  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3279  builder.SetCompositor();
3280  builder.SetDartEntrypoint("empty_scene");
3282  context.AddNativeCallback(
3283  "SignalNativeTest",
3284  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3285 
3286  auto engine = builder.LaunchEngine();
3287 
3288  ASSERT_TRUE(engine.is_valid());
3289 
3290  FlutterEngineDisplay display_1;
3291  display_1.struct_size = sizeof(FlutterEngineDisplay);
3292  display_1.display_id = 1;
3293  display_1.single_display = true;
3294  display_1.refresh_rate = 20;
3295 
3296  FlutterEngineDisplay display_2;
3297  display_2.struct_size = sizeof(FlutterEngineDisplay);
3298  display_2.display_id = 2;
3299  display_2.single_display = true;
3300  display_2.refresh_rate = 60;
3301 
3302  std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
3303 
3305  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3306  displays.size());
3307  ASSERT_NE(result, kSuccess);
3308 
3309  FlutterWindowMetricsEvent event = {};
3310  event.struct_size = sizeof(event);
3311  event.width = 800;
3312  event.height = 600;
3313  event.pixel_ratio = 1.0;
3315  kSuccess);
3316 
3317  latch.Wait();
3318 }
3319 
3320 TEST_F(EmbedderTest, MultipleDisplaysWithSameDisplayIdIsInvalid) {
3321  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3322 
3323  EmbedderConfigBuilder builder(context);
3324  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3325  builder.SetCompositor();
3326  builder.SetDartEntrypoint("empty_scene");
3328  context.AddNativeCallback(
3329  "SignalNativeTest",
3330  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3331 
3332  auto engine = builder.LaunchEngine();
3333 
3334  ASSERT_TRUE(engine.is_valid());
3335 
3336  FlutterEngineDisplay display_1;
3337  display_1.struct_size = sizeof(FlutterEngineDisplay);
3338  display_1.display_id = 1;
3339  display_1.single_display = false;
3340  display_1.refresh_rate = 20;
3341 
3342  FlutterEngineDisplay display_2;
3343  display_2.struct_size = sizeof(FlutterEngineDisplay);
3344  display_2.display_id = 1;
3345  display_2.single_display = false;
3346  display_2.refresh_rate = 60;
3347 
3348  std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
3349 
3351  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3352  displays.size());
3353  ASSERT_NE(result, kSuccess);
3354 
3355  FlutterWindowMetricsEvent event = {};
3356  event.struct_size = sizeof(event);
3357  event.width = 800;
3358  event.height = 600;
3359  event.pixel_ratio = 1.0;
3361  kSuccess);
3362 
3363  latch.Wait();
3364 }
3365 
3366 TEST_F(EmbedderTest, CompositorRenderTargetsNotRecycledWhenAvoidsCacheSet) {
3367  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3368 
3369  EmbedderConfigBuilder builder(context);
3370  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
3371  builder.SetCompositor(/*avoid_backing_store_cache=*/true);
3372  builder.SetDartEntrypoint("render_targets_are_recycled");
3373  builder.SetRenderTargetType(
3375 
3376  const unsigned num_frames = 8;
3377  const unsigned num_engine_layers = 10;
3378  const unsigned num_backing_stores = num_frames * num_engine_layers;
3379  fml::CountDownLatch latch(1 + num_frames); // 1 for native test signal.
3380 
3381  context.AddNativeCallback("SignalNativeTest",
3382  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3383  latch.CountDown();
3384  }));
3385 
3386  context.GetCompositor().SetPresentCallback(
3387  [&](const FlutterLayer** layers, size_t layers_count) {
3388  ASSERT_EQ(layers_count, 20u);
3389  latch.CountDown();
3390  },
3391  /*one_shot=*/false);
3392 
3393  auto engine = builder.LaunchEngine();
3394  ASSERT_TRUE(engine.is_valid());
3395 
3396  FlutterWindowMetricsEvent event = {};
3397  event.struct_size = sizeof(event);
3398  event.width = 300;
3399  event.height = 200;
3400  event.pixel_ratio = 1.0;
3402  kSuccess);
3403 
3404  latch.Wait();
3405 
3406  ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(),
3407  num_backing_stores);
3408  // Killing the engine should collect all the frames.
3409  engine.reset();
3410  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
3411 }
3412 
3413 TEST_F(EmbedderTest, SnapshotRenderTargetScalesDownToDriverMax) {
3414  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3415 
3416  EmbedderConfigBuilder builder(context);
3417  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3418  builder.SetCompositor();
3419 
3420  auto max_size = context.GetCompositor().GetGrContext()->maxRenderTargetSize();
3421 
3422  context.AddIsolateCreateCallback([&]() {
3423  Dart_Handle snapshot_large_scene = Dart_GetField(
3424  Dart_RootLibrary(), tonic::ToDart("snapshot_large_scene"));
3425  tonic::DartInvoke(snapshot_large_scene, {tonic::ToDart<int64_t>(max_size)});
3426  });
3427 
3429  context.AddNativeCallback(
3430  "SnapshotsCallback", CREATE_NATIVE_ENTRY(([&](Dart_NativeArguments args) {
3431  auto get_arg = [&args](int index) {
3432  Dart_Handle dart_image = Dart_GetNativeArgument(args, index);
3433  Dart_Handle internal_image =
3434  Dart_GetField(dart_image, tonic::ToDart("_image"));
3436  internal_image);
3437  };
3438 
3439  CanvasImage* big_image = get_arg(0);
3440  ASSERT_EQ(big_image->width(), max_size);
3441  ASSERT_EQ(big_image->height(), max_size / 2);
3442 
3443  CanvasImage* small_image = get_arg(1);
3444  ASSERT_TRUE(ImageMatchesFixture("snapshot_large_scene.png",
3445  small_image->image()));
3446 
3447  latch.Signal();
3448  })));
3449 
3450  UniqueEngine engine = builder.LaunchEngine();
3451  ASSERT_TRUE(engine.is_valid());
3452 
3453  latch.Wait();
3454 }
3455 
3456 TEST_F(EmbedderTest, ObjectsPostedViaPortsServicedOnSecondaryTaskHeap) {
3457  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3458  EmbedderConfigBuilder builder(context);
3459  builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
3460  builder.SetDartEntrypoint("objects_can_be_posted");
3461 
3462  // Synchronously acquire the send port from the Dart end. We will be using
3463  // this to send message. The Dart end will just echo those messages back to us
3464  // for inspection.
3467  context.AddNativeCallback("SignalNativeCount",
3468  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3470  Dart_GetNativeArgument(args, 0));
3471  event.Signal();
3472  }));
3473  auto engine = builder.LaunchEngine();
3474  ASSERT_TRUE(engine.is_valid());
3475  event.Wait();
3476  ASSERT_NE(port, 0);
3477 
3478  using Trampoline = std::function<void(Dart_Handle message)>;
3479  Trampoline trampoline;
3480 
3481  context.AddNativeCallback("SendObjectToNativeCode",
3482  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3483  FML_CHECK(trampoline);
3484  auto trampoline_copy = trampoline;
3485  trampoline = nullptr;
3486  trampoline_copy(Dart_GetNativeArgument(args, 0));
3487  }));
3488 
3489  // Send a boolean value and assert that it's received by the right heap.
3490  {
3491  FlutterEngineDartObject object = {};
3493  object.bool_value = true;
3494  trampoline = [&](Dart_Handle handle) {
3495  ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(handle));
3497  EXPECT_EQ(task_grade, fml::TaskSourceGrade::kDartMicroTasks);
3498  event.Signal();
3499  };
3500  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
3501  kSuccess);
3502  event.Wait();
3503  }
3504 }
3505 
3506 TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLTexture) {
3507  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3508  EmbedderConfigBuilder builder(context);
3509  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3510  builder.SetCompositor();
3511  builder.SetRenderTargetType(
3513  builder.SetDartEntrypoint("invalid_backingstore");
3514 
3515  class TestCollectOnce {
3516  public:
3517  // Collect() should only be called once
3518  void Collect() {
3519  ASSERT_FALSE(collected_);
3520  collected_ = true;
3521  }
3522 
3523  private:
3524  bool collected_ = false;
3525  };
3527 
3528  builder.GetCompositor().create_backing_store_callback =
3529  [](const FlutterBackingStoreConfig* config, //
3530  FlutterBackingStore* backing_store_out, //
3531  void* user_data //
3532  ) {
3533  backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
3534  // Deliberately set this to be invalid
3535  backing_store_out->user_data = nullptr;
3536  backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeTexture;
3537  backing_store_out->open_gl.texture.target = 0;
3538  backing_store_out->open_gl.texture.name = 0;
3539  backing_store_out->open_gl.texture.format = 0;
3540  static TestCollectOnce collect_once_user_data;
3541  collect_once_user_data = {};
3542  backing_store_out->open_gl.texture.user_data = &collect_once_user_data;
3543  backing_store_out->open_gl.texture.destruction_callback =
3544  [](void* user_data) {
3545  reinterpret_cast<TestCollectOnce*>(user_data)->Collect();
3546  };
3547  return true;
3548  };
3549 
3550  context.AddNativeCallback(
3551  "SignalNativeTest",
3553  [&latch](Dart_NativeArguments args) { latch.Signal(); }));
3554 
3555  auto engine = builder.LaunchEngine();
3556 
3557  // Send a window metrics events so frames may be scheduled.
3558  FlutterWindowMetricsEvent event = {};
3559  event.struct_size = sizeof(event);
3560  event.width = 800;
3561  event.height = 600;
3562  event.pixel_ratio = 1.0;
3564  kSuccess);
3565  ASSERT_TRUE(engine.is_valid());
3566  latch.Wait();
3567 }
3568 
3569 TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLFramebuffer) {
3570  auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
3571  EmbedderConfigBuilder builder(context);
3572  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3573  builder.SetCompositor();
3574  builder.SetRenderTargetType(
3576  builder.SetDartEntrypoint("invalid_backingstore");
3577 
3578  class TestCollectOnce {
3579  public:
3580  // Collect() should only be called once
3581  void Collect() {
3582  ASSERT_FALSE(collected_);
3583  collected_ = true;
3584  }
3585 
3586  private:
3587  bool collected_ = false;
3588  };
3590 
3591  builder.GetCompositor().create_backing_store_callback =
3592  [](const FlutterBackingStoreConfig* config, //
3593  FlutterBackingStore* backing_store_out, //
3594  void* user_data //
3595  ) {
3596  backing_store_out->type = kFlutterBackingStoreTypeOpenGL;
3597  // Deliberately set this to be invalid
3598  backing_store_out->user_data = nullptr;
3599  backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
3600  backing_store_out->open_gl.framebuffer.target = 0;
3601  backing_store_out->open_gl.framebuffer.name = 0;
3602  static TestCollectOnce collect_once_user_data;
3603  collect_once_user_data = {};
3604  backing_store_out->open_gl.framebuffer.user_data =
3605  &collect_once_user_data;
3606  backing_store_out->open_gl.framebuffer.destruction_callback =
3607  [](void* user_data) {
3608  reinterpret_cast<TestCollectOnce*>(user_data)->Collect();
3609  };
3610  return true;
3611  };
3612 
3613  context.AddNativeCallback(
3614  "SignalNativeTest",
3616  [&latch](Dart_NativeArguments args) { latch.Signal(); }));
3617 
3618  auto engine = builder.LaunchEngine();
3619 
3620  // Send a window metrics events so frames may be scheduled.
3621  FlutterWindowMetricsEvent event = {};
3622  event.struct_size = sizeof(event);
3623  event.width = 800;
3624  event.height = 600;
3625  event.pixel_ratio = 1.0;
3627  kSuccess);
3628  ASSERT_TRUE(engine.is_valid());
3629  latch.Wait();
3630 }
3631 
3632 TEST_F(EmbedderTest, ExternalTextureGLRefreshedTooOften) {
3633  TestGLSurface surface(SkISize::Make(100, 100));
3634  auto context = surface.GetGrContext();
3635 
3636  typedef void (*glGenTexturesProc)(uint32_t n, uint32_t * textures);
3637  glGenTexturesProc glGenTextures;
3638 
3639  glGenTextures = reinterpret_cast<glGenTexturesProc>(
3640  surface.GetProcAddress("glGenTextures"));
3641 
3642  uint32_t name;
3643  glGenTextures(1, &name);
3644 
3645  bool resolve_called = false;
3646 
3648  [&](int64_t, size_t, size_t) {
3649  resolve_called = true;
3650  auto res = std::make_unique<FlutterOpenGLTexture>();
3651  res->target = GR_GL_TEXTURE_2D;
3652  res->name = name;
3653  res->format = GR_GL_RGBA8;
3654  res->user_data = nullptr;
3655  res->destruction_callback = [](void*) {};
3656  res->width = res->height = 100;
3657  return res;
3658  });
3660 
3661  auto skia_surface = surface.GetOnscreenSurface();
3662  auto canvas = skia_surface->getCanvas();
3663 
3664  Texture* texture_ = &texture;
3665  texture_->Paint(*canvas, SkRect::MakeXYWH(0, 0, 100, 100), false,
3666  context.get(), SkSamplingOptions(SkFilterMode::kLinear));
3667 
3668  EXPECT_TRUE(resolve_called);
3669  resolve_called = false;
3670 
3671  texture_->Paint(*canvas, SkRect::MakeXYWH(0, 0, 100, 100), false,
3672  context.get(), SkSamplingOptions(SkFilterMode::kLinear));
3673 
3674  EXPECT_FALSE(resolve_called);
3675 
3676  texture_->MarkNewFrameAvailable();
3677  texture_->Paint(*canvas, SkRect::MakeXYWH(0, 0, 100, 100), false,
3678  context.get(), SkSamplingOptions(SkFilterMode::kLinear));
3679 
3680  EXPECT_TRUE(resolve_called);
3681 }
3682 
3683 } // namespace testing
3684 } // namespace flutter
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:2251
static TaskSourceGrade GetCurrentTaskSourceGrade()
G_BEGIN_DECLS FlValue * args
SkMatrix GetTotalMutationTransformationMatrix(const FlutterPlatformViewMutation **mutations, size_t count)
KeyCallType type
void FilterMutationsByType(const FlutterPlatformViewMutation **mutations, size_t count, FlutterPlatformViewMutationType type, std::function< void(const FlutterPlatformViewMutation &mutation)> handler)
FlutterRect FlutterRectMake(const SkRect &rect)
Specified an software allocation for Flutter to render into using the CPU.
Definition: embedder.h:1048
G_BEGIN_DECLS FlTexture * texture
size_t GetCachedEntriesCount() const
uint32_t width
Definition: embedder.h:328
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:1365
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:1956
int64_t FlutterEngineDartPort
Definition: embedder.h:1220
std::unique_ptr< flutter::PlatformViewIOS > platform_view
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:61
const FlutterBackingStore * backing_store
Definition: embedder.h:1099
FlutterPlatformViewIdentifier identifier
Definition: embedder.h:1024
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
Definition: shell.cc:674
FlutterSize size
The size of the layer (in physical pixels).
Definition: embedder.h:1108
FlutterTransformation transformation
Definition: embedder.h:1014
void reset(const T &value=Traits::InvalidValue())
Definition: unique_object.h:62
void * user_data
sk_sp< SkSurface > CreateRenderSurface(const FlutterLayer &layer, GrDirectContext *context)
FlutterSize FlutterSizeMake(double width, double height)
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:1377
GAsyncResult * result
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart Flags passed directly to the Dart VM without being interpreted by the Flutter shell observatory port
Definition: switches.h:75
A task runner that we expect the embedder to provide but whose implementation is a real FML task runn...
void SetCompositor(bool avoid_backing_store_cache=false)
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:2065
FlutterPoint offset
Definition: embedder.h:1106
size_t struct_size
This size of this struct. Must be sizeof(FlutterDisplay).
Definition: embedder.h:1193
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:20
const T & get() const
Definition: unique_object.h:87
A structure to represent a rectangle.
Definition: embedder.h:333
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
FlKeyEvent FlKeyResponderAsyncCallback callback
SkMatrix SkMatrixMake(const FlutterTransformation &xformation)
bool is_valid() const
Definition: unique_object.h:89
virtual void MarkNewFrameAvailable()=0
FlKeyEvent * event
uint32_t height
Definition: embedder.h:329
FlutterUIntSize size
The size of the surface that will be backed by the fbo.
Definition: embedder.h:363
void * GetProcAddress(const char *name) const
FlutterOpenGLTargetType type
Definition: embedder.h:954
size_t struct_size
The size of this struct. Must be sizeof(FlutterEngineDartBuffer).
Definition: embedder.h:1236
sk_sp< GrDirectContext > GetGrContext()
Indicates that the contents of this layer are determined by the embedder.
Definition: embedder.h:1087
FlutterSoftwareBackingStore software
The description of the software backing store.
Definition: embedder.h:1069
FlutterEngineDisplayId display_id
Definition: embedder.h:1195
size_t row_bytes
The number of bytes in a single row of the allocation.
Definition: embedder.h:969
FlutterPoint FlutterPointMake(double x, double y)
fml::TaskRunnerAffineWeakPtr< Rasterizer > GetRasterizer() const
Rasterizers may only be accessed on the raster task runner.
Definition: shell.cc:683
void SetRenderTaskRunner(const FlutterTaskRunnerDescription *runner)
#define CREATE_NATIVE_ENTRY(native_entry)
SkRect SkRectMake(const FlutterRect &rect)
double GetMainDisplayRefreshRate()
Queries the DisplayManager for the main display refresh rate.
Definition: shell.cc:1638
FlutterOpenGLBackingStore open_gl
The description of the OpenGL backing store.
Definition: embedder.h:1067
const FlutterPlatformView * platform_view
Definition: embedder.h:1102
FlutterLayerContentType type
Definition: embedder.h:1095
void(* glGenTexturesProc)(GLsizei n, GLuint *textures)
size_t mutations_count
Definition: embedder.h:1027
void SetPlatformTaskRunner(const FlutterTaskRunnerDescription *runner)
VoidCallback buffer_collect_callback
Definition: embedder.h:1260
double width
Definition: embedder.h:320
size_t struct_size
The size of this struct. Must be sizeof(FlutterBackingStore).
Definition: embedder.h:1055
flutter::EmbedderEngine * ToEmbedderEngine(const FlutterEngine &engine)
testing::EmbedderTest EmbedderTest
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition: embedder.h:565
size_t height
The number of rows in the allocation.
Definition: embedder.h:971
size_t length
FlutterBackingStoreType type
Specifies the type of backing store.
Definition: embedder.h:1061
virtual void Paint(SkCanvas &canvas, const SkRect &bounds, bool freeze, GrDirectContext *context, const SkSamplingOptions &sampling)=0
FlutterEngineResult
Definition: embedder.h:65
const FlutterPlatformViewMutation ** mutations
Definition: embedder.h:1040
const char * name
Definition: fuchsia.cc:50
FlutterRoundedRect clip_rounded_rect
Definition: embedder.h:1013
#define FML_CHECK(condition)
Definition: logging.h:68
static const uint8_t buffer[]
double height
Definition: embedder.h:321
FlutterPlatformViewMutationType type
The type of the mutation described by the subsequent union.
Definition: embedder.h:1009
std::function< std::unique_ptr< FlutterOpenGLTexture >(int64_t, size_t, size_t)> ExternalTextureCallback
size_t buffer_size
The size of the buffer.
Definition: embedder.h:1268
sk_sp< SkSurface > GetOnscreenSurface()
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformView).
Definition: embedder.h:1020
Dart_Handle ToDart(const T &object)
bool ImageMatchesFixture(const std::string &fixture_file_name, sk_sp< SkImage > scene_image)
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterWindowMetricsEvent *flutter_metrics)
Definition: embedder.cc:1388
FlutterRoundedRect FlutterRoundedRectMake(const SkRRect &rect)
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
FlutterEngineResult FlutterEngineRunInitialized(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Runs an initialized engine instance. An engine can be initialized via FlutterEngineInitialize. An initialized instance can only be run once. During and after this call, custom task runners supplied by the embedder are expected to start servicing tasks.
Definition: embedder.cc:1326
size_t struct_size
This size of this struct. Must be sizeof(FlutterLayer).
Definition: embedder.h:1092
FlutterTransformation FlutterTransformationMake(const SkMatrix &matrix)
void SetRenderTargetType(EmbedderTestBackingStoreProducer::RenderTargetType type)
FlutterEngineDartObjectType type
Definition: embedder.h:1279