Skip to content

[Android] ImpellerBackend / --impeller-backend is ignored in release builds #192467

Open

Description

@midorinokaze

Steps to reproduce

  1. flutter create bug
  2. Add this to android/app/src/main/AndroidManifest.xml, inside <application>:
<meta-data android:name="io.flutter.embedding.android.ImpellerBackend"
           android:value="opengles"/>
  1. flutter build apk --debug, install, run. The engine logs:
    Using the Impeller rendering backend (OpenGLES).
  2. flutter build apk --release, install, run the same source.

Nothing has to be tapped: the engine prints the backend it picked.

Expected results

The release build uses the OpenGLES backend, as the debug build does.

Actual results

The release build uses Vulkan. Same device, same manifest, same source:

debug:   I flutter : [IMPORTANT:flutter/shell/platform/android/android_context_gl_impeller.cc(104)] Using the Impeller rendering backend (OpenGLES).
release: I flutter : [IMPORTANT:flutter/shell/platform/android/android_context_vk_impeller.cc(62)] Using the Impeller rendering backend (Vulkan).

Passing the switch through the embedder instead of the manifest behaves the
same way. Overriding FlutterActivity.getFlutterShellArgs() and adding
--impeller-backend=opengles is honoured in debug and ignored in release,
even though the argument demonstrably reaches the engine - this is from a
release build, logging what the override returns:

I MyApp   : shell args: --impeller-backend=opengles
I flutter : [IMPORTANT:...android_context_vk_impeller.cc(62)] Using the Impeller rendering backend (Vulkan).

The Java side does not appear to drop it: in FlutterEngineFlags,
IMPELLER_BACKEND is constructed with allowedInRelease = true (verified by
disassembling flutter.jar from the 3.47.2 artifacts).

docs.flutter.dev/perf/impeller does say backend selection "will only work in
debug and profile runtime modes", so this may be intended. If so, please
consider allowing it in release. On a Mali-G57 device, reading back a
3840x2160 offscreen picture (Picture.toImage() then toByteData()) takes
5682-6055 ms on Vulkan and 48-163 ms on OpenGLES - the same work, 40-120x
apart. On an Adreno 740 the two backends are indistinguishable (25-56 ms vs
23-58 ms), so choosing OpenGLES costs nothing there. Today the only
release-time escape is EnableImpeller=false, which is deprecated, so the
workaround for that is scheduled to disappear.

Code sample

Code sample
// Minimal reproduction: the ImpellerBackend manifest entry (and the same
// switch passed through getFlutterShellArgs) is honoured in debug but ignored
// in release.
//
// The app's content is irrelevant - the engine itself logs which backend it
// picked, so nothing has to be tapped. Build this in debug and then in
// release with the same AndroidManifest.xml entry, and compare the log line.

import 'package:flutter/material.dart';

void main() => runApp(
      const MaterialApp(
        home: Scaffold(
          body: Center(child: Text('Impeller backend probe')),
        ),
      ),
    );

Screenshots or Video

Screenshots / Video demonstration

Not applicable - the symptom is a log line.

Logs

Logs

See "Actual results" above.

Flutter Doctor output

Doctor output

Note on the channel: flutter doctor reports [user-branch], but this
checkout is exactly the 3.47.2 tag - revision
d3b14c876900e553bc736ca19295fc09e3853e8e matches refs/tags/3.47.2.
It is stable 3.47.2, not a custom branch.

[!] Flutter (Channel [user-branch], 3.47.2, on Microsoft Windows [Version 10.0.26200.9168], locale ja-JP) [971ms]
    ! Flutter version 3.47.2 on channel [user-branch] at C:\Users\<user>\develop\flutter
      Currently on an unknown channel. Run `flutter channel` to switch to an official channel.
      If that doesn't fix the issue, try deleting the 'bin/cache/flutter.version.json' file in your Flutter SDK directory and then reinstall Flutter by following instructions at https://flutter.dev/setup.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision d3b14c8769 (13 days ago), 2026-08-26 16:07:51 -0700
    • Engine revision a804b26164
    • Dart version 3.13.2
    • DevTools version 2.60.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, enable-record-use, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration, enable-riscv64
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Windows Version (11 Pro 64-bit, 25H2, 2009) [3.9s]

