Skip to content

Impeller causes severe performance regression on older Adreno GPUs (e.g. Adreno 506) #187009

Open

Description

@andrea75

Steps to reproduce

  1. 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)
  2. Profile with Flutter DevTools in --profile mode
  3. Observe FPS and frame times
  4. Add io.flutter.embedding.android.EnableImpeller = false to AndroidManifest.xml
  5. 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

Screenshots / Video demonstration With Impeller enabled Image

With Impeller disabled
Image

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

  1. puneetkukreja98 commented on May 25, 2026

    @puneetkukreja98
    Contributor

    @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

  2. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    and removed
    in triagePresently being triaged by the triage team
    on May 25, 2026
  3. andrea75 commented on May 25, 2026

    @andrea75
    Author

    @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.

    Image Image
  4. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 25, 2026
  5. added
    in triagePresently being triaged by the triage team
    engineflutter/engine related. See also e: labels.
    e: impellerImpeller rendering backend issues and features requests
    platform-androidAndroid applications specifically
    and removed
    in triagePresently being triaged by the triage team
    on May 26, 2026
  6. puneetkukreja98 commented on May 26, 2026

    @puneetkukreja98
    Contributor

    Routing this to team-engine for further investigation.

  7. gaaclarke commented on Jun 1, 2026

    @gaaclarke
    Member

    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?

  8. added
    P2Important issues not at the top of the work list
    on Jun 1, 2026
  9. andrea75 commented on Jun 1, 2026

    @andrea75
    Author

    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?

    Test results on Flutter 3.44.0:

    1. Impeller + OpenGL ES (EnableImpeller=true + EnableVulkan=false)
      → 31 FPS average, UI Jank + Raster Jank detected, Build phase 34.8 ms
    Image
    1. Impeller disabled (Skia) (EnableImpeller=false)
      → 55 FPS average, no jank, clean frames
    Image

    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.

  10. gaaclarke commented on Jun 1, 2026

    @gaaclarke
    Member

    Yes, trying a few versions of flutter would be helpful. If it's a regression it's much more actionable.

  11. gaaclarke commented on Jun 1, 2026

    @gaaclarke
    Member

    @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.

  12. andrea75 commented on Jun 2, 2026

    @andrea75
    Author

    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.

  13. MostafaAlyy commented on Sep 2, 2026

    @MostafaAlyy

    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 prints Using 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.builder of 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. plain is a rounded Container + border + two Texts + LinearProgressIndicator + a gradient thumbnail; shadow adds three offset BoxShadows (blur 8/16/24); gradient a LinearGradient fill; opacity an Opacity(0.92) wrapper; shader a ShaderMask; blur a BackdropFilter(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.sh in the repo runs the whole matrix; RESULTS-all.tsv has every row.

    Release mode, vivo V2424 (Adreno 610)

    p50 frame / p50 raster / share of frames over 16.7 ms:

    Scene Impeller GLES Skia GL
    plain 12.0 ms / 8.5 ms / 10 % 6.7 ms / 3.4 ms / 0 %
    blur 46.8 ms / 28.8 ms / 99 % 12.9 ms / 8.7 ms / 34 %
    all 71.7 ms / 41.7 ms / 100 % 15.8 ms / 10.3 ms / 24 %

    Per-primitive attribution (profile mode, same device)

    Scene Impeller GLES Skia GL
    plain 20.5 / 12.5 / 54 % 5.9 / 3.0 / 0 %
    shadow 12.4 / 8.6 / 15 % 8.5 / 4.3 / 1 %
    gradient 13.5 / 9.9 / 24 % 6.6 / 3.1 / 0 %
    opacity 13.4 / 10.3 / 22 % 6.3 / 2.7 / 0 %
    shader (ShaderMask) 13.8 / 10.8 / 25 % 7.4 / 3.7 / 0 %
    blur (BackdropFilter ×5) 46.3 / 28.6 / 99 % 9.5 / 6.9 / 6 %
    all 73.2 / 41.8 / 100 % 13.3 / 9.9 / 25 %
    all + forced 30 fps repaint 69.6 / 40.8 / 100 % 31.8 / 18.2 / 100 %

    The Dart VM timeline (Embedder stream) separates two costs:

    1. A flat scene is CPU-bound in GL command encoding. plain under Impeller GLES is a single render pass per frame, but RenderPassGLES::EncodeCommandsInReactor takes 6.5 ms of raster-thread time per frame (SurfaceFrame::Encode 8.5 ms, GPURasterizer::Draw p50 10.4 ms), and top -H shows the raster thread at ~45 % of a core. Skia on the same scene: GrDirectContext::flushAndSubmit 1.6 ms, Draw 3.9 ms, raster thread ~18 %. Reading render_pass_gles.cc, buffer_bindings_gles.cc and sampler_gles.cc, every command re-issues its full state; only the viewport, cull mode and winding are checked for redundancy. Per draw that is BlendFuncSeparate + enable/disable, StencilFuncSeparate/StencilOpSeparate per face, depth enable + DepthFunc + DepthMask, Scissor, per attribute EnableVertexAttribArray + VertexAttribPointer + VertexAttribDivisor, an unconditional UseProgram, the y-flip Uniform1fv, BindBufferRange per UBO, and per texture ActiveTexture + BindTexture + four to six TexParameteri (no sampler objects) + Uniform1i — roughly 25–35 GL calls per draw. Skia's GrGLGpu state cache and op batching avoid most of those on the same driver.

    2. Blur is GPU-bound on pass count. Five BackdropFilters make the frame 9.35 render passes (EncodeCommandsInReactor count per frame). Encoding is only 5.3 ms, but SurfaceFrame::Submit is 25.5 ms — about 18 ms per frame blocked in swap waiting for the GPU. all stacks both: 15.8 passes per frame, 12.7 ms of encoding, 38.7 ms Draw.

    A note for anyone measuring this: impeller_debug is on in profile engines (impeller/tools/args.gni), so profile builds also pay a PushDebugGroup/PopDebugGroup per command — plain reads 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)

    Scene Impeller GLES Skia GL Impeller Vulkan (forced via ImpellerBackend)
    plain 5.1 / 3.7 / 0 % 5.0 / 3.5 / 0 % 47.9 / 27.5 / 98 %
    blur 16.9 / 12.1 / 46 % 4.9 / 3.5 / 0 % 85.1 / 47.0 / 99 %
    all 22.0 / 14.4 / 63 % 6.1 / 4.3 / 0 % 75.7 / 40.7 / 99 %

    With a desktop GPU behind the translator the encoding cost disappears (plain ties), 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)

    Screen Device Impeller GLES Skia GL
    Home fling, p50 frame Galaxy Tab A7 SM-T505N (Adreno 610, Android 12) 43–107 ms 8–10 ms
    Video page (texture-backed platform view) vivo V2424 86 ms (24 fps) 26 ms (59 fps)
    Same page, error state, no video vivo V2424 75 ms 13 ms

    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=false on 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.

  14. MostafaAlyy commented on Sep 2, 2026

    @MostafaAlyy

    Filed the encode-cost half of this (RenderPassGLES re-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.

  15. andrea75 commented on Sep 2, 2026

    @andrea75
    Author

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work liste: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.platform-androidAndroid applications specificallyteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions