Repository navigation
Description
Steps to reproduce
- Run any Flutter app with animations, gradients, box shadows and ClipRRect
on a device with Adreno 506 GPU (e.g. Xiaomi Redmi 5 Plus, Android 8.1) - Profile with Flutter DevTools in --profile mode
- Observe FPS and frame times
- Add
io.flutter.embedding.android.EnableImpeller = falseto AndroidManifest.xml - Profile again and compare
Expected results
Impeller should perform at least as well as Skia on older Adreno GPUs.
Actual results
With Impeller enabled: ~28 FPS average. Flutter DevTools shows Build 34ms
and Layout 60ms per frame — consistent jank across all screens.
With Impeller disabled (Skia): ~54 FPS average. Build ~2ms, Layout ~1ms.
Only expected shader compilation spikes on first render.
The opt-out via AndroidManifest.xml restores acceptable performance,
but this opt-out is being deprecated.
Code sample
No minimal reproduction needed — the issue is reproducible on any
Flutter app with standard Material widgets on the affected hardware.
Device: Xiaomi Redmi 5 Plus / Snapdragon 625 / Adreno 506 / Android 8.1
Screenshots or Video
Logs
Logs
[Paste your logs here]Flutter Doctor output
[√] Flutter (Channel stable, 3.41.9, on Microsoft Windows [Versione 10.0.19045.6466], locale it-IT) [320ms]
• Flutter version 3.41.9 on channel stable at C:\src\flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 00b0c91 (3 weeks ago), 2026-04-29 10:03:19 -0700
• Engine revision 42d3d75
• Dart version 3.11.5
• DevTools version 2.54.2
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets,
omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration
[√] Windows Version (10 Pro 64 bit, 22H2, 2009) [1.624ms]
[√] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [2,7s]
• Android SDK at C:\Users\Andrea\AppData\Local\Android\sdk
• Emulator version 36.2.11.0 (build_id 14212360) (CL:N/A)
• Platform android-37.0, build-tools 36.1.0
• Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: flutter config --jdk-dir="path/to/jdk".
• Java version OpenJDK Runtime Environment (build 21.0.8+-14018985-b1038.68)
• All Android licenses accepted.
[√] Chrome - develop for the web [11ms]
• Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
[X] Visual Studio - develop Windows apps [9ms]
X Visual Studio not installed; this is necessary to develop Windows apps.
Download at https://visualstudio.microsoft.com/downloads/.
Please install the "Desktop development with C++" workload, including all of its default components
[√] Connected device (4 available) [270ms]
• RMX3867 (mobile) • DMKRIVQKEYMJP7SO • android-arm64 • Android 16 (API 36)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Versione 10.0.19045.6466]
• Chrome (web) • chrome • web-javascript • Google Chrome 148.0.7778.179
• Edge (web) • edge • web-javascript • Microsoft Edge 148.0.3967.70
[√] Network resources [650ms]
• All expected network resources are available.