[!] Android toolchain - develop for Android devices (Android SDK version 37.0.0) [1,845ms]
    • Android SDK at C:\Users\<user>\AppData\Local\Android\Sdk
    • Emulator version unknown
    • Platform android-37.0, build-tools 37.0.0
    • ANDROID_HOME = C:\Users\<user>\AppData\Local\Android\Sdk
    • Java binary at: C:\Users\<user>\AppData\Local\Programs\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 25.0.3+-15898627-b508.16)
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/to/windows-android-setup for more details.

[✓] Chrome - develop for the web [956ms]
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[✓] Visual Studio - develop Windows apps (Visual Studio Community 2026 18.9.3) [952ms]
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\18\Community
    • Visual Studio Community 2026 version 18.9.12128.139
    • Windows 10 SDK version 10.0.26100.0

[✓] Connected device (5 available) [2.8s]
    • SC 51D (mobile)   • RFCW31LYZJY • android-arm64  • Android 16 (API 36)
    • SM A253C (mobile) • RFGL63FS5GF • android-arm64  • Android 16 (API 36)
    • Windows (desktop) • windows     • windows-x64    • Microsoft Windows [Version 10.0.26200.9168]
    • Chrome (web)      • chrome      • web-javascript • Google Chrome 152.0.7977.76
    • Edge (web)        • edge        • web-javascript • Microsoft Edge 152.0.4191.66
    ! Device emulator-5562 is offline.

[✓] Network resources [1,562ms]
    • All expected network resources are available.

! Doctor found issues in 2 categories.

