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/paths.h"
18 #include "flutter/fml/synchronization/count_down_latch.h"
19 #include "flutter/fml/synchronization/waitable_event.h"
20 #include "flutter/fml/thread.h"
21 #include "flutter/runtime/dart_vm.h"
22 #include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
23 #include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"
24 #include "flutter/shell/platform/embedder/tests/embedder_test.h"
25 #include "flutter/shell/platform/embedder/tests/embedder_test_context_gl.h"
26 #include "flutter/shell/platform/embedder/tests/embedder_unittests_util.h"
27 #include "flutter/testing/assertions_skia.h"
28 #include "flutter/testing/testing.h"
29 #include "third_party/skia/include/core/SkSurface.h"
31 
32 namespace flutter {
33 namespace testing {
34 
36 
37 TEST_F(EmbedderTest, CanCreateOpenGLRenderingEngine) {
38  EmbedderConfigBuilder builder(
39  GetEmbedderContext(ContextType::kOpenGLContext));
40  builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
41  auto engine = builder.LaunchEngine();
42  ASSERT_TRUE(engine.is_valid());
43 }
44 
45 //------------------------------------------------------------------------------
46 /// If an incorrectly configured compositor is set on the engine, the engine
47 /// must fail to launch instead of failing to render a frame at a later point in
48 /// time.
49 ///
51  MustPreventEngineLaunchWhenRequiredCompositorArgsAreAbsent) {
52  auto& context = GetEmbedderContext(ContextType::kSoftwareContext);
53  EmbedderConfigBuilder builder(context);
54  builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
55  builder.SetCompositor();
56  builder.GetCompositor().create_backing_store_callback = nullptr;
58  builder.GetCompositor().present_layers_callback = nullptr;
59  auto engine = builder.LaunchEngine();
60  ASSERT_FALSE(engine.is_valid());
61 }
62 
63 //------------------------------------------------------------------------------
64 /// Must be able to render to a custom compositor whose render targets are fully
65 /// complete OpenGL textures.
66 ///
67 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) {
68  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
69 
70  EmbedderConfigBuilder builder(context);
71  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
72  builder.SetCompositor();
73  builder.SetDartEntrypoint("can_composite_platform_views");
74 
75  builder.SetRenderTargetType(
77 
78  fml::CountDownLatch latch(3);
79  context.GetCompositor().SetNextPresentCallback(
80  [&](const FlutterLayer** layers, size_t layers_count) {
81  ASSERT_EQ(layers_count, 3u);
82 
83  {
84  FlutterBackingStore backing_store = *layers[0]->backing_store;
85  backing_store.struct_size = sizeof(backing_store);
86  backing_store.type = kFlutterBackingStoreTypeOpenGL;
87  backing_store.did_update = true;
89 
90  FlutterLayer layer = {};
91  layer.struct_size = sizeof(layer);
93  layer.backing_store = &backing_store;
94  layer.size = FlutterSizeMake(800.0, 600.0);
95  layer.offset = FlutterPointMake(0, 0);
96 
97  ASSERT_EQ(*layers[0], layer);
98  }
99 
100  {
101  FlutterPlatformView platform_view = *layers[1]->platform_view;
102  platform_view.struct_size = sizeof(platform_view);
103  platform_view.identifier = 42;
104 
105  FlutterLayer layer = {};
106  layer.struct_size = sizeof(layer);
108  layer.platform_view = &platform_view;
109  layer.size = FlutterSizeMake(123.0, 456.0);
110  layer.offset = FlutterPointMake(1.0, 2.0);
111 
112  ASSERT_EQ(*layers[1], layer);
113  }
114 
115  {
116  FlutterBackingStore backing_store = *layers[2]->backing_store;
117  backing_store.struct_size = sizeof(backing_store);
118  backing_store.type = kFlutterBackingStoreTypeOpenGL;
119  backing_store.did_update = true;
121 
122  FlutterLayer layer = {};
123  layer.struct_size = sizeof(layer);
125  layer.backing_store = &backing_store;
126  layer.size = FlutterSizeMake(800.0, 600.0);
127  layer.offset = FlutterPointMake(0.0, 0.0);
128 
129  ASSERT_EQ(*layers[2], layer);
130  }
131 
132  latch.CountDown();
133  });
134 
135  context.AddNativeCallback(
136  "SignalNativeTest",
138  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
139 
140  auto engine = builder.LaunchEngine();
141 
142  // Send a window metrics events so frames may be scheduled.
143  FlutterWindowMetricsEvent event = {};
144  event.struct_size = sizeof(event);
145  event.width = 800;
146  event.height = 600;
147  event.pixel_ratio = 1.0;
149  kSuccess);
150  ASSERT_TRUE(engine.is_valid());
151 
152  latch.Wait();
153 }
154 
155 //------------------------------------------------------------------------------
156 /// Layers in a hierarchy containing a platform view should not be cached. The
157 /// other layers in the hierarchy should be, however.
158 TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) {
159  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
160 
161  EmbedderConfigBuilder builder(context);
162  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
163  builder.SetCompositor();
164  builder.SetDartEntrypoint("can_composite_platform_views_with_opacity");
165 
166  builder.SetRenderTargetType(
168 
169  fml::CountDownLatch setup(3);
170  fml::CountDownLatch verify(1);
171 
172  context.GetCompositor().SetNextPresentCallback(
173  [&](const FlutterLayer** layers, size_t layers_count) {
174  ASSERT_EQ(layers_count, 3u);
175 
176  {
177  FlutterBackingStore backing_store = *layers[0]->backing_store;
178  backing_store.struct_size = sizeof(backing_store);
179  backing_store.type = kFlutterBackingStoreTypeOpenGL;
180  backing_store.did_update = true;
182 
183  FlutterLayer layer = {};
184  layer.struct_size = sizeof(layer);
186  layer.backing_store = &backing_store;
187  layer.size = FlutterSizeMake(800.0, 600.0);
188  layer.offset = FlutterPointMake(0, 0);
189 
190  ASSERT_EQ(*layers[0], layer);
191  }
192 
193  {
194  FlutterPlatformView platform_view = *layers[1]->platform_view;
195  platform_view.struct_size = sizeof(platform_view);
196  platform_view.identifier = 42;
197 
198  FlutterLayer layer = {};
199  layer.struct_size = sizeof(layer);
201  layer.platform_view = &platform_view;
202  layer.size = FlutterSizeMake(123.0, 456.0);
203  layer.offset = FlutterPointMake(1.0, 2.0);
204 
205  ASSERT_EQ(*layers[1], layer);
206  }
207 
208  {
209  FlutterBackingStore backing_store = *layers[2]->backing_store;
210  backing_store.struct_size = sizeof(backing_store);
211  backing_store.type = kFlutterBackingStoreTypeOpenGL;
212  backing_store.did_update = true;
214 
215  FlutterLayer layer = {};
216  layer.struct_size = sizeof(layer);
218  layer.backing_store = &backing_store;
219  layer.size = FlutterSizeMake(800.0, 600.0);
220  layer.offset = FlutterPointMake(0.0, 0.0);
221 
222  ASSERT_EQ(*layers[2], layer);
223  }
224 
225  setup.CountDown();
226  });
227 
228  context.AddNativeCallback(
229  "SignalNativeTest",
231  [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
232 
233  UniqueEngine engine = builder.LaunchEngine();
234 
235  // Send a window metrics events so frames may be scheduled.
236  FlutterWindowMetricsEvent event = {};
237  event.struct_size = sizeof(event);
238  event.width = 800;
239  event.height = 600;
240  event.pixel_ratio = 1.0;
241  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
242  kSuccess);
243  ASSERT_TRUE(engine.is_valid());
244 
245  setup.Wait();
246  const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
248  const flutter::RasterCache& raster_cache =
249  shell.GetRasterizer()->compositor_context()->raster_cache();
250  // 3 layers total, but one of them had the platform view. So the cache
251  // should only have 2 entries.
252  ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 2u);
253  verify.CountDown();
254  });
255 
256  verify.Wait();
257 }
258 
259 //------------------------------------------------------------------------------
260 /// The RasterCache should normally be enabled.
261 ///
262 TEST_F(EmbedderTest, RasterCacheEnabled) {
263  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
264 
265  EmbedderConfigBuilder builder(context);
266  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
267  builder.SetCompositor();
268  builder.SetDartEntrypoint("can_composite_with_opacity");
269 
270  builder.SetRenderTargetType(
272 
273  fml::CountDownLatch setup(3);
274  fml::CountDownLatch verify(1);
275 
276  context.GetCompositor().SetNextPresentCallback(
277  [&](const FlutterLayer** layers, size_t layers_count) {
278  ASSERT_EQ(layers_count, 1u);
279 
280  {
281  FlutterBackingStore backing_store = *layers[0]->backing_store;
282  backing_store.struct_size = sizeof(backing_store);
283  backing_store.type = kFlutterBackingStoreTypeOpenGL;
284  backing_store.did_update = true;
286 
287  FlutterLayer layer = {};
288  layer.struct_size = sizeof(layer);
290  layer.backing_store = &backing_store;
291  layer.size = FlutterSizeMake(800.0, 600.0);
292  layer.offset = FlutterPointMake(0, 0);
293 
294  ASSERT_EQ(*layers[0], layer);
295  }
296 
297  setup.CountDown();
298  });
299 
300  context.AddNativeCallback(
301  "SignalNativeTest",
303  [&setup](Dart_NativeArguments args) { setup.CountDown(); }));
304 
305  UniqueEngine engine = builder.LaunchEngine();
306 
307  // Send a window metrics events so frames may be scheduled.
308  FlutterWindowMetricsEvent event = {};
309  event.struct_size = sizeof(event);
310  event.width = 800;
311  event.height = 600;
312  event.pixel_ratio = 1.0;
313  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
314  kSuccess);
315  ASSERT_TRUE(engine.is_valid());
316 
317  setup.Wait();
318  const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
320  const flutter::RasterCache& raster_cache =
321  shell.GetRasterizer()->compositor_context()->raster_cache();
322  ASSERT_EQ(raster_cache.GetCachedEntriesCount(), 1u);
323  verify.CountDown();
324  });
325 
326  verify.Wait();
327 }
328 
329 //------------------------------------------------------------------------------
330 /// Must be able to render using a custom compositor whose render targets for
331 /// the individual layers are OpenGL textures.
332 ///
333 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) {
334  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
335 
336  EmbedderConfigBuilder builder(context);
337  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
338  builder.SetCompositor();
339  builder.SetDartEntrypoint("can_composite_platform_views");
340 
341  builder.SetRenderTargetType(
343 
344  fml::CountDownLatch latch(3);
345  context.GetCompositor().SetNextPresentCallback(
346  [&](const FlutterLayer** layers, size_t layers_count) {
347  ASSERT_EQ(layers_count, 3u);
348 
349  {
350  FlutterBackingStore backing_store = *layers[0]->backing_store;
351  backing_store.struct_size = sizeof(backing_store);
352  backing_store.type = kFlutterBackingStoreTypeOpenGL;
353  backing_store.did_update = true;
355 
356  FlutterLayer layer = {};
357  layer.struct_size = sizeof(layer);
359  layer.backing_store = &backing_store;
360  layer.size = FlutterSizeMake(800.0, 600.0);
361  layer.offset = FlutterPointMake(0, 0);
362 
363  ASSERT_EQ(*layers[0], layer);
364  }
365 
366  {
367  FlutterPlatformView platform_view = *layers[1]->platform_view;
368  platform_view.struct_size = sizeof(platform_view);
369  platform_view.identifier = 42;
370 
371  FlutterLayer layer = {};
372  layer.struct_size = sizeof(layer);
374  layer.platform_view = &platform_view;
375  layer.size = FlutterSizeMake(123.0, 456.0);
376  layer.offset = FlutterPointMake(1.0, 2.0);
377 
378  ASSERT_EQ(*layers[1], layer);
379  }
380 
381  {
382  FlutterBackingStore backing_store = *layers[2]->backing_store;
383  backing_store.struct_size = sizeof(backing_store);
384  backing_store.type = kFlutterBackingStoreTypeOpenGL;
385  backing_store.did_update = true;
387 
388  FlutterLayer layer = {};
389  layer.struct_size = sizeof(layer);
391  layer.backing_store = &backing_store;
392  layer.size = FlutterSizeMake(800.0, 600.0);
393  layer.offset = FlutterPointMake(0.0, 0.0);
394 
395  ASSERT_EQ(*layers[2], layer);
396  }
397 
398  latch.CountDown();
399  });
400 
401  context.AddNativeCallback(
402  "SignalNativeTest",
404  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
405 
406  auto engine = builder.LaunchEngine();
407 
408  // Send a window metrics events so frames may be scheduled.
409  FlutterWindowMetricsEvent event = {};
410  event.struct_size = sizeof(event);
411  event.width = 800;
412  event.height = 600;
413  event.pixel_ratio = 1.0;
415  kSuccess);
416  ASSERT_TRUE(engine.is_valid());
417 
418  latch.Wait();
419 }
420 
421 //------------------------------------------------------------------------------
422 /// Must be able to render using a custom compositor whose render target for the
423 /// individual layers are software buffers.
424 ///
425 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) {
426  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
427 
428  EmbedderConfigBuilder builder(context);
429  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
430  builder.SetCompositor();
431  builder.SetDartEntrypoint("can_composite_platform_views");
432 
433  builder.SetRenderTargetType(
435 
436  fml::CountDownLatch latch(3);
437  context.GetCompositor().SetNextPresentCallback(
438  [&](const FlutterLayer** layers, size_t layers_count) {
439  ASSERT_EQ(layers_count, 3u);
440 
441  {
442  FlutterBackingStore backing_store = *layers[0]->backing_store;
443  backing_store.struct_size = sizeof(backing_store);
444  backing_store.type = kFlutterBackingStoreTypeSoftware;
445  backing_store.did_update = true;
446  ASSERT_FLOAT_EQ(
447  backing_store.software.row_bytes * backing_store.software.height,
448  800 * 4 * 600.0);
449 
450  FlutterLayer layer = {};
451  layer.struct_size = sizeof(layer);
453  layer.backing_store = &backing_store;
454  layer.size = FlutterSizeMake(800.0, 600.0);
455  layer.offset = FlutterPointMake(0, 0);
456 
457  ASSERT_EQ(*layers[0], layer);
458  }
459 
460  {
461  FlutterPlatformView platform_view = *layers[1]->platform_view;
462  platform_view.struct_size = sizeof(platform_view);
463  platform_view.identifier = 42;
464 
465  FlutterLayer layer = {};
466  layer.struct_size = sizeof(layer);
468  layer.platform_view = &platform_view;
469  layer.size = FlutterSizeMake(123.0, 456.0);
470  layer.offset = FlutterPointMake(1.0, 2.0);
471 
472  ASSERT_EQ(*layers[1], layer);
473  }
474 
475  {
476  FlutterBackingStore backing_store = *layers[2]->backing_store;
477  backing_store.struct_size = sizeof(backing_store);
478  backing_store.type = kFlutterBackingStoreTypeSoftware;
479  backing_store.did_update = true;
480  FlutterLayer layer = {};
481  layer.struct_size = sizeof(layer);
483  layer.backing_store = &backing_store;
484  layer.size = FlutterSizeMake(800.0, 600.0);
485  layer.offset = FlutterPointMake(0.0, 0.0);
486 
487  ASSERT_EQ(*layers[2], layer);
488  }
489 
490  latch.CountDown();
491  });
492 
493  context.AddNativeCallback(
494  "SignalNativeTest",
496  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
497 
498  auto engine = builder.LaunchEngine();
499 
500  // Send a window metrics events so frames may be scheduled.
501  FlutterWindowMetricsEvent event = {};
502  event.struct_size = sizeof(event);
503  event.width = 800;
504  event.height = 600;
505  event.pixel_ratio = 1.0;
507  kSuccess);
508  ASSERT_TRUE(engine.is_valid());
509 
510  latch.Wait();
511 }
512 
513 //------------------------------------------------------------------------------
514 /// Test the layer structure and pixels rendered when using a custom compositor.
515 ///
516 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) {
517  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
518 
519  EmbedderConfigBuilder builder(context);
520  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
521  builder.SetCompositor();
522  builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
523 
524  builder.SetRenderTargetType(
526 
527  fml::CountDownLatch latch(5);
528 
529  auto scene_image = context.GetNextSceneImage();
530 
531  context.GetCompositor().SetNextPresentCallback(
532  [&](const FlutterLayer** layers, size_t layers_count) {
533  ASSERT_EQ(layers_count, 5u);
534 
535  // Layer Root
536  {
537  FlutterBackingStore backing_store = *layers[0]->backing_store;
538  backing_store.type = kFlutterBackingStoreTypeOpenGL;
539  backing_store.did_update = true;
541 
542  FlutterLayer layer = {};
543  layer.struct_size = sizeof(layer);
545  layer.backing_store = &backing_store;
546  layer.size = FlutterSizeMake(800.0, 600.0);
547  layer.offset = FlutterPointMake(0.0, 0.0);
548 
549  ASSERT_EQ(*layers[0], layer);
550  }
551 
552  // Layer 1
553  {
554  FlutterPlatformView platform_view = *layers[1]->platform_view;
555  platform_view.struct_size = sizeof(platform_view);
556  platform_view.identifier = 1;
557 
558  FlutterLayer layer = {};
559  layer.struct_size = sizeof(layer);
561  layer.platform_view = &platform_view;
562  layer.size = FlutterSizeMake(50.0, 150.0);
563  layer.offset = FlutterPointMake(20.0, 20.0);
564 
565  ASSERT_EQ(*layers[1], layer);
566  }
567 
568  // Layer 2
569  {
570  FlutterBackingStore backing_store = *layers[2]->backing_store;
571  backing_store.type = kFlutterBackingStoreTypeOpenGL;
572  backing_store.did_update = true;
574 
575  FlutterLayer layer = {};
576  layer.struct_size = sizeof(layer);
578  layer.backing_store = &backing_store;
579  layer.size = FlutterSizeMake(800.0, 600.0);
580  layer.offset = FlutterPointMake(0.0, 0.0);
581 
582  ASSERT_EQ(*layers[2], layer);
583  }
584 
585  // Layer 3
586  {
587  FlutterPlatformView platform_view = *layers[3]->platform_view;
588  platform_view.struct_size = sizeof(platform_view);
589  platform_view.identifier = 2;
590 
591  FlutterLayer layer = {};
592  layer.struct_size = sizeof(layer);
594  layer.platform_view = &platform_view;
595  layer.size = FlutterSizeMake(50.0, 150.0);
596  layer.offset = FlutterPointMake(40.0, 40.0);
597 
598  ASSERT_EQ(*layers[3], layer);
599  }
600 
601  // Layer 4
602  {
603  FlutterBackingStore backing_store = *layers[4]->backing_store;
604  backing_store.type = kFlutterBackingStoreTypeOpenGL;
605  backing_store.did_update = true;
607 
608  FlutterLayer layer = {};
609  layer.struct_size = sizeof(layer);
611  layer.backing_store = &backing_store;
612  layer.size = FlutterSizeMake(800.0, 600.0);
613  layer.offset = FlutterPointMake(0.0, 0.0);
614 
615  ASSERT_EQ(*layers[4], layer);
616  }
617 
618  latch.CountDown();
619  });
620 
621  context.GetCompositor().SetPlatformViewRendererCallback(
622  [&](const FlutterLayer& layer,
623  GrDirectContext* context) -> sk_sp<SkImage> {
624  auto surface = CreateRenderSurface(layer, context);
625  auto canvas = surface->getCanvas();
626  FML_CHECK(canvas != nullptr);
627 
628  switch (layer.platform_view->identifier) {
629  case 1: {
630  SkPaint paint;
631  // See dart test for total order.
632  paint.setColor(SK_ColorGREEN);
633  paint.setAlpha(127);
634  const auto& rect =
635  SkRect::MakeWH(layer.size.width, layer.size.height);
636  canvas->drawRect(rect, paint);
637  latch.CountDown();
638  } break;
639  case 2: {
640  SkPaint paint;
641  // See dart test for total order.
642  paint.setColor(SK_ColorMAGENTA);
643  paint.setAlpha(127);
644  const auto& rect =
645  SkRect::MakeWH(layer.size.width, layer.size.height);
646  canvas->drawRect(rect, paint);
647  latch.CountDown();
648  } break;
649  default:
650  // Asked to render an unknown platform view.
651  FML_CHECK(false)
652  << "Test was asked to composite an unknown platform view.";
653  }
654 
655  return surface->makeImageSnapshot();
656  });
657 
658  context.AddNativeCallback(
659  "SignalNativeTest",
661  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
662 
663  auto engine = builder.LaunchEngine();
664 
665  // Send a window metrics events so frames may be scheduled.
666  FlutterWindowMetricsEvent event = {};
667  event.struct_size = sizeof(event);
668  event.width = 800;
669  event.height = 600;
670  event.pixel_ratio = 1.0;
672  kSuccess);
673  ASSERT_TRUE(engine.is_valid());
674 
675  latch.Wait();
676 
677  ASSERT_TRUE(ImageMatchesFixture("compositor.png", scene_image));
678 
679  // There should no present calls on the root surface.
680  ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
681 }
682 
683 //------------------------------------------------------------------------------
684 /// Custom compositor must play nicely with a custom task runner. The raster
685 /// thread merging mechanism must not interfere with the custom compositor.
686 ///
687 TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) {
688  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
689 
690  EmbedderConfigBuilder builder(context);
691 
692  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
693  builder.SetCompositor();
694  builder.SetDartEntrypoint("can_composite_platform_views");
695 
696  auto platform_task_runner = CreateNewThread("test_platform_thread");
697  static std::mutex engine_mutex;
699  fml::AutoResetWaitableEvent sync_latch;
700 
701  EmbedderTestTaskRunner test_task_runner(
702  platform_task_runner, [&](FlutterTask task) {
703  std::scoped_lock lock(engine_mutex);
704  if (!engine.is_valid()) {
705  return;
706  }
707  ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
708  });
709 
710  builder.SetRenderTargetType(
712 
713  fml::CountDownLatch latch(3);
714  context.GetCompositor().SetNextPresentCallback(
715  [&](const FlutterLayer** layers, size_t layers_count) {
716  ASSERT_EQ(layers_count, 3u);
717 
718  {
719  FlutterBackingStore backing_store = *layers[0]->backing_store;
720  backing_store.struct_size = sizeof(backing_store);
721  backing_store.type = kFlutterBackingStoreTypeOpenGL;
722  backing_store.did_update = true;
724 
725  FlutterLayer layer = {};
726  layer.struct_size = sizeof(layer);
728  layer.backing_store = &backing_store;
729  layer.size = FlutterSizeMake(800.0, 600.0);
730  layer.offset = FlutterPointMake(0, 0);
731 
732  ASSERT_EQ(*layers[0], layer);
733  }
734 
735  {
736  FlutterPlatformView platform_view = *layers[1]->platform_view;
737  platform_view.struct_size = sizeof(platform_view);
738  platform_view.identifier = 42;
739 
740  FlutterLayer layer = {};
741  layer.struct_size = sizeof(layer);
743  layer.platform_view = &platform_view;
744  layer.size = FlutterSizeMake(123.0, 456.0);
745  layer.offset = FlutterPointMake(1.0, 2.0);
746 
747  ASSERT_EQ(*layers[1], layer);
748  }
749 
750  {
751  FlutterBackingStore backing_store = *layers[2]->backing_store;
752  backing_store.struct_size = sizeof(backing_store);
753  backing_store.type = kFlutterBackingStoreTypeOpenGL;
754  backing_store.did_update = true;
756 
757  FlutterLayer layer = {};
758  layer.struct_size = sizeof(layer);
760  layer.backing_store = &backing_store;
761  layer.size = FlutterSizeMake(800.0, 600.0);
762  layer.offset = FlutterPointMake(0.0, 0.0);
763 
764  ASSERT_EQ(*layers[2], layer);
765  }
766 
767  latch.CountDown();
768  });
769 
770  const auto task_runner_description =
771  test_task_runner.GetFlutterTaskRunnerDescription();
772 
773  builder.SetPlatformTaskRunner(&task_runner_description);
774 
775  context.AddNativeCallback(
776  "SignalNativeTest",
778  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
779 
780  platform_task_runner->PostTask([&]() {
781  std::scoped_lock lock(engine_mutex);
782  engine = builder.LaunchEngine();
783  ASSERT_TRUE(engine.is_valid());
784 
785  // Send a window metrics events so frames may be scheduled.
786  FlutterWindowMetricsEvent event = {};
787  event.struct_size = sizeof(event);
788  event.width = 800;
789  event.height = 600;
790  event.pixel_ratio = 1.0;
791  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
792  kSuccess);
793  ASSERT_TRUE(engine.is_valid());
794  sync_latch.Signal();
795  });
796  sync_latch.Wait();
797 
798  latch.Wait();
799 
800  platform_task_runner->PostTask([&]() {
801  std::scoped_lock lock(engine_mutex);
802  engine.reset();
803  sync_latch.Signal();
804  });
805  sync_latch.Wait();
806 }
807 
808 //------------------------------------------------------------------------------
809 /// Test the layer structure and pixels rendered when using a custom compositor
810 /// and a single layer.
811 ///
812 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) {
813  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
814 
815  EmbedderConfigBuilder builder(context);
816  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
817  builder.SetCompositor();
818  builder.SetDartEntrypoint(
819  "can_composite_platform_views_with_root_layer_only");
820 
821  builder.SetRenderTargetType(
823 
824  fml::CountDownLatch latch(3);
825 
826  auto scene_image = context.GetNextSceneImage();
827 
828  context.GetCompositor().SetNextPresentCallback(
829  [&](const FlutterLayer** layers, size_t layers_count) {
830  ASSERT_EQ(layers_count, 1u);
831 
832  // Layer Root
833  {
834  FlutterBackingStore backing_store = *layers[0]->backing_store;
835  backing_store.type = kFlutterBackingStoreTypeOpenGL;
836  backing_store.did_update = true;
838 
839  FlutterLayer layer = {};
840  layer.struct_size = sizeof(layer);
842  layer.backing_store = &backing_store;
843  layer.size = FlutterSizeMake(800.0, 600.0);
844  layer.offset = FlutterPointMake(0.0, 0.0);
845 
846  ASSERT_EQ(*layers[0], layer);
847  }
848 
849  latch.CountDown();
850  });
851 
852  context.AddNativeCallback(
853  "SignalNativeTest",
855  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
856 
857  auto engine = builder.LaunchEngine();
858 
859  // Send a window metrics events so frames may be scheduled.
860  FlutterWindowMetricsEvent event = {};
861  event.struct_size = sizeof(event);
862  event.width = 800;
863  event.height = 600;
864  event.pixel_ratio = 1.0;
866  kSuccess);
867  ASSERT_TRUE(engine.is_valid());
868 
869  latch.Wait();
870 
871  ASSERT_TRUE(
872  ImageMatchesFixture("compositor_with_root_layer_only.png", scene_image));
873 }
874 
875 //------------------------------------------------------------------------------
876 /// Test the layer structure and pixels rendered when using a custom compositor
877 /// and ensure that a redundant layer is not added.
878 ///
879 TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) {
880  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
881 
882  EmbedderConfigBuilder builder(context);
883  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
884  builder.SetCompositor();
885  builder.SetDartEntrypoint(
886  "can_composite_platform_views_with_platform_layer_on_bottom");
887 
888  builder.SetRenderTargetType(
890 
891  fml::CountDownLatch latch(3);
892 
893  auto scene_image = context.GetNextSceneImage();
894 
895  context.GetCompositor().SetNextPresentCallback(
896  [&](const FlutterLayer** layers, size_t layers_count) {
897  ASSERT_EQ(layers_count, 2u);
898 
899  // Layer Root
900  {
901  FlutterBackingStore backing_store = *layers[0]->backing_store;
902  backing_store.type = kFlutterBackingStoreTypeOpenGL;
903  backing_store.did_update = true;
905 
906  FlutterLayer layer = {};
907  layer.struct_size = sizeof(layer);
909  layer.backing_store = &backing_store;
910  layer.size = FlutterSizeMake(800.0, 600.0);
911  layer.offset = FlutterPointMake(0.0, 0.0);
912 
913  ASSERT_EQ(*layers[0], layer);
914  }
915 
916  // Layer 1
917  {
918  FlutterPlatformView platform_view = *layers[1]->platform_view;
919  platform_view.struct_size = sizeof(platform_view);
920  platform_view.identifier = 1;
921 
922  FlutterLayer layer = {};
923  layer.struct_size = sizeof(layer);
925  layer.platform_view = &platform_view;
926  layer.size = FlutterSizeMake(50.0, 150.0);
927  layer.offset = FlutterPointMake(20.0, 20.0);
928 
929  ASSERT_EQ(*layers[1], layer);
930  }
931 
932  latch.CountDown();
933  });
934 
935  context.GetCompositor().SetPlatformViewRendererCallback(
936  [&](const FlutterLayer& layer,
937  GrDirectContext* context) -> sk_sp<SkImage> {
938  auto surface = CreateRenderSurface(layer, context);
939  auto canvas = surface->getCanvas();
940  FML_CHECK(canvas != nullptr);
941 
942  switch (layer.platform_view->identifier) {
943  case 1: {
944  SkPaint paint;
945  // See dart test for total order.
946  paint.setColor(SK_ColorGREEN);
947  paint.setAlpha(127);
948  const auto& rect =
949  SkRect::MakeWH(layer.size.width, layer.size.height);
950  canvas->drawRect(rect, paint);
951  latch.CountDown();
952  } break;
953  default:
954  // Asked to render an unknown platform view.
955  FML_CHECK(false)
956  << "Test was asked to composite an unknown platform view.";
957  }
958 
959  return surface->makeImageSnapshot();
960  });
961 
962  context.AddNativeCallback(
963  "SignalNativeTest",
965  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
966 
967  auto engine = builder.LaunchEngine();
968 
969  // Send a window metrics events so frames may be scheduled.
970  FlutterWindowMetricsEvent event = {};
971  event.struct_size = sizeof(event);
972  event.width = 800;
973  event.height = 600;
974  event.pixel_ratio = 1.0;
976  kSuccess);
977  ASSERT_TRUE(engine.is_valid());
978 
979  latch.Wait();
980 
981  ASSERT_TRUE(ImageMatchesFixture(
982  "compositor_with_platform_layer_on_bottom.png", scene_image));
983 
984  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 1u);
985 }
986 
987 //------------------------------------------------------------------------------
988 /// Test the layer structure and pixels rendered when using a custom compositor
989 /// with a root surface transformation.
990 ///
992  CompositorMustBeAbleToRenderKnownSceneWithRootSurfaceTransformation) {
993  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
994 
995  EmbedderConfigBuilder builder(context);
996  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
997  builder.SetCompositor();
998  builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
999 
1000  builder.SetRenderTargetType(
1002 
1003  // This must match the transformation provided in the
1004  // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1005  // transforms are consistent respected.
1006  const auto root_surface_transformation =
1007  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1008 
1009  context.SetRootSurfaceTransformation(root_surface_transformation);
1010 
1011  fml::CountDownLatch latch(5);
1012 
1013  auto scene_image = context.GetNextSceneImage();
1014 
1015  context.GetCompositor().SetNextPresentCallback(
1016  [&](const FlutterLayer** layers, size_t layers_count) {
1017  ASSERT_EQ(layers_count, 5u);
1018 
1019  // Layer Root
1020  {
1021  FlutterBackingStore backing_store = *layers[0]->backing_store;
1022  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1023  backing_store.did_update = true;
1025 
1026  FlutterLayer layer = {};
1027  layer.struct_size = sizeof(layer);
1029  layer.backing_store = &backing_store;
1030  layer.size = FlutterSizeMake(600.0, 800.0);
1031  layer.offset = FlutterPointMake(0.0, 0.0);
1032 
1033  ASSERT_EQ(*layers[0], layer);
1034  }
1035 
1036  // Layer 1
1037  {
1038  FlutterPlatformView platform_view = *layers[1]->platform_view;
1039  platform_view.struct_size = sizeof(platform_view);
1040  platform_view.identifier = 1;
1041 
1042  FlutterLayer layer = {};
1043  layer.struct_size = sizeof(layer);
1045  layer.platform_view = &platform_view;
1046  layer.size = FlutterSizeMake(150.0, 50.0);
1047  layer.offset = FlutterPointMake(20.0, 730.0);
1048 
1049  ASSERT_EQ(*layers[1], layer);
1050  }
1051 
1052  // Layer 2
1053  {
1054  FlutterBackingStore backing_store = *layers[2]->backing_store;
1055  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1056  backing_store.did_update = true;
1058 
1059  FlutterLayer layer = {};
1060  layer.struct_size = sizeof(layer);
1062  layer.backing_store = &backing_store;
1063  layer.size = FlutterSizeMake(600.0, 800.0);
1064  layer.offset = FlutterPointMake(0.0, 0.0);
1065 
1066  ASSERT_EQ(*layers[2], layer);
1067  }
1068 
1069  // Layer 3
1070  {
1071  FlutterPlatformView platform_view = *layers[3]->platform_view;
1072  platform_view.struct_size = sizeof(platform_view);
1073  platform_view.identifier = 2;
1074 
1075  FlutterLayer layer = {};
1076  layer.struct_size = sizeof(layer);
1078  layer.platform_view = &platform_view;
1079  layer.size = FlutterSizeMake(150.0, 50.0);
1080  layer.offset = FlutterPointMake(40.0, 710.0);
1081 
1082  ASSERT_EQ(*layers[3], layer);
1083  }
1084 
1085  // Layer 4
1086  {
1087  FlutterBackingStore backing_store = *layers[4]->backing_store;
1088  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1089  backing_store.did_update = true;
1091 
1092  FlutterLayer layer = {};
1093  layer.struct_size = sizeof(layer);
1095  layer.backing_store = &backing_store;
1096  layer.size = FlutterSizeMake(600.0, 800.0);
1097  layer.offset = FlutterPointMake(0.0, 0.0);
1098 
1099  ASSERT_EQ(*layers[4], layer);
1100  }
1101 
1102  latch.CountDown();
1103  });
1104 
1105  context.GetCompositor().SetPlatformViewRendererCallback(
1106  [&](const FlutterLayer& layer,
1107  GrDirectContext* context) -> sk_sp<SkImage> {
1108  auto surface = CreateRenderSurface(layer, context);
1109  auto canvas = surface->getCanvas();
1110  FML_CHECK(canvas != nullptr);
1111 
1112  switch (layer.platform_view->identifier) {
1113  case 1: {
1114  SkPaint paint;
1115  // See dart test for total order.
1116  paint.setColor(SK_ColorGREEN);
1117  paint.setAlpha(127);
1118  const auto& rect =
1119  SkRect::MakeWH(layer.size.width, layer.size.height);
1120  canvas->drawRect(rect, paint);
1121  latch.CountDown();
1122  } break;
1123  case 2: {
1124  SkPaint paint;
1125  // See dart test for total order.
1126  paint.setColor(SK_ColorMAGENTA);
1127  paint.setAlpha(127);
1128  const auto& rect =
1129  SkRect::MakeWH(layer.size.width, layer.size.height);
1130  canvas->drawRect(rect, paint);
1131  latch.CountDown();
1132  } break;
1133  default:
1134  // Asked to render an unknown platform view.
1135  FML_CHECK(false)
1136  << "Test was asked to composite an unknown platform view.";
1137  }
1138 
1139  return surface->makeImageSnapshot();
1140  });
1141 
1142  context.AddNativeCallback(
1143  "SignalNativeTest",
1145  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
1146 
1147  auto engine = builder.LaunchEngine();
1148 
1149  // Send a window metrics events so frames may be scheduled.
1150  FlutterWindowMetricsEvent event = {};
1151  event.struct_size = sizeof(event);
1152  // Flutter still thinks it is 800 x 600. Only the root surface is rotated.
1153  event.width = 800;
1154  event.height = 600;
1155  event.pixel_ratio = 1.0;
1157  kSuccess);
1158  ASSERT_TRUE(engine.is_valid());
1159 
1160  latch.Wait();
1161 
1162  ASSERT_TRUE(ImageMatchesFixture("compositor_root_surface_xformation.png",
1163  scene_image));
1164 }
1165 
1166 TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositor) {
1167  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1168 
1169  EmbedderConfigBuilder builder(context);
1170 
1171  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1172  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1173 
1174  auto renderered_scene = context.GetNextSceneImage();
1175 
1176  auto engine = builder.LaunchEngine();
1177  ASSERT_TRUE(engine.is_valid());
1178 
1179  // Send a window metrics events so frames may be scheduled.
1180  FlutterWindowMetricsEvent event = {};
1181  event.struct_size = sizeof(event);
1182  event.width = 800;
1183  event.height = 600;
1184  event.pixel_ratio = 1.0;
1186  kSuccess);
1187 
1188  ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png",
1189  renderered_scene));
1190 }
1191 
1192 TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositorWithTransformation) {
1193  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1194 
1195  const auto root_surface_transformation =
1196  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1197 
1198  context.SetRootSurfaceTransformation(root_surface_transformation);
1199 
1200  EmbedderConfigBuilder builder(context);
1201 
1202  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1203  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1204 
1205  auto renderered_scene = context.GetNextSceneImage();
1206 
1207  auto engine = builder.LaunchEngine();
1208  ASSERT_TRUE(engine.is_valid());
1209 
1210  // Send a window metrics events so frames may be scheduled.
1211  FlutterWindowMetricsEvent event = {};
1212  event.struct_size = sizeof(event);
1213 
1214  // Flutter still thinks it is 800 x 600.
1215  event.width = 800;
1216  event.height = 600;
1217  event.pixel_ratio = 1.0;
1219  kSuccess);
1220 
1221  ASSERT_TRUE(ImageMatchesFixture(
1222  "scene_without_custom_compositor_with_xform.png", renderered_scene));
1223 }
1224 
1225 TEST_F(EmbedderTest, CanRenderGradientWithoutCompositor) {
1226  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1227 
1228  EmbedderConfigBuilder builder(context);
1229 
1230  builder.SetDartEntrypoint("render_gradient");
1231  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1232 
1233  auto renderered_scene = context.GetNextSceneImage();
1234 
1235  auto engine = builder.LaunchEngine();
1236  ASSERT_TRUE(engine.is_valid());
1237 
1238  // Send a window metrics events so frames may be scheduled.
1239  FlutterWindowMetricsEvent event = {};
1240  event.struct_size = sizeof(event);
1241  event.width = 800;
1242  event.height = 600;
1243  event.pixel_ratio = 1.0;
1245  kSuccess);
1246 
1247  ASSERT_TRUE(ImageMatchesFixture("gradient.png", renderered_scene));
1248 }
1249 
1250 TEST_F(EmbedderTest, CanRenderGradientWithoutCompositorWithXform) {
1251  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1252 
1253  const auto root_surface_transformation =
1254  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1255 
1256  context.SetRootSurfaceTransformation(root_surface_transformation);
1257 
1258  EmbedderConfigBuilder builder(context);
1259 
1260  const auto surface_size = SkISize::Make(600, 800);
1261 
1262  builder.SetDartEntrypoint("render_gradient");
1263  builder.SetOpenGLRendererConfig(surface_size);
1264 
1265  auto renderered_scene = context.GetNextSceneImage();
1266 
1267  auto engine = builder.LaunchEngine();
1268  ASSERT_TRUE(engine.is_valid());
1269 
1270  // Send a window metrics events so frames may be scheduled.
1271  FlutterWindowMetricsEvent event = {};
1272  event.struct_size = sizeof(event);
1273  // Flutter still thinks it is 800 x 600.
1274  event.width = 800;
1275  event.height = 600;
1276  event.pixel_ratio = 1.0;
1278  kSuccess);
1279 
1280  ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", renderered_scene));
1281 }
1282 
1283 TEST_F(EmbedderTest, CanRenderGradientWithCompositor) {
1284  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1285 
1286  EmbedderConfigBuilder builder(context);
1287 
1288  builder.SetDartEntrypoint("render_gradient");
1289  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1290  builder.SetCompositor();
1291  builder.SetRenderTargetType(
1293 
1294  auto renderered_scene = context.GetNextSceneImage();
1295 
1296  auto engine = builder.LaunchEngine();
1297  ASSERT_TRUE(engine.is_valid());
1298 
1299  // Send a window metrics events so frames may be scheduled.
1300  FlutterWindowMetricsEvent event = {};
1301  event.struct_size = sizeof(event);
1302  event.width = 800;
1303  event.height = 600;
1304  event.pixel_ratio = 1.0;
1306  kSuccess);
1307 
1308  ASSERT_TRUE(ImageMatchesFixture("gradient.png", renderered_scene));
1309 }
1310 
1311 TEST_F(EmbedderTest, CanRenderGradientWithCompositorWithXform) {
1312  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1313 
1314  // This must match the transformation provided in the
1315  // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1316  // transforms are consistent respected.
1317  const auto root_surface_transformation =
1318  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1319 
1320  context.SetRootSurfaceTransformation(root_surface_transformation);
1321 
1322  EmbedderConfigBuilder builder(context);
1323 
1324  builder.SetDartEntrypoint("render_gradient");
1325  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1326  builder.SetCompositor();
1327  builder.SetRenderTargetType(
1329 
1330  auto renderered_scene = context.GetNextSceneImage();
1331 
1332  auto engine = builder.LaunchEngine();
1333  ASSERT_TRUE(engine.is_valid());
1334 
1335  // Send a window metrics events so frames may be scheduled.
1336  FlutterWindowMetricsEvent event = {};
1337  event.struct_size = sizeof(event);
1338  // Flutter still thinks it is 800 x 600.
1339  event.width = 800;
1340  event.height = 600;
1341  event.pixel_ratio = 1.0;
1343  kSuccess);
1344 
1345  ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", renderered_scene));
1346 }
1347 
1348 TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayer) {
1349  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1350 
1351  EmbedderConfigBuilder builder(context);
1352 
1353  builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1354  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1355  builder.SetCompositor();
1356  builder.SetRenderTargetType(
1358 
1359  context.GetCompositor().SetNextPresentCallback(
1360  [&](const FlutterLayer** layers, size_t layers_count) {
1361  ASSERT_EQ(layers_count, 3u);
1362 
1363  // Layer Root
1364  {
1365  FlutterBackingStore backing_store = *layers[0]->backing_store;
1366  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1367  backing_store.did_update = true;
1369 
1370  FlutterLayer layer = {};
1371  layer.struct_size = sizeof(layer);
1373  layer.backing_store = &backing_store;
1374  layer.size = FlutterSizeMake(800.0, 600.0);
1375  layer.offset = FlutterPointMake(0.0, 0.0);
1376 
1377  ASSERT_EQ(*layers[0], layer);
1378  }
1379 
1380  // Layer 1
1381  {
1382  FlutterPlatformView platform_view = *layers[1]->platform_view;
1383  platform_view.struct_size = sizeof(platform_view);
1384  platform_view.identifier = 1;
1385 
1386  FlutterLayer layer = {};
1387  layer.struct_size = sizeof(layer);
1389  layer.platform_view = &platform_view;
1390  layer.size = FlutterSizeMake(100.0, 200.0);
1391  layer.offset = FlutterPointMake(0.0, 0.0);
1392 
1393  ASSERT_EQ(*layers[1], layer);
1394  }
1395 
1396  // Layer 2
1397  {
1398  FlutterBackingStore backing_store = *layers[2]->backing_store;
1399  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1400  backing_store.did_update = true;
1402 
1403  FlutterLayer layer = {};
1404  layer.struct_size = sizeof(layer);
1406  layer.backing_store = &backing_store;
1407  layer.size = FlutterSizeMake(800.0, 600.0);
1408  layer.offset = FlutterPointMake(0.0, 0.0);
1409 
1410  ASSERT_EQ(*layers[2], layer);
1411  }
1412  });
1413 
1414  context.GetCompositor().SetPlatformViewRendererCallback(
1415  [&](const FlutterLayer& layer,
1416  GrDirectContext* context) -> sk_sp<SkImage> {
1417  auto surface = CreateRenderSurface(layer, context);
1418  auto canvas = surface->getCanvas();
1419  FML_CHECK(canvas != nullptr);
1420 
1421  switch (layer.platform_view->identifier) {
1422  case 1: {
1423  FML_CHECK(layer.size.width == 100);
1424  FML_CHECK(layer.size.height == 200);
1425  // This is occluded anyway. We just want to make sure we see this.
1426  } break;
1427  default:
1428  // Asked to render an unknown platform view.
1429  FML_CHECK(false)
1430  << "Test was asked to composite an unknown platform view.";
1431  }
1432 
1433  return surface->makeImageSnapshot();
1434  });
1435 
1436  auto renderered_scene = context.GetNextSceneImage();
1437 
1438  auto engine = builder.LaunchEngine();
1439  ASSERT_TRUE(engine.is_valid());
1440 
1441  // Send a window metrics events so frames may be scheduled.
1442  FlutterWindowMetricsEvent event = {};
1443  event.struct_size = sizeof(event);
1444  event.width = 800;
1445  event.height = 600;
1446  event.pixel_ratio = 1.0;
1448  kSuccess);
1449 
1450  ASSERT_TRUE(ImageMatchesFixture("gradient.png", renderered_scene));
1451 }
1452 
1453 TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) {
1454  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1455 
1456  // This must match the transformation provided in the
1457  // |CanRenderGradientWithoutCompositorWithXform| test to ensure that
1458  // transforms are consistent respected.
1459  const auto root_surface_transformation =
1460  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1461 
1462  context.SetRootSurfaceTransformation(root_surface_transformation);
1463 
1464  EmbedderConfigBuilder builder(context);
1465 
1466  builder.SetDartEntrypoint("render_gradient_on_non_root_backing_store");
1467  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1468  builder.SetCompositor();
1469  builder.SetRenderTargetType(
1471 
1472  context.GetCompositor().SetNextPresentCallback(
1473  [&](const FlutterLayer** layers, size_t layers_count) {
1474  ASSERT_EQ(layers_count, 3u);
1475 
1476  // Layer Root
1477  {
1478  FlutterBackingStore backing_store = *layers[0]->backing_store;
1479  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1480  backing_store.did_update = true;
1482 
1483  FlutterLayer layer = {};
1484  layer.struct_size = sizeof(layer);
1486  layer.backing_store = &backing_store;
1487  layer.size = FlutterSizeMake(600.0, 800.0);
1488  layer.offset = FlutterPointMake(0.0, 0.0);
1489 
1490  ASSERT_EQ(*layers[0], layer);
1491  }
1492 
1493  // Layer 1
1494  {
1495  FlutterPlatformView platform_view = *layers[1]->platform_view;
1496  platform_view.struct_size = sizeof(platform_view);
1497  platform_view.identifier = 1;
1498 
1499  FlutterLayer layer = {};
1500  layer.struct_size = sizeof(layer);
1502  layer.platform_view = &platform_view;
1503  layer.size = FlutterSizeMake(200.0, 100.0);
1504  layer.offset = FlutterPointMake(0.0, 700.0);
1505 
1506  ASSERT_EQ(*layers[1], layer);
1507  }
1508 
1509  // Layer 2
1510  {
1511  FlutterBackingStore backing_store = *layers[2]->backing_store;
1512  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1513  backing_store.did_update = true;
1515 
1516  FlutterLayer layer = {};
1517  layer.struct_size = sizeof(layer);
1519  layer.backing_store = &backing_store;
1520  layer.size = FlutterSizeMake(600.0, 800.0);
1521  layer.offset = FlutterPointMake(0.0, 0.0);
1522 
1523  ASSERT_EQ(*layers[2], layer);
1524  }
1525  });
1526 
1527  context.GetCompositor().SetPlatformViewRendererCallback(
1528  [&](const FlutterLayer& layer,
1529  GrDirectContext* context) -> sk_sp<SkImage> {
1530  auto surface = CreateRenderSurface(layer, context);
1531  auto canvas = surface->getCanvas();
1532  FML_CHECK(canvas != nullptr);
1533 
1534  switch (layer.platform_view->identifier) {
1535  case 1: {
1536  FML_CHECK(layer.size.width == 200);
1537  FML_CHECK(layer.size.height == 100);
1538  // This is occluded anyway. We just want to make sure we see this.
1539  } break;
1540  default:
1541  // Asked to render an unknown platform view.
1542  FML_CHECK(false)
1543  << "Test was asked to composite an unknown platform view.";
1544  }
1545 
1546  return surface->makeImageSnapshot();
1547  });
1548 
1549  auto renderered_scene = context.GetNextSceneImage();
1550 
1551  auto engine = builder.LaunchEngine();
1552  ASSERT_TRUE(engine.is_valid());
1553 
1554  // Send a window metrics events so frames may be scheduled.
1555  FlutterWindowMetricsEvent event = {};
1556  event.struct_size = sizeof(event);
1557  // Flutter still thinks it is 800 x 600.
1558  event.width = 800;
1559  event.height = 600;
1560  event.pixel_ratio = 1.0;
1562  kSuccess);
1563 
1564  ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", renderered_scene));
1565 }
1566 
1567 TEST_F(EmbedderTest, VerifyB141980393) {
1568  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1569 
1570  EmbedderConfigBuilder builder(context);
1571 
1572  // The Flutter application is 800 x 600 but rendering on a surface that is 600
1573  // x 800 achieved using a root surface transformation.
1574  const auto root_surface_transformation =
1575  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1576  const auto flutter_application_rect = SkRect::MakeWH(800, 600);
1577  const auto root_surface_rect =
1578  root_surface_transformation.mapRect(flutter_application_rect);
1579 
1580  ASSERT_DOUBLE_EQ(root_surface_rect.width(), 600.0);
1581  ASSERT_DOUBLE_EQ(root_surface_rect.height(), 800.0);
1582 
1583  // Configure the fixture for the surface transformation.
1584  context.SetRootSurfaceTransformation(root_surface_transformation);
1585 
1586  // Configure the Flutter project args for the root surface transformation.
1587  builder.SetOpenGLRendererConfig(
1588  SkISize::Make(root_surface_rect.width(), root_surface_rect.height()));
1589 
1590  // Use a compositor instead of rendering directly to the surface.
1591  builder.SetCompositor();
1592  builder.SetRenderTargetType(
1594 
1595  builder.SetDartEntrypoint("verify_b141980393");
1596 
1598 
1599  context.GetCompositor().SetNextPresentCallback(
1600  [&](const FlutterLayer** layers, size_t layers_count) {
1601  ASSERT_EQ(layers_count, 1u);
1602 
1603  // Layer Root
1604  {
1605  FlutterPlatformView platform_view = *layers[0]->platform_view;
1606  platform_view.struct_size = sizeof(platform_view);
1607  platform_view.identifier = 1337;
1608 
1609  FlutterLayer layer = {};
1610  layer.struct_size = sizeof(layer);
1612  layer.platform_view = &platform_view;
1613 
1614  // From the Dart side. These dimensions match those specified in Dart
1615  // code and are free of root surface transformations.
1616  const double unxformed_top_margin = 31.0;
1617  const double unxformed_bottom_margin = 37.0;
1618  const auto unxformed_platform_view_rect = SkRect::MakeXYWH(
1619  0.0, // x
1620  unxformed_top_margin, // y (top margin)
1621  800, // width
1622  600 - unxformed_top_margin - unxformed_bottom_margin // height
1623  );
1624 
1625  // The platform views are in the coordinate space of the root surface
1626  // with top-left origin. The embedder has specified a transformation
1627  // to this surface which it must account for in the coordinates it
1628  // receives here.
1629  const auto xformed_platform_view_rect =
1630  root_surface_transformation.mapRect(unxformed_platform_view_rect);
1631 
1632  // Spell out the value that we are going to be checking below for
1633  // clarity.
1634  ASSERT_EQ(xformed_platform_view_rect,
1635  SkRect::MakeXYWH(31.0, // x
1636  0.0, // y
1637  532.0, // width
1638  800.0 // height
1639  ));
1640 
1641  // Verify that the engine is giving us the right size and offset.
1642  layer.offset = FlutterPointMake(xformed_platform_view_rect.x(),
1643  xformed_platform_view_rect.y());
1644  layer.size = FlutterSizeMake(xformed_platform_view_rect.width(),
1645  xformed_platform_view_rect.height());
1646 
1647  ASSERT_EQ(*layers[0], layer);
1648  }
1649 
1650  latch.Signal();
1651  });
1652 
1653  auto engine = builder.LaunchEngine();
1654 
1655  // Send a window metrics events so frames may be scheduled.
1656  FlutterWindowMetricsEvent event = {};
1657  event.struct_size = sizeof(event);
1658 
1659  // The Flutter application is 800 x 600 rendering on a surface 600 x 800
1660  // achieved via a root surface transformation.
1661  event.width = flutter_application_rect.width();
1662  event.height = flutter_application_rect.height();
1663  event.pixel_ratio = 1.0;
1665  kSuccess);
1666  ASSERT_TRUE(engine.is_valid());
1667 
1668  latch.Wait();
1669 }
1670 
1671 //------------------------------------------------------------------------------
1672 /// Asserts that embedders can provide a task runner for the render thread.
1673 ///
1674 TEST_F(EmbedderTest, CanCreateEmbedderWithCustomRenderTaskRunner) {
1675  std::mutex engine_mutex;
1677  fml::AutoResetWaitableEvent task_latch;
1678  bool task_executed = false;
1679  EmbedderTestTaskRunner render_task_runner(
1680  CreateNewThread("custom_render_thread"), [&](FlutterTask task) {
1681  std::scoped_lock engine_lock(engine_mutex);
1682  if (engine.is_valid()) {
1683  ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
1684  task_executed = true;
1685  task_latch.Signal();
1686  }
1687  });
1688  EmbedderConfigBuilder builder(
1689  GetEmbedderContext(ContextType::kOpenGLContext));
1690  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1691  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1692  builder.SetRenderTaskRunner(
1693  &render_task_runner.GetFlutterTaskRunnerDescription());
1694 
1695  {
1696  std::scoped_lock lock(engine_mutex);
1697  engine = builder.InitializeEngine();
1698  }
1699 
1700  ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
1701 
1702  ASSERT_TRUE(engine.is_valid());
1703 
1704  FlutterWindowMetricsEvent event = {};
1705  event.struct_size = sizeof(event);
1706  event.width = 800;
1707  event.height = 600;
1708  event.pixel_ratio = 1.0;
1709  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1710  kSuccess);
1711  task_latch.Wait();
1712  ASSERT_TRUE(task_executed);
1713  ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
1714 
1715  {
1716  std::scoped_lock engine_lock(engine_mutex);
1717  engine.reset();
1718  }
1719 }
1720 
1721 //------------------------------------------------------------------------------
1722 /// Asserts that the render task runner can be the same as the platform task
1723 /// runner.
1724 ///
1726  CanCreateEmbedderWithCustomRenderTaskRunnerTheSameAsPlatformTaskRunner) {
1727  // A new thread needs to be created for the platform thread because the test
1728  // can't wait for assertions to be completed on the same thread that services
1729  // platform task runner tasks.
1730  auto platform_task_runner = CreateNewThread("platform_thread");
1731 
1732  static std::mutex engine_mutex;
1733  static UniqueEngine engine;
1734  fml::AutoResetWaitableEvent task_latch;
1735  bool task_executed = false;
1736  EmbedderTestTaskRunner common_task_runner(
1737  platform_task_runner, [&](FlutterTask task) {
1738  std::scoped_lock engine_lock(engine_mutex);
1739  if (engine.is_valid()) {
1740  ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
1741  task_executed = true;
1742  task_latch.Signal();
1743  }
1744  });
1745 
1746  platform_task_runner->PostTask([&]() {
1747  EmbedderConfigBuilder builder(
1748  GetEmbedderContext(ContextType::kOpenGLContext));
1749  builder.SetDartEntrypoint("can_render_scene_without_custom_compositor");
1750  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1751  builder.SetRenderTaskRunner(
1752  &common_task_runner.GetFlutterTaskRunnerDescription());
1753  builder.SetPlatformTaskRunner(
1754  &common_task_runner.GetFlutterTaskRunnerDescription());
1755 
1756  {
1757  std::scoped_lock lock(engine_mutex);
1758  engine = builder.InitializeEngine();
1759  }
1760 
1761  ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
1762 
1763  ASSERT_TRUE(engine.is_valid());
1764 
1765  FlutterWindowMetricsEvent event = {};
1766  event.struct_size = sizeof(event);
1767  event.width = 800;
1768  event.height = 600;
1769  event.pixel_ratio = 1.0;
1770  ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
1771  kSuccess);
1772  });
1773 
1774  task_latch.Wait();
1775 
1776  // Don't use the task latch because that may be called multiple time
1777  // (including during the shutdown process).
1778  fml::AutoResetWaitableEvent shutdown_latch;
1779 
1780  platform_task_runner->PostTask([&]() {
1781  ASSERT_TRUE(task_executed);
1782  ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
1783 
1784  {
1785  std::scoped_lock engine_lock(engine_mutex);
1786  engine.reset();
1787  }
1788  shutdown_latch.Signal();
1789  });
1790 
1791  shutdown_latch.Wait();
1792 
1793  {
1794  std::scoped_lock engine_lock(engine_mutex);
1795  // Engine should have been killed by this point.
1796  ASSERT_FALSE(engine.is_valid());
1797  }
1798 }
1799 
1801  CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurface) {
1802  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1803 
1804  EmbedderConfigBuilder builder(context);
1805  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
1806  builder.SetCompositor();
1807  builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
1808 
1809  builder.SetRenderTargetType(
1811 
1812  fml::CountDownLatch latch(1);
1813 
1814  auto renderered_scene = context.GetNextSceneImage();
1815 
1816  context.GetCompositor().SetNextPresentCallback(
1817  [&](const FlutterLayer** layers, size_t layers_count) {
1818  ASSERT_EQ(layers_count, 3u);
1819 
1820  // Layer 0 (Root)
1821  {
1822  FlutterBackingStore backing_store = *layers[0]->backing_store;
1823  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1824  backing_store.did_update = true;
1826 
1827  FlutterLayer layer = {};
1828  layer.struct_size = sizeof(layer);
1830  layer.backing_store = &backing_store;
1831  layer.size = FlutterSizeMake(800.0, 600.0);
1832  layer.offset = FlutterPointMake(0.0, 0.0);
1833 
1834  ASSERT_EQ(*layers[0], layer);
1835  }
1836 
1837  // Layer 1
1838  {
1839  FlutterPlatformView platform_view = *layers[1]->platform_view;
1840  platform_view.struct_size = sizeof(platform_view);
1841  platform_view.identifier = 42;
1842 
1843  FlutterLayer layer = {};
1844  layer.struct_size = sizeof(layer);
1846  layer.platform_view = &platform_view;
1847  layer.size = FlutterSizeMake(800.0, 560.0);
1848  layer.offset = FlutterPointMake(0.0, 40.0);
1849 
1850  ASSERT_EQ(*layers[1], layer);
1851  }
1852 
1853  // Layer 2
1854  {
1855  FlutterBackingStore backing_store = *layers[2]->backing_store;
1856  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1857  backing_store.did_update = true;
1859 
1860  FlutterLayer layer = {};
1861  layer.struct_size = sizeof(layer);
1863  layer.backing_store = &backing_store;
1864  layer.size = FlutterSizeMake(800.0, 600.0);
1865  layer.offset = FlutterPointMake(0.0, 0.0);
1866 
1867  ASSERT_EQ(*layers[2], layer);
1868  }
1869 
1870  latch.CountDown();
1871  });
1872 
1873  auto engine = builder.LaunchEngine();
1874 
1875  // Send a window metrics events so frames may be scheduled.
1876  FlutterWindowMetricsEvent event = {};
1877  event.struct_size = sizeof(event);
1878  event.width = 400 * 2.0;
1879  event.height = 300 * 2.0;
1880  event.pixel_ratio = 2.0;
1882  kSuccess);
1883  ASSERT_TRUE(engine.is_valid());
1884 
1885  latch.Wait();
1886 
1887  ASSERT_TRUE(ImageMatchesFixture("dpr_noxform.png", renderered_scene));
1888 }
1889 
1891  EmbedderTest,
1892  CompositorMustBeAbleToRenderKnownScenePixelRatioOnSurfaceWithRootSurfaceXformation) {
1893  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1894 
1895  EmbedderConfigBuilder builder(context);
1896  builder.SetOpenGLRendererConfig(SkISize::Make(600, 800));
1897  builder.SetCompositor();
1898  builder.SetDartEntrypoint("can_display_platform_view_with_pixel_ratio");
1899 
1900  builder.SetRenderTargetType(
1902 
1903  const auto root_surface_transformation =
1904  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
1905 
1906  context.SetRootSurfaceTransformation(root_surface_transformation);
1907 
1908  auto renderered_scene = context.GetNextSceneImage();
1909  fml::CountDownLatch latch(1);
1910 
1911  context.GetCompositor().SetNextPresentCallback(
1912  [&](const FlutterLayer** layers, size_t layers_count) {
1913  ASSERT_EQ(layers_count, 3u);
1914 
1915  // Layer 0 (Root)
1916  {
1917  FlutterBackingStore backing_store = *layers[0]->backing_store;
1918  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1919  backing_store.did_update = true;
1921 
1922  FlutterLayer layer = {};
1923  layer.struct_size = sizeof(layer);
1925  layer.backing_store = &backing_store;
1926  layer.size = FlutterSizeMake(600.0, 800.0);
1927  layer.offset = FlutterPointMake(0.0, 0.0);
1928 
1929  ASSERT_EQ(*layers[0], layer);
1930  }
1931 
1932  // Layer 1
1933  {
1934  FlutterPlatformView platform_view = *layers[1]->platform_view;
1935  platform_view.struct_size = sizeof(platform_view);
1936  platform_view.identifier = 42;
1937 
1938  FlutterLayer layer = {};
1939  layer.struct_size = sizeof(layer);
1941  layer.platform_view = &platform_view;
1942  layer.size = FlutterSizeMake(560.0, 800.0);
1943  layer.offset = FlutterPointMake(40.0, 0.0);
1944 
1945  ASSERT_EQ(*layers[1], layer);
1946  }
1947 
1948  // Layer 2
1949  {
1950  FlutterBackingStore backing_store = *layers[2]->backing_store;
1951  backing_store.type = kFlutterBackingStoreTypeOpenGL;
1952  backing_store.did_update = true;
1954 
1955  FlutterLayer layer = {};
1956  layer.struct_size = sizeof(layer);
1958  layer.backing_store = &backing_store;
1959  layer.size = FlutterSizeMake(600.0, 800.0);
1960  layer.offset = FlutterPointMake(0.0, 0.0);
1961 
1962  ASSERT_EQ(*layers[2], layer);
1963  }
1964 
1965  latch.CountDown();
1966  });
1967 
1968  auto engine = builder.LaunchEngine();
1969 
1970  // Send a window metrics events so frames may be scheduled.
1971  FlutterWindowMetricsEvent event = {};
1972  event.struct_size = sizeof(event);
1973  event.width = 400 * 2.0;
1974  event.height = 300 * 2.0;
1975  event.pixel_ratio = 2.0;
1977  kSuccess);
1978  ASSERT_TRUE(engine.is_valid());
1979 
1980  latch.Wait();
1981 
1982  ASSERT_TRUE(ImageMatchesFixture("dpr_xform.png", renderered_scene));
1983 }
1984 
1986  PushingMutlipleFramesSetsUpNewRecordingCanvasWithCustomCompositor) {
1987  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
1988 
1989  EmbedderConfigBuilder builder(context);
1990  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
1991  builder.SetCompositor();
1992  builder.SetDartEntrypoint("push_frames_over_and_over");
1993 
1994  builder.SetRenderTargetType(
1996 
1997  const auto root_surface_transformation =
1998  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
1999 
2000  context.SetRootSurfaceTransformation(root_surface_transformation);
2001 
2002  auto engine = builder.LaunchEngine();
2003 
2004  // Send a window metrics events so frames may be scheduled.
2005  FlutterWindowMetricsEvent event = {};
2006  event.struct_size = sizeof(event);
2007  event.width = 1024;
2008  event.height = 600;
2009  event.pixel_ratio = 1.0;
2011  kSuccess);
2012  ASSERT_TRUE(engine.is_valid());
2013 
2014  constexpr size_t frames_expected = 10;
2015  fml::CountDownLatch frame_latch(frames_expected);
2016  size_t frames_seen = 0;
2017  context.AddNativeCallback("SignalNativeTest",
2018  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2019  frames_seen++;
2020  frame_latch.CountDown();
2021  }));
2022  frame_latch.Wait();
2023 
2024  ASSERT_EQ(frames_expected, frames_seen);
2025 }
2026 
2028  PushingMutlipleFramesSetsUpNewRecordingCanvasWithoutCustomCompositor) {
2029  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2030 
2031  EmbedderConfigBuilder builder(context);
2032  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
2033  builder.SetDartEntrypoint("push_frames_over_and_over");
2034 
2035  const auto root_surface_transformation =
2036  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
2037 
2038  context.SetRootSurfaceTransformation(root_surface_transformation);
2039 
2040  auto engine = builder.LaunchEngine();
2041 
2042  // Send a window metrics events so frames may be scheduled.
2043  FlutterWindowMetricsEvent event = {};
2044  event.struct_size = sizeof(event);
2045  event.width = 1024;
2046  event.height = 600;
2047  event.pixel_ratio = 1.0;
2049  kSuccess);
2050  ASSERT_TRUE(engine.is_valid());
2051 
2052  constexpr size_t frames_expected = 10;
2053  fml::CountDownLatch frame_latch(frames_expected);
2054  size_t frames_seen = 0;
2055  context.AddNativeCallback("SignalNativeTest",
2056  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2057  frames_seen++;
2058  frame_latch.CountDown();
2059  }));
2060  frame_latch.Wait();
2061 
2062  ASSERT_EQ(frames_expected, frames_seen);
2063 }
2064 
2065 TEST_F(EmbedderTest, PlatformViewMutatorsAreValid) {
2066  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2067 
2068  EmbedderConfigBuilder builder(context);
2069  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2070  builder.SetCompositor();
2071  builder.SetDartEntrypoint("platform_view_mutators");
2072 
2073  builder.SetRenderTargetType(
2075 
2076  fml::CountDownLatch latch(1);
2077  context.GetCompositor().SetNextPresentCallback(
2078  [&](const FlutterLayer** layers, size_t layers_count) {
2079  ASSERT_EQ(layers_count, 2u);
2080 
2081  // Layer 0 (Root)
2082  {
2083  FlutterBackingStore backing_store = *layers[0]->backing_store;
2084  backing_store.type = kFlutterBackingStoreTypeOpenGL;
2085  backing_store.did_update = true;
2087 
2088  FlutterLayer layer = {};
2089  layer.struct_size = sizeof(layer);
2091  layer.backing_store = &backing_store;
2092  layer.size = FlutterSizeMake(800.0, 600.0);
2093  layer.offset = FlutterPointMake(0.0, 0.0);
2094 
2095  ASSERT_EQ(*layers[0], layer);
2096  }
2097 
2098  // Layer 2
2099  {
2100  FlutterPlatformView platform_view = *layers[1]->platform_view;
2101  platform_view.struct_size = sizeof(platform_view);
2102  platform_view.identifier = 42;
2103  platform_view.mutations_count = 3;
2104 
2105  FlutterLayer layer = {};
2106  layer.struct_size = sizeof(layer);
2108  layer.platform_view = &platform_view;
2109  layer.size = FlutterSizeMake(800.0, 600.0);
2110  layer.offset = FlutterPointMake(0.0, 0.0);
2111 
2112  ASSERT_EQ(*layers[1], layer);
2113 
2114  // There are no ordering guarantees.
2115  for (size_t i = 0; i < platform_view.mutations_count; i++) {
2116  FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2117  switch (mutation.type) {
2119  mutation.clip_rounded_rect =
2120  FlutterRoundedRectMake(SkRRect::MakeRectXY(
2121  SkRect::MakeLTRB(10.0, 10.0, 800.0 - 10.0,
2122  600.0 - 10.0),
2123  14.0, 14.0));
2124  break;
2127  mutation.clip_rect = FlutterRectMake(
2128  SkRect::MakeXYWH(10.0, 10.0, 800.0 - 20.0, 600.0 - 20.0));
2129  break;
2132  mutation.opacity = 128.0 / 255.0;
2133  break;
2135  FML_CHECK(false)
2136  << "There should be no transformation in the test.";
2137  break;
2138  }
2139 
2140  ASSERT_EQ(*platform_view.mutations[i], mutation);
2141  }
2142  }
2143  latch.CountDown();
2144  });
2145 
2146  auto engine = builder.LaunchEngine();
2147 
2148  // Send a window metrics events so frames may be scheduled.
2149  FlutterWindowMetricsEvent event = {};
2150  event.struct_size = sizeof(event);
2151  event.width = 800;
2152  event.height = 600;
2153  event.pixel_ratio = 1.0;
2155  kSuccess);
2156  ASSERT_TRUE(engine.is_valid());
2157 
2158  latch.Wait();
2159 }
2160 
2161 TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) {
2162  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2163 
2164  EmbedderConfigBuilder builder(context);
2165  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2166  builder.SetCompositor();
2167  builder.SetDartEntrypoint("platform_view_mutators_with_pixel_ratio");
2168 
2169  builder.SetRenderTargetType(
2171 
2172  fml::CountDownLatch latch(1);
2173  context.GetCompositor().SetNextPresentCallback(
2174  [&](const FlutterLayer** layers, size_t layers_count) {
2175  ASSERT_EQ(layers_count, 2u);
2176 
2177  // Layer 0 (Root)
2178  {
2179  FlutterBackingStore backing_store = *layers[0]->backing_store;
2180  backing_store.type = kFlutterBackingStoreTypeOpenGL;
2181  backing_store.did_update = true;
2183 
2184  FlutterLayer layer = {};
2185  layer.struct_size = sizeof(layer);
2187  layer.backing_store = &backing_store;
2188  layer.size = FlutterSizeMake(800.0, 600.0);
2189  layer.offset = FlutterPointMake(0.0, 0.0);
2190 
2191  ASSERT_EQ(*layers[0], layer);
2192  }
2193 
2194  // Layer 2
2195  {
2196  FlutterPlatformView platform_view = *layers[1]->platform_view;
2197  platform_view.struct_size = sizeof(platform_view);
2198  platform_view.identifier = 42;
2199  platform_view.mutations_count = 3;
2200 
2201  FlutterLayer layer = {};
2202  layer.struct_size = sizeof(layer);
2204  layer.platform_view = &platform_view;
2205  layer.size = FlutterSizeMake(800.0, 600.0);
2206  layer.offset = FlutterPointMake(0.0, 0.0);
2207 
2208  ASSERT_EQ(*layers[1], layer);
2209 
2210  // There are no ordering guarantees.
2211  for (size_t i = 0; i < platform_view.mutations_count; i++) {
2212  FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2213  switch (mutation.type) {
2215  mutation.clip_rounded_rect =
2216  FlutterRoundedRectMake(SkRRect::MakeRectXY(
2217  SkRect::MakeLTRB(5.0, 5.0, 400.0 - 5.0, 300.0 - 5.0),
2218  7.0, 7.0));
2219  break;
2222  mutation.clip_rect = FlutterRectMake(
2223  SkRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2224  break;
2227  mutation.opacity = 128.0 / 255.0;
2228  break;
2231  mutation.transformation =
2232  FlutterTransformationMake(SkMatrix::Scale(2.0, 2.0));
2233  break;
2234  }
2235 
2236  ASSERT_EQ(*platform_view.mutations[i], mutation);
2237  }
2238  }
2239  latch.CountDown();
2240  });
2241 
2242  auto engine = builder.LaunchEngine();
2243 
2244  // Send a window metrics events so frames may be scheduled.
2245  FlutterWindowMetricsEvent event = {};
2246  event.struct_size = sizeof(event);
2247  event.width = 800;
2248  event.height = 600;
2249  event.pixel_ratio = 2.0;
2251  kSuccess);
2252  ASSERT_TRUE(engine.is_valid());
2253 
2254  latch.Wait();
2255 }
2256 
2258  PlatformViewMutatorsAreValidWithPixelRatioAndRootSurfaceTransformation) {
2259  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2260 
2261  EmbedderConfigBuilder builder(context);
2262  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2263  builder.SetCompositor();
2264  builder.SetDartEntrypoint("platform_view_mutators_with_pixel_ratio");
2265 
2266  builder.SetRenderTargetType(
2268 
2269  static const auto root_surface_transformation =
2270  SkMatrix().preTranslate(0, 800).preRotate(-90, 0, 0);
2271 
2272  context.SetRootSurfaceTransformation(root_surface_transformation);
2273 
2274  fml::CountDownLatch latch(1);
2275  context.GetCompositor().SetNextPresentCallback(
2276  [&](const FlutterLayer** layers, size_t layers_count) {
2277  ASSERT_EQ(layers_count, 2u);
2278 
2279  // Layer 0 (Root)
2280  {
2281  FlutterBackingStore backing_store = *layers[0]->backing_store;
2282  backing_store.type = kFlutterBackingStoreTypeOpenGL;
2283  backing_store.did_update = true;
2285 
2286  FlutterLayer layer = {};
2287  layer.struct_size = sizeof(layer);
2289  layer.backing_store = &backing_store;
2290  layer.size = FlutterSizeMake(600.0, 800.0);
2291  layer.offset = FlutterPointMake(0.0, 0.0);
2292 
2293  ASSERT_EQ(*layers[0], layer);
2294  }
2295 
2296  // Layer 2
2297  {
2298  FlutterPlatformView platform_view = *layers[1]->platform_view;
2299  platform_view.struct_size = sizeof(platform_view);
2300  platform_view.identifier = 42;
2301  platform_view.mutations_count = 4;
2302 
2303  FlutterLayer layer = {};
2304  layer.struct_size = sizeof(layer);
2306  layer.platform_view = &platform_view;
2307  layer.size = FlutterSizeMake(600.0, 800.0);
2308  layer.offset = FlutterPointMake(0.0, 0.0);
2309 
2310  ASSERT_EQ(*layers[1], layer);
2311 
2312  // There are no ordering guarantees.
2313  for (size_t i = 0; i < platform_view.mutations_count; i++) {
2314  FlutterPlatformViewMutation mutation = *platform_view.mutations[i];
2315  switch (mutation.type) {
2317  mutation.clip_rounded_rect =
2318  FlutterRoundedRectMake(SkRRect::MakeRectXY(
2319  SkRect::MakeLTRB(5.0, 5.0, 400.0 - 5.0, 300.0 - 5.0),
2320  7.0, 7.0));
2321  break;
2324  mutation.clip_rect = FlutterRectMake(
2325  SkRect::MakeXYWH(5.0, 5.0, 400.0 - 10.0, 300.0 - 10.0));
2326  break;
2329  mutation.opacity = 128.0 / 255.0;
2330  break;
2333  mutation.transformation =
2334  FlutterTransformationMake(root_surface_transformation);
2335 
2336  break;
2337  }
2338 
2339  ASSERT_EQ(*platform_view.mutations[i], mutation);
2340  }
2341  }
2342  latch.CountDown();
2343  });
2344 
2345  auto engine = builder.LaunchEngine();
2346 
2347  // Send a window metrics events so frames may be scheduled.
2348  FlutterWindowMetricsEvent event = {};
2349  event.struct_size = sizeof(event);
2350  event.width = 800;
2351  event.height = 600;
2352  event.pixel_ratio = 2.0;
2354  kSuccess);
2355  ASSERT_TRUE(engine.is_valid());
2356 
2357  latch.Wait();
2358 }
2359 
2360 TEST_F(EmbedderTest, EmptySceneIsAcceptable) {
2361  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2362 
2363  EmbedderConfigBuilder builder(context);
2364  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2365  builder.SetCompositor();
2366  builder.SetDartEntrypoint("empty_scene");
2368  context.AddNativeCallback(
2369  "SignalNativeTest",
2370  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
2371 
2372  auto engine = builder.LaunchEngine();
2373 
2374  ASSERT_TRUE(engine.is_valid());
2375 
2376  FlutterWindowMetricsEvent event = {};
2377  event.struct_size = sizeof(event);
2378  event.width = 800;
2379  event.height = 600;
2380  event.pixel_ratio = 1.0;
2382  kSuccess);
2383  latch.Wait();
2384 }
2385 
2386 TEST_F(EmbedderTest, SceneWithNoRootContainerIsAcceptable) {
2387  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2388 
2389  EmbedderConfigBuilder builder(context);
2390  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
2391  builder.SetCompositor();
2392  builder.SetRenderTargetType(
2394  builder.SetDartEntrypoint("scene_with_no_container");
2396  context.AddNativeCallback(
2397  "SignalNativeTest",
2398  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
2399 
2400  auto engine = builder.LaunchEngine();
2401 
2402  ASSERT_TRUE(engine.is_valid());
2403 
2404  FlutterWindowMetricsEvent event = {};
2405  event.struct_size = sizeof(event);
2406  event.width = 800;
2407  event.height = 600;
2408  event.pixel_ratio = 1.0;
2410  kSuccess);
2411  latch.Wait();
2412 }
2413 
2414 // Verifies that https://skia-review.googlesource.com/c/skia/+/259174 is pulled
2415 // into the engine.
2416 TEST_F(EmbedderTest, ArcEndCapsAreDrawnCorrectly) {
2417  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2418 
2419  EmbedderConfigBuilder builder(context);
2420  builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
2421  builder.SetCompositor();
2422  builder.SetDartEntrypoint("arc_end_caps_correct");
2423  builder.SetRenderTargetType(
2425 
2426  const auto root_surface_transformation = SkMatrix()
2427  .preScale(1.0, -1.0)
2428  .preTranslate(1024.0, -800.0)
2429  .preRotate(90.0);
2430 
2431  context.SetRootSurfaceTransformation(root_surface_transformation);
2432 
2433  auto engine = builder.LaunchEngine();
2434 
2435  auto scene_image = context.GetNextSceneImage();
2436 
2437  ASSERT_TRUE(engine.is_valid());
2438 
2439  FlutterWindowMetricsEvent event = {};
2440  event.struct_size = sizeof(event);
2441  event.width = 1024;
2442  event.height = 800;
2443  event.pixel_ratio = 1.0;
2445  kSuccess);
2446 
2447  ASSERT_TRUE(ImageMatchesFixture("arc_end_caps.png", scene_image));
2448 }
2449 
2450 TEST_F(EmbedderTest, ClipsAreCorrectlyCalculated) {
2451  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2452 
2453  EmbedderConfigBuilder builder(context);
2454  builder.SetOpenGLRendererConfig(SkISize::Make(400, 300));
2455  builder.SetCompositor();
2456  builder.SetDartEntrypoint("scene_builder_with_clips");
2457  builder.SetRenderTargetType(
2459 
2460  const auto root_surface_transformation =
2461  SkMatrix().preTranslate(0, 400).preRotate(-90, 0, 0);
2462 
2463  context.SetRootSurfaceTransformation(root_surface_transformation);
2464 
2466  context.GetCompositor().SetNextPresentCallback(
2467  [&](const FlutterLayer** layers, size_t layers_count) {
2468  ASSERT_EQ(layers_count, 2u);
2469 
2470  {
2471  FlutterPlatformView platform_view = *layers[0]->platform_view;
2472  platform_view.struct_size = sizeof(platform_view);
2473  platform_view.identifier = 42;
2474 
2475  FlutterLayer layer = {};
2476  layer.struct_size = sizeof(layer);
2478  layer.platform_view = &platform_view;
2479  layer.size = FlutterSizeMake(300.0, 400.0);
2480  layer.offset = FlutterPointMake(0.0, 0.0);
2481 
2482  ASSERT_EQ(*layers[0], layer);
2483 
2484  bool clip_assertions_checked = false;
2485 
2486  // The total transformation on the stack upto the platform view.
2487  const auto total_xformation =
2488  GetTotalMutationTransformationMatrix(layers[0]->platform_view);
2489 
2491  layers[0]->platform_view,
2493  [&](const auto& mutation) {
2494  FlutterRect clip = mutation.clip_rect;
2495 
2496  // The test is only setup to supply one clip. Make sure it is
2497  // the one we expect.
2498  const auto rect_to_compare =
2499  SkRect::MakeLTRB(10.0, 10.0, 390, 290);
2500  ASSERT_EQ(clip, FlutterRectMake(rect_to_compare));
2501 
2502  // This maps the clip from device space into surface space.
2503  SkRect mapped;
2504  ASSERT_TRUE(total_xformation.mapRect(&mapped, rect_to_compare));
2505  ASSERT_EQ(mapped, SkRect::MakeLTRB(10, 10, 290, 390));
2506  clip_assertions_checked = true;
2507  });
2508 
2509  ASSERT_TRUE(clip_assertions_checked);
2510  }
2511 
2512  latch.Signal();
2513  });
2514 
2515  auto engine = builder.LaunchEngine();
2516  ASSERT_TRUE(engine.is_valid());
2517 
2518  FlutterWindowMetricsEvent event = {};
2519  event.struct_size = sizeof(event);
2520  event.width = 400;
2521  event.height = 300;
2522  event.pixel_ratio = 1.0;
2524  kSuccess);
2525 
2526  latch.Wait();
2527 }
2528 
2529 TEST_F(EmbedderTest, ComplexClipsAreCorrectlyCalculated) {
2530  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2531 
2532  EmbedderConfigBuilder builder(context);
2533  builder.SetOpenGLRendererConfig(SkISize::Make(1024, 600));
2534  builder.SetCompositor();
2535  builder.SetDartEntrypoint("scene_builder_with_complex_clips");
2536  builder.SetRenderTargetType(
2538 
2539  const auto root_surface_transformation =
2540  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
2541 
2542  context.SetRootSurfaceTransformation(root_surface_transformation);
2543 
2545  context.GetCompositor().SetNextPresentCallback(
2546  [&](const FlutterLayer** layers, size_t layers_count) {
2547  ASSERT_EQ(layers_count, 2u);
2548 
2549  {
2550  FlutterPlatformView platform_view = *layers[0]->platform_view;
2551  platform_view.struct_size = sizeof(platform_view);
2552  platform_view.identifier = 42;
2553 
2554  FlutterLayer layer = {};
2555  layer.struct_size = sizeof(layer);
2557  layer.platform_view = &platform_view;
2558  layer.size = FlutterSizeMake(600.0, 1024.0);
2559  layer.offset = FlutterPointMake(0.0, -256.0);
2560 
2561  ASSERT_EQ(*layers[0], layer);
2562 
2563  const auto** mutations = platform_view.mutations;
2564 
2565  ASSERT_EQ(mutations[0]->type,
2567  ASSERT_EQ(SkMatrixMake(mutations[0]->transformation),
2568  root_surface_transformation);
2569 
2570  ASSERT_EQ(mutations[1]->type,
2572  ASSERT_EQ(SkRectMake(mutations[1]->clip_rect),
2573  SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
2574 
2575  ASSERT_EQ(mutations[2]->type,
2577  ASSERT_EQ(SkMatrixMake(mutations[2]->transformation),
2578  SkMatrix::Translate(512.0, 0.0));
2579 
2580  ASSERT_EQ(mutations[3]->type,
2582  ASSERT_EQ(SkRectMake(mutations[3]->clip_rect),
2583  SkRect::MakeLTRB(0.0, 0.0, 512.0, 600.0));
2584 
2585  ASSERT_EQ(mutations[4]->type,
2587  ASSERT_EQ(SkMatrixMake(mutations[4]->transformation),
2588  SkMatrix::Translate(-256.0, 0.0));
2589 
2590  ASSERT_EQ(mutations[5]->type,
2592  ASSERT_EQ(SkRectMake(mutations[5]->clip_rect),
2593  SkRect::MakeLTRB(0.0, 0.0, 1024.0, 600.0));
2594  }
2595 
2596  latch.Signal();
2597  });
2598 
2599  auto engine = builder.LaunchEngine();
2600  ASSERT_TRUE(engine.is_valid());
2601 
2602  FlutterWindowMetricsEvent event = {};
2603  event.struct_size = sizeof(event);
2604  event.width = 400;
2605  event.height = 300;
2606  event.pixel_ratio = 1.0;
2608  kSuccess);
2609 
2610  latch.Wait();
2611 }
2612 
2613 TEST_F(EmbedderTest, ObjectsCanBePostedViaPorts) {
2614  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2615  EmbedderConfigBuilder builder(context);
2616  builder.SetOpenGLRendererConfig(SkISize::Make(800, 1024));
2617  builder.SetDartEntrypoint("objects_can_be_posted");
2618 
2619  // Synchronously acquire the send port from the Dart end. We will be using
2620  // this to send message. The Dart end will just echo those messages back to us
2621  // for inspection.
2624  context.AddNativeCallback("SignalNativeCount",
2625  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2627  Dart_GetNativeArgument(args, 0));
2628  event.Signal();
2629  }));
2630  auto engine = builder.LaunchEngine();
2631  ASSERT_TRUE(engine.is_valid());
2632  event.Wait();
2633  ASSERT_NE(port, 0);
2634 
2635  using Trampoline = std::function<void(Dart_Handle message)>;
2636  Trampoline trampoline;
2637 
2638  context.AddNativeCallback("SendObjectToNativeCode",
2639  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2640  FML_CHECK(trampoline);
2641  auto trampoline_copy = trampoline;
2642  trampoline = nullptr;
2643  trampoline_copy(Dart_GetNativeArgument(args, 0));
2644  }));
2645 
2646  // Check null.
2647  {
2648  FlutterEngineDartObject object = {};
2650  trampoline = [&](Dart_Handle handle) {
2651  ASSERT_TRUE(Dart_IsNull(handle));
2652  event.Signal();
2653  };
2654  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2655  kSuccess);
2656  event.Wait();
2657  }
2658 
2659  // Check bool.
2660  {
2661  FlutterEngineDartObject object = {};
2663  object.bool_value = true;
2664  trampoline = [&](Dart_Handle handle) {
2665  ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(handle));
2666  event.Signal();
2667  };
2668  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2669  kSuccess);
2670  event.Wait();
2671  }
2672 
2673  // Check int32.
2674  {
2675  FlutterEngineDartObject object = {};
2677  object.int32_value = 1988;
2678  trampoline = [&](Dart_Handle handle) {
2679  ASSERT_EQ(tonic::DartConverter<int32_t>::FromDart(handle), 1988);
2680  event.Signal();
2681  };
2682  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2683  kSuccess);
2684  event.Wait();
2685  }
2686 
2687  // Check int64.
2688  {
2689  FlutterEngineDartObject object = {};
2691  object.int64_value = 1988;
2692  trampoline = [&](Dart_Handle handle) {
2693  ASSERT_EQ(tonic::DartConverter<int64_t>::FromDart(handle), 1988);
2694  event.Signal();
2695  };
2696  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2697  kSuccess);
2698  event.Wait();
2699  }
2700 
2701  // Check double.
2702  {
2703  FlutterEngineDartObject object = {};
2705  object.double_value = 1988.0;
2706  trampoline = [&](Dart_Handle handle) {
2707  ASSERT_DOUBLE_EQ(tonic::DartConverter<double>::FromDart(handle), 1988.0);
2708  event.Signal();
2709  };
2710  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2711  kSuccess);
2712  event.Wait();
2713  }
2714 
2715  // Check string.
2716  {
2717  const char* message = "Hello. My name is Inigo Montoya.";
2718  FlutterEngineDartObject object = {};
2720  object.string_value = message;
2721  trampoline = [&](Dart_Handle handle) {
2723  std::string{message});
2724  event.Signal();
2725  };
2726  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2727  kSuccess);
2728  event.Wait();
2729  }
2730 
2731  // Check buffer (copied out).
2732  {
2733  std::vector<uint8_t> message;
2734  message.resize(1988);
2735 
2736  ASSERT_TRUE(MemsetPatternSetOrCheck(
2738 
2739  FlutterEngineDartBuffer buffer = {};
2740 
2741  buffer.struct_size = sizeof(buffer);
2742  buffer.user_data = nullptr;
2743  buffer.buffer_collect_callback = nullptr;
2744  buffer.buffer = message.data();
2745  buffer.buffer_size = message.size();
2746 
2747  FlutterEngineDartObject object = {};
2749  object.buffer_value = &buffer;
2750  trampoline = [&](Dart_Handle handle) {
2751  intptr_t length = 0;
2752  Dart_ListLength(handle, &length);
2753  ASSERT_EQ(length, 1988);
2754  // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
2755  // DartConvertor in tonic is broken which is preventing the buffer
2756  // being checked here. Fix tonic and strengthen this check. For now, just
2757  // the buffer length is checked.
2758  event.Signal();
2759  };
2760  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2761  kSuccess);
2762  event.Wait();
2763  }
2764 
2765  std::vector<uint8_t> message;
2766  fml::AutoResetWaitableEvent buffer_released_latch;
2767 
2768  // Check buffer (caller own buffer with zero copy transfer).
2769  {
2770  message.resize(1988);
2771 
2772  ASSERT_TRUE(MemsetPatternSetOrCheck(
2774 
2775  FlutterEngineDartBuffer buffer = {};
2776 
2777  buffer.struct_size = sizeof(buffer);
2778  buffer.user_data = &buffer_released_latch;
2779  buffer.buffer_collect_callback = +[](void* user_data) {
2780  reinterpret_cast<fml::AutoResetWaitableEvent*>(user_data)->Signal();
2781  };
2782  buffer.buffer = message.data();
2783  buffer.buffer_size = message.size();
2784 
2785  FlutterEngineDartObject object = {};
2787  object.buffer_value = &buffer;
2788  trampoline = [&](Dart_Handle handle) {
2789  intptr_t length = 0;
2790  Dart_ListLength(handle, &length);
2791  ASSERT_EQ(length, 1988);
2792  // TODO(chinmaygarde); The std::vector<uint8_t> specialization for
2793  // DartConvertor in tonic is broken which is preventing the buffer
2794  // being checked here. Fix tonic and strengthen this check. For now, just
2795  // the buffer length is checked.
2796  event.Signal();
2797  };
2798  ASSERT_EQ(FlutterEnginePostDartObject(engine.get(), port, &object),
2799  kSuccess);
2800  event.Wait();
2801  }
2802 
2803  engine.reset();
2804 
2805  // We cannot determine when the VM will GC objects that might have external
2806  // typed data finalizers. Since we need to ensure that we correctly wired up
2807  // finalizers from the embedders, we force the VM to collect all objects but
2808  // just shutting it down.
2809  buffer_released_latch.Wait();
2810 }
2811 
2812 TEST_F(EmbedderTest, CompositorCanPostZeroLayersForPresentation) {
2813  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2814 
2815  EmbedderConfigBuilder builder(context);
2816  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2817  builder.SetCompositor();
2818  builder.SetDartEntrypoint("empty_scene_posts_zero_layers_to_compositor");
2819  builder.SetRenderTargetType(
2821 
2823 
2824  context.GetCompositor().SetNextPresentCallback(
2825  [&](const FlutterLayer** layers, size_t layers_count) {
2826  ASSERT_EQ(layers_count, 0u);
2827  latch.Signal();
2828  });
2829 
2830  auto engine = builder.LaunchEngine();
2831 
2832  FlutterWindowMetricsEvent event = {};
2833  event.struct_size = sizeof(event);
2834  event.width = 300;
2835  event.height = 200;
2836  event.pixel_ratio = 1.0;
2838  kSuccess);
2839  ASSERT_TRUE(engine.is_valid());
2840  latch.Wait();
2841 
2842  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
2843 }
2844 
2845 TEST_F(EmbedderTest, CompositorCanPostOnlyPlatformViews) {
2846  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2847 
2848  EmbedderConfigBuilder builder(context);
2849  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2850  builder.SetCompositor();
2851  builder.SetDartEntrypoint("compositor_can_post_only_platform_views");
2852  builder.SetRenderTargetType(
2854 
2856 
2857  context.GetCompositor().SetNextPresentCallback(
2858  [&](const FlutterLayer** layers, size_t layers_count) {
2859  ASSERT_EQ(layers_count, 2u);
2860 
2861  // Layer 0
2862  {
2863  FlutterPlatformView platform_view = *layers[0]->platform_view;
2864  platform_view.struct_size = sizeof(platform_view);
2865  platform_view.identifier = 42;
2866  FlutterLayer layer = {};
2867  layer.struct_size = sizeof(layer);
2869  layer.platform_view = &platform_view;
2870  layer.size = FlutterSizeMake(300.0, 200.0);
2871  layer.offset = FlutterPointMake(0.0, 0.0);
2872 
2873  ASSERT_EQ(*layers[0], layer);
2874  }
2875 
2876  // Layer 1
2877  {
2878  FlutterPlatformView platform_view = *layers[1]->platform_view;
2879  platform_view.struct_size = sizeof(platform_view);
2880  platform_view.identifier = 24;
2881  FlutterLayer layer = {};
2882  layer.struct_size = sizeof(layer);
2884  layer.platform_view = &platform_view;
2885  layer.size = FlutterSizeMake(300.0, 200.0);
2886  layer.offset = FlutterPointMake(0.0, 0.0);
2887 
2888  ASSERT_EQ(*layers[1], layer);
2889  }
2890  latch.Signal();
2891  });
2892 
2893  auto engine = builder.LaunchEngine();
2894 
2895  FlutterWindowMetricsEvent event = {};
2896  event.struct_size = sizeof(event);
2897  event.width = 300;
2898  event.height = 200;
2899  event.pixel_ratio = 1.0;
2901  kSuccess);
2902  ASSERT_TRUE(engine.is_valid());
2903  latch.Wait();
2904 
2905  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
2906 }
2907 
2908 TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) {
2909  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2910 
2911  EmbedderConfigBuilder builder(context);
2912  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2913  builder.SetCompositor();
2914  builder.SetDartEntrypoint("render_targets_are_recycled");
2915  builder.SetRenderTargetType(
2917 
2918  fml::CountDownLatch latch(2);
2919 
2920  context.AddNativeCallback("SignalNativeTest",
2921  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2922  latch.CountDown();
2923  }));
2924 
2925  context.GetCompositor().SetNextPresentCallback(
2926  [&](const FlutterLayer** layers, size_t layers_count) {
2927  ASSERT_EQ(layers_count, 20u);
2928  latch.CountDown();
2929  });
2930 
2931  auto engine = builder.LaunchEngine();
2932  ASSERT_TRUE(engine.is_valid());
2933 
2934  FlutterWindowMetricsEvent event = {};
2935  event.struct_size = sizeof(event);
2936  event.width = 300;
2937  event.height = 200;
2938  event.pixel_ratio = 1.0;
2940  kSuccess);
2941 
2942  latch.Wait();
2943  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 10u);
2944  ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
2945  ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 0u);
2946  // Killing the engine should immediately collect all pending render targets.
2947  engine.reset();
2948  ASSERT_EQ(context.GetCompositor().GetPendingBackingStoresCount(), 0u);
2949  ASSERT_EQ(context.GetCompositor().GetBackingStoresCreatedCount(), 10u);
2950  ASSERT_EQ(context.GetCompositor().GetBackingStoresCollectedCount(), 10u);
2951 }
2952 
2953 TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) {
2954  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
2955 
2956  EmbedderConfigBuilder builder(context);
2957  builder.SetOpenGLRendererConfig(SkISize::Make(300, 200));
2958  builder.SetCompositor();
2959  builder.SetDartEntrypoint("render_targets_are_recycled");
2960  builder.SetRenderTargetType(
2962 
2963  fml::CountDownLatch latch(2);
2964 
2965  context.AddNativeCallback("SignalNativeTest",
2966  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
2967  latch.CountDown();
2968  }));
2969 
2970  size_t frame_count = 0;
2971  std::vector<void*> first_frame_backing_store_user_data;
2972  context.GetCompositor().SetPresentCallback(
2973  [&](const FlutterLayer** layers, size_t layers_count) {
2974  ASSERT_EQ(layers_count, 20u);
2975 
2976  if (first_frame_backing_store_user_data.size() == 0u) {
2977  for (size_t i = 0; i < layers_count; ++i) {
2978  if (layers[i]->type == kFlutterLayerContentTypeBackingStore) {
2979  first_frame_backing_store_user_data.push_back(
2980  layers[i]->backing_store->user_data);
2981  }
2982  }
2983  return;
2984  }
2985 
2986  ASSERT_EQ(first_frame_backing_store_user_data.size(), 10u);
2987 
2988  frame_count++;
2989  std::vector<void*> backing_store_user_data;
2990  for (size_t i = 0; i < layers_count; ++i) {
2991  if (layers[i]->type == kFlutterLayerContentTypeBackingStore) {
2992  backing_store_user_data.push_back(
2993  layers[i]->backing_store->user_data);
2994  }
2995  }
2996 
2997  ASSERT_EQ(backing_store_user_data.size(), 10u);
2998 
2999  ASSERT_EQ(first_frame_backing_store_user_data, backing_store_user_data);
3000 
3001  if (frame_count == 20) {
3002  latch.CountDown();
3003  }
3004  },
3005  false // one shot
3006  );
3007 
3008  auto engine = builder.LaunchEngine();
3009  ASSERT_TRUE(engine.is_valid());
3010 
3011  FlutterWindowMetricsEvent event = {};
3012  event.struct_size = sizeof(event);
3013  event.width = 300;
3014  event.height = 200;
3015  event.pixel_ratio = 1.0;
3017  kSuccess);
3018 
3019  latch.Wait();
3020 }
3021 
3022 TEST_F(EmbedderTest, FrameInfoContainsValidWidthAndHeight) {
3023  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3024 
3025  EmbedderConfigBuilder builder(context);
3026  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3027  builder.SetDartEntrypoint("push_frames_over_and_over");
3028 
3029  const auto root_surface_transformation =
3030  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
3031 
3032  context.SetRootSurfaceTransformation(root_surface_transformation);
3033 
3034  auto engine = builder.LaunchEngine();
3035 
3036  // Send a window metrics events so frames may be scheduled.
3037  FlutterWindowMetricsEvent event = {};
3038  event.struct_size = sizeof(event);
3039  event.width = 1024;
3040  event.height = 600;
3041  event.pixel_ratio = 1.0;
3043  kSuccess);
3044  ASSERT_TRUE(engine.is_valid());
3045 
3046  fml::CountDownLatch frame_latch(10);
3047 
3048  context.AddNativeCallback("SignalNativeTest",
3049  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3050  /* Nothing to do. */
3051  }));
3052 
3053  static_cast<EmbedderTestContextGL&>(context).SetGLGetFBOCallback(
3054  [&event, &frame_latch](FlutterFrameInfo frame_info) {
3055  // width and height are rotated by 90 deg
3056  ASSERT_EQ(frame_info.size.width, event.height);
3057  ASSERT_EQ(frame_info.size.height, event.width);
3058 
3059  frame_latch.CountDown();
3060  });
3061 
3062  frame_latch.Wait();
3063 }
3064 
3065 TEST_F(EmbedderTest, MustNotRunWithBothFBOCallbacksSet) {
3066  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3067 
3068  EmbedderConfigBuilder builder(context);
3069  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3070  builder.SetOpenGLFBOCallBack();
3071 
3072  auto engine = builder.LaunchEngine();
3073  ASSERT_FALSE(engine.is_valid());
3074 }
3075 
3076 TEST_F(EmbedderTest, MustNotRunWithBothPresentCallbacksSet) {
3077  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3078 
3079  EmbedderConfigBuilder builder(context);
3080  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3081  builder.SetOpenGLPresentCallBack();
3082 
3083  auto engine = builder.LaunchEngine();
3084  ASSERT_FALSE(engine.is_valid());
3085 }
3086 
3087 TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) {
3088  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3089 
3090  EmbedderConfigBuilder builder(context);
3091  builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
3092  builder.SetDartEntrypoint("push_frames_over_and_over");
3093 
3094  const auto root_surface_transformation =
3095  SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
3096 
3097  context.SetRootSurfaceTransformation(root_surface_transformation);
3098 
3099  auto engine = builder.LaunchEngine();
3100 
3101  // Send a window metrics events so frames may be scheduled.
3102  FlutterWindowMetricsEvent event = {};
3103  event.struct_size = sizeof(event);
3104  event.width = 1024;
3105  event.height = 600;
3106  event.pixel_ratio = 1.0;
3108  kSuccess);
3109  ASSERT_TRUE(engine.is_valid());
3110 
3111  fml::CountDownLatch frame_latch(10);
3112 
3113  context.AddNativeCallback("SignalNativeTest",
3114  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
3115  /* Nothing to do. */
3116  }));
3117 
3118  const uint32_t window_fbo_id =
3119  static_cast<EmbedderTestContextGL&>(context).GetWindowFBOId();
3120  static_cast<EmbedderTestContextGL&>(context).SetGLPresentCallback(
3121  [window_fbo_id = window_fbo_id, &frame_latch](uint32_t fbo_id) {
3122  ASSERT_EQ(fbo_id, window_fbo_id);
3123 
3124  frame_latch.CountDown();
3125  });
3126 
3127  frame_latch.Wait();
3128 }
3129 
3130 TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithDisplayId) {
3131  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3132 
3133  EmbedderConfigBuilder builder(context);
3134  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3135  builder.SetCompositor();
3136  builder.SetDartEntrypoint("empty_scene");
3138  context.AddNativeCallback(
3139  "SignalNativeTest",
3140  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3141 
3142  auto engine = builder.LaunchEngine();
3143 
3144  ASSERT_TRUE(engine.is_valid());
3145 
3146  FlutterEngineDisplay display;
3147  display.struct_size = sizeof(FlutterEngineDisplay);
3148  display.display_id = 1;
3149  display.refresh_rate = 20;
3150 
3151  std::vector<FlutterEngineDisplay> displays = {display};
3152 
3154  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3155  displays.size());
3156  ASSERT_EQ(result, kSuccess);
3157 
3158  flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
3159  ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
3160 
3161  FlutterWindowMetricsEvent event = {};
3162  event.struct_size = sizeof(event);
3163  event.width = 800;
3164  event.height = 600;
3165  event.pixel_ratio = 1.0;
3167  kSuccess);
3168 
3169  latch.Wait();
3170 }
3171 
3172 TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithoutDisplayId) {
3173  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3174 
3175  EmbedderConfigBuilder builder(context);
3176  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3177  builder.SetCompositor();
3178  builder.SetDartEntrypoint("empty_scene");
3180  context.AddNativeCallback(
3181  "SignalNativeTest",
3182  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3183 
3184  auto engine = builder.LaunchEngine();
3185 
3186  ASSERT_TRUE(engine.is_valid());
3187 
3188  FlutterEngineDisplay display;
3189  display.struct_size = sizeof(FlutterEngineDisplay);
3190  display.single_display = true;
3191  display.refresh_rate = 20;
3192 
3193  std::vector<FlutterEngineDisplay> displays = {display};
3194 
3196  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3197  displays.size());
3198  ASSERT_EQ(result, kSuccess);
3199 
3200  flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
3201  ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display.refresh_rate);
3202 
3203  FlutterWindowMetricsEvent event = {};
3204  event.struct_size = sizeof(event);
3205  event.width = 800;
3206  event.height = 600;
3207  event.pixel_ratio = 1.0;
3209  kSuccess);
3210 
3211  latch.Wait();
3212 }
3213 
3214 TEST_F(EmbedderTest, SetValidMultiDisplayConfiguration) {
3215  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3216 
3217  EmbedderConfigBuilder builder(context);
3218  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3219  builder.SetCompositor();
3220  builder.SetDartEntrypoint("empty_scene");
3222  context.AddNativeCallback(
3223  "SignalNativeTest",
3224  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3225 
3226  auto engine = builder.LaunchEngine();
3227 
3228  ASSERT_TRUE(engine.is_valid());
3229 
3230  FlutterEngineDisplay display_1;
3231  display_1.struct_size = sizeof(FlutterEngineDisplay);
3232  display_1.display_id = 1;
3233  display_1.single_display = false;
3234  display_1.refresh_rate = 20;
3235 
3236  FlutterEngineDisplay display_2;
3237  display_2.struct_size = sizeof(FlutterEngineDisplay);
3238  display_2.display_id = 2;
3239  display_2.single_display = false;
3240  display_2.refresh_rate = 60;
3241 
3242  std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
3243 
3245  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3246  displays.size());
3247  ASSERT_EQ(result, kSuccess);
3248 
3249  flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
3250  ASSERT_EQ(shell.GetMainDisplayRefreshRate(), display_1.refresh_rate);
3251 
3252  FlutterWindowMetricsEvent event = {};
3253  event.struct_size = sizeof(event);
3254  event.width = 800;
3255  event.height = 600;
3256  event.pixel_ratio = 1.0;
3258  kSuccess);
3259 
3260  latch.Wait();
3261 }
3262 
3263 TEST_F(EmbedderTest, MultipleDisplaysWithSingleDisplayTrueIsInvalid) {
3264  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3265 
3266  EmbedderConfigBuilder builder(context);
3267  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3268  builder.SetCompositor();
3269  builder.SetDartEntrypoint("empty_scene");
3271  context.AddNativeCallback(
3272  "SignalNativeTest",
3273  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3274 
3275  auto engine = builder.LaunchEngine();
3276 
3277  ASSERT_TRUE(engine.is_valid());
3278 
3279  FlutterEngineDisplay display_1;
3280  display_1.struct_size = sizeof(FlutterEngineDisplay);
3281  display_1.display_id = 1;
3282  display_1.single_display = true;
3283  display_1.refresh_rate = 20;
3284 
3285  FlutterEngineDisplay display_2;
3286  display_2.struct_size = sizeof(FlutterEngineDisplay);
3287  display_2.display_id = 2;
3288  display_2.single_display = true;
3289  display_2.refresh_rate = 60;
3290 
3291  std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
3292 
3294  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3295  displays.size());
3296  ASSERT_NE(result, kSuccess);
3297 
3298  FlutterWindowMetricsEvent event = {};
3299  event.struct_size = sizeof(event);
3300  event.width = 800;
3301  event.height = 600;
3302  event.pixel_ratio = 1.0;
3304  kSuccess);
3305 
3306  latch.Wait();
3307 }
3308 
3309 TEST_F(EmbedderTest, MultipleDisplaysWithSameDisplayIdIsInvalid) {
3310  auto& context = GetEmbedderContext(ContextType::kOpenGLContext);
3311 
3312  EmbedderConfigBuilder builder(context);
3313  builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
3314  builder.SetCompositor();
3315  builder.SetDartEntrypoint("empty_scene");
3317  context.AddNativeCallback(
3318  "SignalNativeTest",
3319  CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
3320 
3321  auto engine = builder.LaunchEngine();
3322 
3323  ASSERT_TRUE(engine.is_valid());
3324 
3325  FlutterEngineDisplay display_1;
3326  display_1.struct_size = sizeof(FlutterEngineDisplay);
3327  display_1.display_id = 1;
3328  display_1.single_display = false;
3329  display_1.refresh_rate = 20;
3330 
3331  FlutterEngineDisplay display_2;
3332  display_2.struct_size = sizeof(FlutterEngineDisplay);
3333  display_2.display_id = 1;
3334  display_2.single_display = false;
3335  display_2.refresh_rate = 60;
3336 
3337  std::vector<FlutterEngineDisplay> displays = {display_1, display_2};
3338 
3340  engine.get(), kFlutterEngineDisplaysUpdateTypeStartup, displays.data(),
3341  displays.size());
3342  ASSERT_NE(result, kSuccess);
3343 
3344  FlutterWindowMetricsEvent event = {};
3345  event.struct_size = sizeof(event);
3346  event.width = 800;
3347  event.height = 600;
3348  event.pixel_ratio = 1.0;
3350  kSuccess);
3351 
3352  latch.Wait();
3353 }
3354 
3355 } // namespace testing
3356 } // 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:2012
G_BEGIN_DECLS FlValue * args
SkMatrix GetTotalMutationTransformationMatrix(const FlutterPlatformViewMutation **mutations, size_t count)
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:846
size_t GetCachedEntriesCount() const
uint32_t width
Definition: embedder.h:319
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:1206
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:1717
int64_t FlutterEngineDartPort
Definition: embedder.h:1004
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:56
const FlutterBackingStore * backing_store
Definition: embedder.h:893
FlutterPlatformViewIdentifier identifier
Definition: embedder.h:822
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
Definition: shell.cc:583
FlutterSize size
The size of the layer (in physical pixels).
Definition: embedder.h:902
FlutterTransformation transformation
Definition: embedder.h:812
void reset(const T &value=Traits::InvalidValue())
Definition: unique_object.h:62
sk_sp< SkSurface > CreateRenderSurface(const FlutterLayer &layer, GrDirectContext *context)
FlutterSize FlutterSizeMake(double width, double height)
virtual void PostTask(const fml::closure &task)
Definition: task_runner.cc:24
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...
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:1825
FlutterPoint offset
Definition: embedder.h:900
size_t struct_size
This size of this struct. Must be sizeof(FlutterDisplay).
Definition: embedder.h:977
const T & get() const
Definition: unique_object.h:87
A structure to represent a rectangle.
Definition: embedder.h:324
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
SkMatrix SkMatrixMake(const FlutterTransformation &xformation)
bool is_valid() const
Definition: unique_object.h:89
uint32_t height
Definition: embedder.h:320
FlutterUIntSize size
The size of the surface that will be backed by the fbo.
Definition: embedder.h:354
FlutterOpenGLTargetType type
Definition: embedder.h:763
size_t struct_size
The size of this struct. Must be sizeof(FlutterEngineDartBuffer).
Definition: embedder.h:1020
G_BEGIN_DECLS FlValue gpointer user_data
Indicates that the contents of this layer are determined by the embedder.
Definition: embedder.h:881
FlutterSoftwareBackingStore software
The description of the software backing store.
Definition: embedder.h:865
FlutterEngineDisplayId display_id
Definition: embedder.h:979
size_t row_bytes
The number of bytes in a single row of the allocation.
Definition: embedder.h:778
FlutterPoint FlutterPointMake(double x, double y)
fml::TaskRunnerAffineWeakPtr< Rasterizer > GetRasterizer() const
Rasterizers may only be accessed on the GPU task runner.
Definition: shell.cc:587
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:1487
FlutterOpenGLBackingStore open_gl
The description of the OpenGL backing store.
Definition: embedder.h:863
const FlutterPlatformView * platform_view
Definition: embedder.h:896
FlutterLayerContentType type
Definition: embedder.h:889
size_t length
size_t mutations_count
Definition: embedder.h:825
void SetPlatformTaskRunner(const FlutterTaskRunnerDescription *runner)
VoidCallback buffer_collect_callback
Definition: embedder.h:1044
double width
Definition: embedder.h:311
size_t struct_size
The size of this struct. Must be sizeof(FlutterBackingStore).
Definition: embedder.h:851
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:457
GdkEventButton * event
Definition: fl_view.cc:62
size_t height
The number of rows in the allocation.
Definition: embedder.h:780
FlutterBackingStoreCollectCallback collect_backing_store_callback
Definition: embedder.h:936
FlutterBackingStoreType type
Specifies the type of backing store.
Definition: embedder.h:857
FlutterEngineResult
Definition: embedder.h:65
const FlutterPlatformViewMutation ** mutations
Definition: embedder.h:838
FlutterLayersPresentCallback present_layers_callback
Definition: embedder.h:939
FlutterRoundedRect clip_rounded_rect
Definition: embedder.h:811
#define FML_CHECK(condition)
Definition: logging.h:68
double height
Definition: embedder.h:312
FlutterPlatformViewMutationType type
The type of the mutation described by the subsequent union.
Definition: embedder.h:807
size_t buffer_size
The size of the buffer.
Definition: embedder.h:1052
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformView).
Definition: embedder.h:818
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:1229
FlutterRoundedRect FlutterRoundedRectMake(const SkRRect &rect)
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:1167
size_t struct_size
This size of this struct. Must be sizeof(FlutterLayer).
Definition: embedder.h:886
FlutterTransformation FlutterTransformationMake(const SkMatrix &matrix)
void SetRenderTargetType(EmbedderTestBackingStoreProducer::RenderTargetType type)
FlutterEngineDartObjectType type
Definition: embedder.h:1063
FlutterBackingStoreCreateCallback create_backing_store_callback
Definition: embedder.h:933