Activity
puneetkukreja98 commentedon May 25, 2026
@andrea75 Thanks for reporting the issue! Could you please try updating to the latest stable version (3.44.0) and check if the issue still persists? Also, if it does, is this performance regression something you only started noticing on this specific version (3.41.9), or did it occur on older versions as well?
Similar issues:
#162312
#180958
#169423
andrea75 commentedon May 25, 2026
@puneetkukreja98 thank you for your answer.
Tested on Flutter 3.44.0 — issue persists.
Device: Xiaomi Redmi 5 Plus (Adreno 506, Android 8.1)
With Impeller enabled (opt-out removed):
32 FPS average, both idle and during scroll
100% of frames flagged as jank during scroll
Build phase reaching 35ms on idle frames
Repeated FlutterImageDecoderImplDefault: invalid input errors (image decode failures)
With io.flutter.embedding.android.EnableImpeller = false:
~54 FPS, smooth scroll, no jank
The runtime GPU blocklist from #160041 does not appear to cover the Adreno 506 in Flutter 3.44.0. The manual opt-out remains necessary.
puneetkukreja98 commentedon May 26, 2026
Routing this to team-engine for further investigation.
gaaclarke commentedon Jun 1, 2026
Are these devices using the vulkan or opengles backend? Did you attempt to bisect the issue a bit to see if there was a regression at some point in the performance?
andrea75 commentedon Jun 1, 2026
Test results on Flutter 3.44.0:
→ 31 FPS average, UI Jank + Raster Jank detected, Build phase 34.8 ms
→ 55 FPS average, no jank, clean frames
The issue is not Vulkan-specific — OpenGL ES backend also causes significant performance degradation on this device. Impeller itself (regardless of backend) appears to be the regression source on Adreno 506 with Flutter 3.44.0.
We did not bisect across intermediate versions (3.42.x / 3.43.x) — let us know if that would be useful and we'll try.
gaaclarke commentedon Jun 1, 2026
Yes, trying a few versions of flutter would be helpful. If it's a regression it's much more actionable.
gaaclarke commentedon Jun 1, 2026
@andrea75 can you verify that this is the case for the default counter app too with flutter? I wonder if you are measuring an app with platform views.
andrea75 commentedon Jun 2, 2026
The measurement was taken on the main screen with no WebViews / platform views active — only standard Flutter widgets. So platform views are not the cause.
We'll verify with the default counter app and report back. We'll also try to bisect across 3.42.x / 3.43.x to narrow down the regression.
MostafaAlyy commentedon Sep 2, 2026
Adding lab and field data for the same class of device (Adreno 610), with answers to the three questions above and a per-primitive attribution.
Backend: OpenGL ES. Adreno 610 is on the Vulkan denylist (
driver_info_vk.cc, Adreno ≤ 650), so logcat printsUsing the Impeller rendering backend (Vulkan)immediately followed by… (OpenGLES). Every number below is Impeller GLES vs Skia GL on the same GPU and driver (Adreno (TM) 610, OpenGL ES 3.2 [email protected], vivo V2424, Android 16, 120 Hz panel).Not platform views. Everything below is a plain
ListView.builderof 40 Material cards — no platform view, no texture, no image decoding.Not a version regression as far as we can tell. We did not bisect; our field numbers were flat across three months of releases, and the only thing that moved them was switching the renderer.
Minimal repro
https://github.com/MostafaAlyy/impeller_gles_repro — 40 cards, decorations toggled with
--dart-define=SCENE=plain|shadow|gradient|opacity|blur|shader|all.plainis a roundedContainer+ border + twoTexts +LinearProgressIndicator+ a gradient thumbnail;shadowadds three offsetBoxShadows (blur 8/16/24);gradientaLinearGradientfill;opacityanOpacity(0.92)wrapper;shaderaShaderMask;bluraBackdropFilter(blur 12)on every 4th card. The list flings itself end-to-end forever;FrameTimings are aggregated per 3 s window and printed to logcat. Flutter 3.47.2 stable, engine a804b26.measure.shin the repo runs the whole matrix;RESULTS-all.tsvhas every row.Release mode, vivo V2424 (Adreno 610)
p50 frame / p50 raster / share of frames over 16.7 ms:
Per-primitive attribution (profile mode, same device)
The Dart VM timeline (Embedder stream) separates two costs:
A flat scene is CPU-bound in GL command encoding.
plainunder Impeller GLES is a single render pass per frame, butRenderPassGLES::EncodeCommandsInReactortakes 6.5 ms of raster-thread time per frame (SurfaceFrame::Encode8.5 ms,GPURasterizer::Drawp50 10.4 ms), andtop -Hshows the raster thread at ~45 % of a core. Skia on the same scene:GrDirectContext::flushAndSubmit1.6 ms,Draw3.9 ms, raster thread ~18 %. Readingrender_pass_gles.cc,buffer_bindings_gles.ccandsampler_gles.cc, every command re-issues its full state; only the viewport, cull mode and winding are checked for redundancy. Per draw that isBlendFuncSeparate+ enable/disable,StencilFuncSeparate/StencilOpSeparateper face, depth enable +DepthFunc+DepthMask,Scissor, per attributeEnableVertexAttribArray+VertexAttribPointer+VertexAttribDivisor, an unconditionalUseProgram, the y-flipUniform1fv,BindBufferRangeper UBO, and per textureActiveTexture+BindTexture+ four to sixTexParameteri(no sampler objects) +Uniform1i— roughly 25–35 GL calls per draw. Skia'sGrGLGpustate cache and op batching avoid most of those on the same driver.Blur is GPU-bound on pass count. Five
BackdropFilters make the frame 9.35 render passes (EncodeCommandsInReactorcount per frame). Encoding is only 5.3 ms, butSurfaceFrame::Submitis 25.5 ms — about 18 ms per frame blocked in swap waiting for the GPU.allstacks both: 15.8 passes per frame, 12.7 ms of encoding, 38.7 msDraw.A note for anyone measuring this:
impeller_debugis on in profile engines (impeller/tools/args.gni), so profile builds also pay aPushDebugGroup/PopDebugGroupper command —plainreads 20 ms in profile and 12 ms in release on this device. The release numbers above are the honest ones.Same repro on the emulator (Android 16 x86_64, host GPU Intel Arc / Mesa)
ImpellerBackend)With a desktop GPU behind the translator the encoding cost disappears (
plainties), but the blur/pass cost is still ~3.5× Skia. The forced-Vulkan column goes through the gfxstream translation layer and is not representative of a phone; it only shows why auto-select avoids it.Production app (same APK, renderer toggled via
--enable-impeller=false)Firebase Analytics across our Android fleet, per model, video-screen p50 frame before → after the switch to Skia: SM-T505N 52–69 ms → 23–28 ms, CPH2591 51 ms → 27 ms, SM-X216B (Adreno 619) 25 ms → 19 ms. We are shipping
--enable-impeller=falseon Android for now.If a per-pass GL state cache in
RenderPassGLES(skipping redundant program / blend / stencil / depth / vertex-attribute / texture-parameter calls, and sampler objects on ES 3.0) is a direction the team would take, I'm happy to put a PR together — we have the Adreno 610 devices on the desk to measure it.MostafaAlyy commentedon Sep 2, 2026
Filed the encode-cost half of this (
RenderPassGLESre-issuing all GL state per draw, raster thread CPU-bound on Adreno 610) as its own issue with the mechanism and a proposed fix: #192147. The blur/pass-count half stays with #169423.andrea75 commentedon Sep 2, 2026
Thanks to @MostafaAlyy for the detailed analysis on Adreno 610 (same GPU family, same symptoms). The root cause they identified — RenderPassGLES re-issuing all GL state per draw — matches our observations on Adreno 506 exactly.
Tracking the proposed fix in #192147.