Activity

  1. saurabh-mirajkar commented on Sep 9, 2026

    @saurabh-mirajkar
    Contributor

    @midorinokaze Thanks for report. I was able to reproduce this on both latest stable and current master on a Pixel 6(Android 17). Labelling for further investigation.

    stable
    Flutter 3.47.2 • channel stable • https://github.com/flutter/flutter.git
    Framework • revision d3b14c8769 (13 days ago) • 2026-08-26 16:07:51 -0700
    Engine • hash 1cf1c4773fb941c4c74a7f8bb144a8837596c0f4 (revision a804b26164) (13 days ago) • 2026-08-26 18:46:13.000Z
    Tools • Dart 3.13.2 • DevTools 2.60.0
    master
    Flutter 3.48.0-1.0.pre-675 • channel master • https://github.com/saurabh-mirajkar/flutter.git
    Framework • revision 0056d8b88d (5 hours ago) • 2026-09-09 04:17:26 +0000
    Engine • hash f3617fcddba73c5e94d41b81c527ce2fcb801996 (revision 0056d8b88d) (4 hours ago) • 2026-09-09 04:17:26.000Z
    Tools • Dart 3.14.0 (build 3.14.0-206.0.dev) • DevTools 2.61.0-dev.0
  2. added
    platform-androidAndroid applications specifically
    engineflutter/engine related. See also e: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    e: impellerImpeller rendering backend issues and features requests
    and removed
    in triagePresently being triaged by the triage team
    on Sep 9, 2026
  3. gaaclarke commented on Sep 14, 2026

    @gaaclarke
    Member

    This is working as intended. If this is a problem with a vulkan driver we should implement a workaround or block that device from using vulkan. Can you provide the information on the device you are having a problem with?

    adb shell cat /system/build.prop

    and/or

    adb shell getprop ro.board.platform
    adb shell getprop ro.hardware
    adb shell getprop ro.soc.model
    

    I think those properties are what we'd need to block those devices.

  4. added
    P2Important issues not at the top of the work list
    on Sep 14, 2026
  5. midorinokaze commented on Sep 15, 2026

    @midorinokaze
    Author

    Thanks - understood that the release-mode restriction is intended.

    The device where Vulkan is a problem is a Samsung Galaxy A25 5G (SM-A253C),
    Mali-G57 MC2, Android 16:

    ro.product.model         = SM-A253C
    ro.product.device        = a25ex
    ro.board.platform        = mt6835
    ro.hardware              = mt6835
    ro.soc.manufacturer      = Mediatek
    ro.soc.model             = MT6835
    ro.hardware.egl          = meow
    ro.hardware.vulkan       = mali
    ro.build.version.release = 16 (SDK 36)
    ro.build.fingerprint     = samsung/a25exrkt/a25ex:16/BP4A.251205.006/A253CONS1BZG1_QKT1BZG1:user/release-keys
    GLES (SurfaceFlinger)    = ARM, Mali-G57 MC2, OpenGL ES 3.2 v1.r38p1
    Vulkan (cmd gpu vkjson)  = deviceName "Mali-G57 MC2", vendorID 0x13B5, deviceID 0x90930010,
                               driverInfo "v1.r38p1-01eac0.51dbefa0fd07f79a7a6805f21ef15c50",
                               driverVersion 159387648, apiVersion 1.3.219
    

    /system/build.prop is not readable on this device (Permission denied,
    stock Samsung firmware); the values above are from getprop. Happy to paste
    the full getprop dump if it helps.

    What goes wrong on it: reading back a large offscreen picture
    (Picture.toImage(3840, 2160) followed by toByteData(rawRgba)) takes
    5682-6055 ms per image with Impeller-Vulkan and 48-163 ms with
    Impeller-OpenGLES
    , same build, same scene (debug builds, switched with the
    ImpellerBackend manifest entry). Drawing the picture itself is 91-135 ms on
    both. The readback runs on the platform thread, so the app produces no frames
    for ~6 s per image; during that window the compositor shows a stale frame
    from a previously removed route (this looks like #189767), and Choreographer
    reports Skipped 227 frames! for com.android.systemui as well.

    For comparison, on two other devices the backends behave the same:

    • Samsung SC-51D (Galaxy S23, Adreno 740): Vulkan 25-56 ms, OpenGLES 23-58 ms.
    • Sony 902SO (Adreno 508): Vulkan initialisation fails and the engine falls
      back to OpenGLES; 127-168 ms.

    One caveat on reproducing it: the ratio depends on what is drawn. The scene
    above is a few thousand stroked paths (Natural Earth coastlines and borders,
    ~82,000 points). With synthetic scenes of a few hundred stroked polylines the
    two backends are within 2x of each other on the same Mali device. If a
    standalone reproduction would help, I can put one together with the real
    data (it is public domain), but it would need a small repo rather than an
    inline sample.

  6. midorinokaze commented on Sep 15, 2026

    @midorinokaze
    Author

    Follow-up with two more devices, all three measured with the same harness
    (debug builds of the same app, one APK per backend, switched only through the
    ImpellerBackend manifest entry; devices run one at a time). The work is:
    draw the map picture, Picture.toImage(3840, 2160), then
    toByteData(rawRgba). Times are toImage + first readback of one 3840x2160
    image, two runs each:

    Device SoC / GPU / driver Android Vulkan OpenGLES
    Samsung SC-42A (Galaxy A21) Exynos 7884B (universal7884B) / Mali-G71 MP2 / v1.r26p0 11 16.2 s 1.26 / 1.32 s
    Samsung SM-A253C (Galaxy A25 5G) MT6835 / Mali-G57 MC2 / v1.r38p1 16 6.6 / 6.1 s 1.18 / 0.71 s
    Sony 902SO sdm660 / Adreno 508 10 (see note below) 0.56 / 0.77 s

    So the Mali-G71 device is worse than the Mali-G57 one: 16 s per image, about
    12x OpenGLES on the same device. The A21 number matches what the release
    build of the app did before I opted out of Impeller (17.1 s per 3840x2160
    band), so the debug harness is not distorting it.

    On the A21 a larger picture (7680x4320, the harness's second case) does not
    just take longer on Vulkan - the device is lost, and from then on every draw
    and readback in the process fails, including the 3840x2160 ones that had
    worked a moment earlier:

    E flutter : [ERROR:flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc(171)] Break on 'ImpellerValidationBreak' to inspect point of failure: Fence waiter encountered an unexpected error. Tearing down the waiter thread.
    E flutter : [ERROR:flutter/impeller/renderer/backend/vulkan/command_queue_vk.cc(72)] Break on 'ImpellerValidationBreak' to inspect point of failure: Failed to submit command: ErrorDeviceLost
    E flutter : [ERROR:flutter/lib/ui/painting/image_encoding_impeller.cc(225)] Failed to submit commands.
    

    OpenGLES handles the same 7680x4320 picture on that device in 1.6-1.9 s plus
    a 1.2-2.4 s readback. The A25 renders it on Vulkan in 26.8 s (OpenGLES:
    0.8-1.5 s plus 0.6-1.5 s).

    Identifiers for the A21:

    ro.product.model         = SC-42A
    ro.board.platform        = universal7884B
    ro.hardware              = exynos7884B
    ro.hardware.chipname     = exynos7884B
    ro.soc.manufacturer      = (empty on this firmware)
    ro.soc.model             = (empty on this firmware)
    ro.build.version.release = 11 (SDK 30)
    ro.build.fingerprint     = samsung/SC-42A/SC-42A:11/RP1A.200720.012/SC42AOMU1BVH1:user/release-keys
    GLES (SurfaceFlinger)    = ARM, Mali-G71, OpenGL ES 3.2 v1.r26p0-01eac0.0cdc40c87619f3e2c0bb1143755a6e8f
    Vulkan (cmd gpu vkjson)  = deviceName "Mali-G71", vendorID 0x13B5, deviceID 0x60A00002,
                               driverInfo "v1.r26p0-01eac0.0cdc40c87619f3e2c0bb1143755a6e8f",
                               driverVersion 109051904, apiVersion 1.1.131
    

    The two Mali devices are different GPU generations (G71 / G57), different SoC
    vendors (Samsung Exynos / MediaTek) and different driver branches (r26p0 /
    r38p1), and neither Adreno device shows a gap between the backends, so this
    looks Mali-wide rather than specific to one SoC.

    Side note on the Adreno 508 (Sony 902SO, sdm660, Android 10): with no
    ImpellerBackend entry the engine fails to initialise Vulkan and falls back
    to OpenGLES, which works. With ImpellerBackend=vulkan set explicitly it
    aborts at startup instead of falling back:

    F DEBUG : Abort message: '[FATAL:flutter/shell/platform/android/platform_view_android.cc(161)] Check failed: android_context_->IsValid(). Could not create surface from invalid Android context.
    

    Probably expected for an explicit request; mentioning it only for completeness.

  7. gaaclarke commented on Sep 15, 2026

    @gaaclarke
    Member

    If a
    standalone reproduction would help, I can put one together with the real
    data (it is public domain), but it would need a small repo rather than an
    inline sample.

    Based on what you are saying, it sounds like it may be a vulkan bug. It's at least evaluating it as such. Can you please provide a repro and we can take a look?

    FWIW Android 10 will be using the Skia backend not Impeller. That means the calculus for determining work to fix bugs for it has to be weighed against the fact that it is on the chopping block.

  8. midorinokaze commented on Sep 15, 2026

    @midorinokaze
    Author

    Here is a standalone reproduction:
    https://github.com/midorinokaze/impeller_mali_readback_repro

    It is a flutter create app with one asset: the already projected pixel
    coordinates and paint parameters of the map scene (Natural Earth, public
    domain; 76 draw calls, ~83,000 points, 652 KB). main.dart replays them
    into a PictureRecorder - drawRect, drawPath (even-odd fill + round-join
    stroke), drawCircle - then does toImage(3840, 2160) + toByteData(rawRgba)
    three times, once at 7680x4320, and once more at 3840x2160, printing the
    timings to the log. Nothing has to be tapped. The ImpellerBackend meta-data
    for switching to OpenGLES is in the manifest, commented out.

    Same numbers as the app (Flutter 3.47.2 stable, debug builds):

    Device SoC / GPU / driver Android Vulkan OpenGLES
    Samsung SC-42A (Galaxy A21) Exynos 7884B / Mali-G71 MP2 / r26p0 11 14.97 / 14.90 / 15.18 s; 7680x4320: ErrorDeviceLost, every later draw fails 0.79 / 0.51 / 0.47 s; 7680x4320: 3.6 s
    Samsung SM-A253C (Galaxy A25 5G) MediaTek MT6835 / Mali-G57 MC2 / r38p1 16 6.05 / 6.03 / 5.80 s; 7680x4320: 27.6 s 0.50 / 0.15 / 0.14 s; 7680x4320: 1.4 s
    Samsung SC-51D (Galaxy S23) SM8550 / Adreno 740 / [email protected] 16 0.58 / 0.23 / 0.22 s; 7680x4320: 0.63 s 0.32 / 0.18 / 0.11 s; 7680x4320: 1.2 s
    SHARP SH-RM12 (AQUOS sense3) sdm660 / Adreno 508 11 (Vulkan fails to initialise, engine falls back to OpenGLES) 0.33 / 0.31 / 0.25 s; 7680x4320: 6.1 s

    On the two Mali devices the Vulkan cost is in the first toByteData (that is
    where the picture is actually rasterised) and is 25-65x the OpenGLES time on
    the same device; on the Adreno 740 the two backends are within 2x of each
    other. The A21 log for the 7680x4320 case is in the README.

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.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-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