From 81e404d4cb05cb9508b4c950e8d6e13058328d14 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Mon, 3 Aug 2026 14:26:10 -0700 Subject: [PATCH 1/3] Fix incorrect Android platform view technical details Mostly a follow-up to #13356, which introduced several inaccuracies on the Hosting native Android views page. The compositing description in the hybrid composition section predates that PR. - Thread merging: hybrid composition merges the raster thread into the platform thread, not "the raster and UI threads". The UI thread (which runs Dart) and the platform thread (the Android main thread) are distinct, so describing them as "the UI/platform thread" was also wrong. See AndroidExternalViewEmbedder::PostPrerollAction, where the raster tasks end up handled on the platform thread. This also brings back the detail, lost when platform-view-perf.md was inlined, that the cost is rasterization competing with other platform thread work. - Compositing under hybrid composition: the page claimed Flutter content goes into a texture that SurfaceFlinger then composes with the platform views. It actually goes into ImageReaders painted by FlutterImageViews, which live in the same window as the platform views, so the Android view hierarchy composites them. SurfaceFlinger only composites whole windows. Describe both layer kinds, since they behave differently. The main render surface is swapped for a background FlutterImageView by FlutterView.convertToImageView once a platform view is added, while content drawn above a platform view goes into overlay layers (PlatformOverlayView) that SurfacePool allocates and recycles per frame. SurfaceFlinger compositing is instead what distinguishes HCPP, which drives real SurfaceControl layers by way of PlatformViewsController2. Attributing it to hybrid composition erased that distinction. - Implementation matrix: the pipeline listed under hybrid composition ("renders to texture -> uploads to Impeller -> Impeller composites") actually describes texture layer, so it moves to the texture layer row, and hybrid composition gets the pipeline described above. - HCPP requirements: Vulkan is not required for Impeller. Impeller has an OpenGLES backend and falls back to it when Vulkan is unusable (emulators, known bad SoCs, and so on). The real constraint is the reverse: HCPP requires the Vulkan backend specifically, as gated by PlatformViewAndroid::IsSurfaceControlEnabled. --- .../android/platform-views.md | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/sites/docs/src/content/platform-integration/android/platform-views.md b/sites/docs/src/content/platform-integration/android/platform-views.md index 7a75c6094f..dfd68e6067 100644 --- a/sites/docs/src/content/platform-integration/android/platform-views.md +++ b/sites/docs/src/content/platform-integration/android/platform-views.md @@ -37,8 +37,8 @@ The following matrix summarizes the different implementations and their trade-of | Mode | Benefits | Considerations | Enabler | | :--- | :--- | :--- | :--- | -| **Texture layer** | • Good Flutter performance
• Full widget transforms work | • Janky during quick scrolling
• SurfaceViews lose accessibility and text magnifier breaks | Default behavior or standard `AndroidView` | -| **Hybrid composition** | • Full native fidelity
• Correct accessibility and SurfaceView support | • Causes thread merging of raster & platform, which degrades Flutter FPS
• Platform View -> Renders to texture -> Uploads to Impeller -> Impeller composites Flutter content and Platform View content |• `PlatformViewLink` with `AndroidViewSurface`
• [`AndroidViewController` builds either a TLHC or an HC Platform View][AC] | +| **Texture layer** | • Good Flutter performance
• Full widget transforms work | • Janky during quick scrolling
• SurfaceViews lose accessibility and text magnifier breaks
• Platform View -> Renders to texture -> Uploads to Impeller -> Impeller composites Flutter content and Platform View content | Default behavior or standard `AndroidView` | +| **Hybrid composition** | • Full native fidelity
• Correct accessibility and SurfaceView support | • Causes thread merging of raster & platform, which degrades Flutter FPS
• Platform View -> Renders into the Android view hierarchy as usual, Flutter content renders into `ImageReader`-backed `FlutterImageView`s (a background layer, plus an overlay layer for content drawn above a platform view), the Android view hierarchy composites them together |• `PlatformViewLink` with `AndroidViewSurface`
• [`AndroidViewController` builds either a TLHC or an HC Platform View][AC] | | **HCPP** (Experimental) | • Full fidelity and performance
• Solves original sync overhead | • Requires Android API 34+, Vulkan support, and use of the Impeller rendering engine
• Platform View -> Renders to native Android Surface, Impeller renders to native Android Surface, SurfaceFlinger composites the two together | • `` in `AndroidManifest.xml`
• `--enable-hcpp` local flag
•[`AndroidViewController` builds either a TLHC or an HC Platform View][AC] | {:.table .table-striped} @@ -47,9 +47,18 @@ The following matrix summarizes the different implementations and their trade-of ## Hybrid composition {: #hybrid-composition } -Platform Views are rendered as they are normally. -Flutter content is rendered into a texture. -SurfaceFlinger composes the Flutter content and the platform views. +Platform views are rendered as they normally are, +directly in the Android view hierarchy. +Flutter content is rendered into `ImageReader`s and painted by +`FlutterImageView`s that sit in the same window as the platform views, +so the Android view hierarchy composites them together. + +Flutter uses two kinds of these layers. +The main Flutter render surface is swapped for a background +`FlutterImageView` once a platform view is added. +Flutter content that draws on top of a platform view +goes into an additional overlay `FlutterImageView`, +allocated from a pool and recycled between frames. ## Hybrid composition++ (HCPP) {: #hcpp } @@ -66,8 +75,10 @@ It is currently available as an opt-in feature. * **Android API 34 or later**: Required for native transaction synchronization capabilities. -* **Vulkan rendering**: The device must be capable of rendering with Vulkan. - Required for Impeller to be enabled. +* **Impeller with the Vulkan backend**: The device must be capable of + rendering with Vulkan. Impeller also has an OpenGLES backend, and + falls back to it on devices without usable Vulkan support. + HCPP isn't available in that configuration. If these requirements are not met on the end-user device, Flutter will automatically fall back to the existing platform view strategy @@ -516,15 +527,21 @@ Check out the [existing Platform View issues][] on GitHub. Platform views in Flutter come with performance trade-offs. In a typical Flutter app, -the Flutter UI is composed on a dedicated raster thread, -while platform code runs on the UI/platform thread. -This separation keeps Flutter rendering fast and fluid. - -However, when a platform view is rendered on Android using hybrid -composition, Flutter merges the raster and UI threads into a single thread to -ensure correct synchronization between the native Android views and the Flutter canvas. -Because of this thread merging, rendering complex Flutter widgets -alongside a platform view can compete with OS messages and plugin interactions, +Flutter rasterizes frames on a dedicated raster thread, +while platform code, such as plugins and Android views, +runs on the platform thread, which is the Android main thread. +This separation keeps Flutter rendering fast and fluid, +as the platform thread is rarely blocked by rasterization work. + +However, when a platform view is rendered on Android using +hybrid composition, +Flutter merges the raster thread into the platform thread +to ensure correct synchronization between +the native Android views and the Flutter canvas. +Because of this thread merging, +rasterizing complex Flutter widgets alongside a platform view +competes with other work on the platform thread, +such as OS messages and plugin interactions, potentially causing lower application FPS and frame drops. Also, prior to Android 10, hybrid composition copied each Flutter frame From be6d2d4e4159c037c506c82f6545473b4f2599a5 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:22:56 -0700 Subject: [PATCH 2/3] Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../src/content/platform-integration/android/platform-views.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sites/docs/src/content/platform-integration/android/platform-views.md b/sites/docs/src/content/platform-integration/android/platform-views.md index dfd68e6067..08fc74b83e 100644 --- a/sites/docs/src/content/platform-integration/android/platform-views.md +++ b/sites/docs/src/content/platform-integration/android/platform-views.md @@ -531,7 +531,7 @@ Flutter rasterizes frames on a dedicated raster thread, while platform code, such as plugins and Android views, runs on the platform thread, which is the Android main thread. This separation keeps Flutter rendering fast and fluid, -as the platform thread is rarely blocked by rasterization work. +as the platform thread is not blocked by rasterization work. However, when a platform view is rendered on Android using hybrid composition, From 6a0a8cc431327e9a219be0692c2eb8c3520351ea Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:23:04 -0700 Subject: [PATCH 3/3] Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../src/content/platform-integration/android/platform-views.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sites/docs/src/content/platform-integration/android/platform-views.md b/sites/docs/src/content/platform-integration/android/platform-views.md index 08fc74b83e..a86de18406 100644 --- a/sites/docs/src/content/platform-integration/android/platform-views.md +++ b/sites/docs/src/content/platform-integration/android/platform-views.md @@ -78,7 +78,7 @@ It is currently available as an opt-in feature. * **Impeller with the Vulkan backend**: The device must be capable of rendering with Vulkan. Impeller also has an OpenGLES backend, and falls back to it on devices without usable Vulkan support. - HCPP isn't available in that configuration. + HCPP is not available in that configuration. If these requirements are not met on the end-user device, Flutter will automatically fall back to the existing platform view strategy