Support multiple views in FlRenderer (#54072)

diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc
index f39e3fd..55cd0c7 100644
--- a/shell/platform/linux/fl_engine.cc
+++ b/shell/platform/linux/fl_engine.cc
@@ -207,8 +207,8 @@
 static bool compositor_present_view_callback(
     const FlutterPresentViewInfo* info) {
   g_return_val_if_fail(FL_IS_RENDERER(info->user_data), false);
-  return fl_renderer_present_layers(FL_RENDERER(info->user_data), info->layers,
-                                    info->layers_count);
+  return fl_renderer_present_layers(FL_RENDERER(info->user_data), info->view_id,
+                                    info->layers, info->layers_count);
 }
 
 // Flutter engine rendering callbacks.
diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc
index f54d129..80bdbea 100644
--- a/shell/platform/linux/fl_renderer.cc
+++ b/shell/platform/linux/fl_renderer.cc
@@ -38,7 +38,8 @@
   // Engine we are rendering.
   GWeakRef engine;
 
-  FlView* view;
+  // Views being rendered.
+  GHashTable* views;
 
   // target dimension for resizing
   int target_width;
@@ -244,6 +245,7 @@
   fl_renderer_unblock_main_thread(self);
 
   g_weak_ref_clear(&priv->engine);
+  g_clear_pointer(&priv->views, g_hash_table_unref);
   g_clear_pointer(&priv->framebuffers, g_ptr_array_unref);
 
   G_OBJECT_CLASS(fl_renderer_parent_class)->dispose(object);
@@ -256,6 +258,8 @@
 static void fl_renderer_init(FlRenderer* self) {
   FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
       fl_renderer_get_instance_private(self));
+  priv->views =
+      g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, nullptr);
   priv->framebuffers = g_ptr_array_new_with_free_func(g_object_unref);
 }
 
@@ -268,14 +272,15 @@
   g_weak_ref_init(&priv->engine, engine);
 }
 
-gboolean fl_renderer_start(FlRenderer* self, FlView* view) {
+void fl_renderer_add_view(FlRenderer* self,
+                          FlutterViewId view_id,
+                          FlView* view) {
   FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
       fl_renderer_get_instance_private(self));
 
-  g_return_val_if_fail(FL_IS_RENDERER(self), FALSE);
+  g_return_if_fail(FL_IS_RENDERER(self));
 
-  priv->view = view;
-  return TRUE;
+  g_hash_table_insert(priv->views, GINT_TO_POINTER(view_id), view);
 }
 
 void* fl_renderer_get_proc_address(FlRenderer* self, const char* name) {
@@ -370,6 +375,7 @@
 }
 
 gboolean fl_renderer_present_layers(FlRenderer* self,
+                                    FlutterViewId view_id,
                                     const FlutterLayer** layers,
                                     size_t layers_count) {
   FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
@@ -407,8 +413,10 @@
     }
   }
 
-  if (priv->view != nullptr) {
-    fl_view_redraw(priv->view);
+  FlView* view =
+      FL_VIEW(g_hash_table_lookup(priv->views, GINT_TO_POINTER(view_id)));
+  if (view != nullptr) {
+    fl_view_redraw(view);
   }
 
   return TRUE;
diff --git a/shell/platform/linux/fl_renderer.h b/shell/platform/linux/fl_renderer.h
index 6103b01..2b7d446 100644
--- a/shell/platform/linux/fl_renderer.h
+++ b/shell/platform/linux/fl_renderer.h
@@ -102,15 +102,16 @@
 void fl_renderer_set_engine(FlRenderer* renderer, FlEngine* engine);
 
 /**
- * fl_renderer_start:
+ * fl_renderer_add_view:
  * @renderer: an #FlRenderer.
+ * @view_id: the ID of the view.
  * @view: the view Flutter is renderering to.
  *
- * Start the renderer.
- *
- * Returns: %TRUE if successfully started.
+ * Add a view to render on.
  */
-gboolean fl_renderer_start(FlRenderer* renderer, FlView* view);
+void fl_renderer_add_view(FlRenderer* renderer,
+                          FlutterViewId view_id,
+                          FlView* view);
 
 /**
  * fl_renderer_get_proc_address:
@@ -189,6 +190,7 @@
 /**
  * fl_renderer_present_layers:
  * @renderer: an #FlRenderer.
+ * @view_id: view to present.
  * @layers: layers to be composited.
  * @layers_count: number of layers.
  *
@@ -198,6 +200,7 @@
  * Returns %TRUE if successful.
  */
 gboolean fl_renderer_present_layers(FlRenderer* renderer,
+                                    FlutterViewId view_id,
                                     const FlutterLayer** layers,
                                     size_t layers_count);
 
diff --git a/shell/platform/linux/fl_renderer_test.cc b/shell/platform/linux/fl_renderer_test.cc
index f38e85e..1426e4e 100644
--- a/shell/platform/linux/fl_renderer_test.cc
+++ b/shell/platform/linux/fl_renderer_test.cc
@@ -24,7 +24,7 @@
   g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
   g_autoptr(FlFramebuffer) framebuffer = fl_framebuffer_new(kWidth, kHeight);
 
-  fl_renderer_start(FL_RENDERER(renderer), view);
+  fl_renderer_add_view(FL_RENDERER(renderer), 0, view);
   fl_renderer_wait_for_frame(FL_RENDERER(renderer), kWidth, kHeight);
 
   FlutterBackingStore backing_store;
@@ -42,7 +42,7 @@
   constexpr GLuint kFakeTextureName = 123;
   glBindTexture(GL_TEXTURE_2D, kFakeTextureName);
 
-  fl_renderer_present_layers(FL_RENDERER(renderer), layers.data(),
+  fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers.data(),
                              layers.size());
   fl_renderer_render(FL_RENDERER(renderer), kWidth, kHeight);
 
@@ -97,7 +97,7 @@
                                .backing_store = &backing_store,
                                .size = {.width = 1024, .height = 1024}};
   const FlutterLayer* layers[] = {&layer0};
-  fl_renderer_present_layers(FL_RENDERER(renderer), layers, 1);
+  fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
   fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
 }
 
@@ -131,7 +131,7 @@
                                .backing_store = &backing_store,
                                .size = {.width = 1024, .height = 1024}};
   const FlutterLayer* layers[] = {&layer0};
-  fl_renderer_present_layers(FL_RENDERER(renderer), layers, 1);
+  fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
   fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
 }
 
@@ -160,7 +160,7 @@
                                .backing_store = &backing_store,
                                .size = {.width = 1024, .height = 1024}};
   const FlutterLayer* layers[] = {&layer0};
-  fl_renderer_present_layers(FL_RENDERER(renderer), layers, 1);
+  fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
   fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
 }
 
@@ -190,6 +190,6 @@
                                .backing_store = &backing_store,
                                .size = {.width = 1024, .height = 1024}};
   const FlutterLayer* layers[] = {&layer0};
-  fl_renderer_present_layers(FL_RENDERER(renderer), layers, 1);
+  fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
   fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
 }
diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc
index 18eb5e6..088de80 100644
--- a/shell/platform/linux/fl_view.cc
+++ b/shell/platform/linux/fl_view.cc
@@ -586,7 +586,7 @@
 
   init_keyboard(self);
 
-  fl_renderer_start(FL_RENDERER(self->renderer), self);
+  fl_renderer_add_view(FL_RENDERER(self->renderer), self->view_id, self);
 
   if (!fl_engine_start(self->engine, &error)) {
     g_warning("Failed to start Flutter engine: %s", error->message);