Skip to content

[Impeller][Android] Vendor-SDK Vulkan gate from #186405 also blocks Mali-G52 (MT6768/MT6769, vendor SDK 31) where Vulkan worked on 3.44; the GLES fallback costs +40–90 MB of graphics memory — Flutter 3.47.1 #193148

Open

Description

@Daracul

Steps to reproduce

Device: any MediaTek phone whose vendor partition reports ro.vendor.build.version.sdk = 31 and
whose Vulkan driver works. Two used here:

Samsung Galaxy A13 SM-A137F Samsung Galaxy A32 SM-A325F
ro.board.platform / ro.hardware mt6768 / mt6768 mt6768
ro.soc.manufacturer / ro.soc.model Mediatek / MT6769V/CT Mediatek / MT6768 family
GPU / driver Mali-G52 MC2, OpenGL ES 3.2 v1.r32p1-01eac0 (dumpsys SurfaceFlinger), Vulkan ICD vulkan.mt6768.so, ro.hardware.egl=meow Mali-G52
Android / ro.build.version.sdk 13 / 33 13 / 33
ro.vendor.build.version.sdk 31 31
Vulkan advertised android.hardware.vulkan.version=4198400 (1.1), level=1 yes
ABI list armeabi-v7a, armeabi (32-bit ROM, 64-bit-capable SoC) 64-bit
Display / RAM 1080×2408 / 3.7 GB 1080×2400 / 4 GB
  1. flutter create repro (created with 3.44.2 so sdk: ^3.12.2 fits both SDKs). Nothing else is needed for the backend line.
  2. Build and run the same project with each SDK:
    ~/fvm/versions/3.44.2/bin/flutter build apk --release && adb install -r build/app/outputs/flutter-apk/app-release.apk
    adb logcat -c && adb shell monkey -p com.example.repro 1 && adb logcat | grep "rendering backend"
    ~/fvm/versions/3.47.1/bin/flutter build apk --release   # then the same install / logcat
    
  3. For the memory part, use the two-file variant at https://github.com/Daracul/impeller-gate-repro
    (a hidden full-screen FlutterView drawing one full-screen Clip.antiAliasWithSaveLayer) and read
    adb shell dumpsys meminfo <pkg> | grep "GL mtrack" ~20 s after launch.

Expected results

Devices that ran Impeller Vulkan without issues on 3.44 keep it on 3.47, or the gate targets the
configuration that actually failed — #186067 is MT8788 with Mali-G57 — rather than every MediaTek
device whose vendor partition happens to report SDK 31.

Concretely, any of these would keep these devices on Vulkan while still covering #186067:

  1. Key the MediaTek rule on the platform (ro.board.platform / the Vulkan ICD name, vulkan.mt8788.so
    vs vulkan.mt6768.so) and deny the platforms where the gralloc bug reproduces, the way PowerVR
    B-series is handled by denylist today.
  2. Or gate on the Mali driver release (r32p1 here) through the existing known-bad-driver path for
    Vulkan, instead of on the vendor partition's SDK number.
  3. Keep ro.vendor.build.version.sdk only as a fallback when neither the platform nor the driver is
    recognised.

ro.vendor.build.version.sdk is a proxy for driver vintage, and a coarse one: it cannot tell
Mali-G52 on MT6768 with a working r32p1 driver from Mali-G57 on MT8788 with the gralloc bug.

Actual results

The backend flips with the SDK, nothing else changed:

SDK engine logcat
3.44.2 77e2e94772b6eb43759e34ed1ad7da4674e19cab android_context_vk_impeller.cc(62) Using the Impeller rendering backend (Vulkan).
3.47.1 5d531788691ec3404cac0cee66ead4007b177363 android_context_gl_impeller.cc(104) Using the Impeller rendering backend (OpenGLES).

Deterministic on every launch; reinstalling the 3.44.2 build restores Vulkan. Nothing in the 3.47.1
logcat says why Vulkan was skipped. The literal ro.vendor.build.version.sdk is present in the
3.47.1 libflutter.so (armeabi-v7a) and absent from the 3.44.2 one.

Why: #186405 ("Bumped required mediatek vender sdk version", merged 2026-05-12, in 3.47) replaced
the API-level gate for MediaTek Vulkan with a vendor-SDK gate and raised the threshold to 32
"since the bug was reported on version 31". That bug, #186067, is a gralloc format rejection on
MT8788 / Mali-G57. Mali-G52 on MT6768/MT6769 has the same vendor SDK number but not the bug — it
ran Vulkan on 3.44 in production — and gets swept in. Samsung and many MediaTek-BSP phones rarely
rebuild the vendor partition, so on these devices ro.vendor.build.version.sdk stays at 31 through
Android 13; for them the gate is effectively permanent.

There is no app-side way around it in release: per #192467 the release-mode ImpellerBackend
restriction is intended, and the suggested route is to fix the device gating in the engine — which is
what this issue asks for.

Production impact (inDrive Android app; per-user daily median of the Graphics segment of PSS
from in-app memory telemetry (dumpsys meminfo), p50 across users, 5 days before/after the
release that moved from 3.44.2 to 3.47.1; figures are shares of the release's user base):

Device (Android) SoC / GPU vendor SDK p50 Graphics MB, 3.44.2 p50 Graphics MB, 3.47.1
Samsung A32 SM-A325F/M (13) MT6768 / Mali-G52 31 16 121 / 132
Samsung A22 SM-A225M (13) MT6769 / Mali-G52 31 10 78
Redmi 13C gale (13 / 14) MT6769 / Mali-G52 < 32 4 79 / 83
Redmi 13C gale (15) — vendor rebuilt MT6769 / Mali-G52 ≥ 32 63 65
control: Samsung A12 (PowerVR, GLES on both) MT6765 / PowerVR — 53 52
control: Redmi 10 selene MT6769 / Mali-G52 ≥ 32 11 10
control: Qualcomm Adreno ≤ 650 — — +2…+5
  • 14.3 % of the release's users are in flipped model × Android cells (Δ ≥ 30 MB); user-weighted
    mean Δ +76 MB; among affected users 28 % gained 30–60 MB, 53 % 60–100 MB, 19 % ≥ 100 MB.
  • While the app is not in the foreground: same 14.3 % share, mean +66 MB — the extra graphics
    memory is not released on backgrounding.
  • The Redmi 13C rows are the cleanest control: same phone, the Android 15 build has a rebuilt vendor
    partition (SDK ≥ 32) and shows no regression; Android 13/14 builds do.
  • Footprint scales with screen resolution, consistent with full-screen render targets.

On-device, production app, GL mtrack (MB), same account and tap path. A13:

Point Vulkan (3.44.2) GLES (3.47.1) Δ
Flutter engine created, no Flutter view attached yet 4.5 20.4 +15.9
first Flutter screen 6.9 46.0 +39.2
back on a native screen 6.9 53.7 +46.8
second Flutter screen 20.0 59.9 +39.8
backgrounded 19.5 50.4 +30.9

A32 (Graphics): cold start 22.6 → 95.8 (+71.4), Flutter screen 29.7 → 123.1 (+91.2), backgrounded
20.3 → 88.8 (+66.9). Java heap, native heap and EGL mtrack are flat; the whole delta is GL mtrack.

Stability: Crashlytics for SM-A137F over the 3.44.2-based release (Vulkan) shows no crash issues
with libflutter, Mali, Vulkan or Impeller in the title or subtitle; the same search over the
3.47.1-based release (GLES) is also empty. So on this SoC the gate removes no observed Vulkan crash —
it only removes Vulkan. (The Impeller GLES path on Mali has open crash reports of its own, e.g.
#190640 on Android 10 devices.)

Mechanism (minimal app, hidden full-screen FlutterView, GL mtrack KB):

Dart content in the hidden view 3.44.2 Vulkan 3.47.1 GLES Δ
empty Material 6640 5312 −1.3 MB
one full-screen Clip.antiAliasWithSaveLayer, persistent 17652 29076 +11.4 MB
same saveLayer for 1 s, then a static frame 17556 28564 +11.0 MB
same 1 s saveLayer, then ~300 layer-free frames 6788 10636 +3.8 MB

An empty frame is free on both backends. One offscreen pass allocates a full-screen render target,
and the numbers are consistent with its MSAA attachment being lazily allocated on Vulkan (tiler)
but fully resident on GLES. The target is held until later frames let the render-target cache evict
it (see #190613); after ~300 frames GLES was still ~5 MB above its own baseline. Destroying the
engine returns everything on both backends. This is the known cost
of the GLES backend — the point here is that the gate now imposes it on devices where Vulkan worked.

Code sample

Stock flutter create output reproduces the backend flip. The two-file variant behind the memory
table (a plain Activity attaching a covered full-screen FlutterView(FlutterTextureView), and a
main.dart with one full-screen saveLayer) is at https://github.com/Daracul/impeller-gate-repro.

lib/main.dart (core)
class ReproApp extends StatelessWidget {
  const ReproApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ClipRRect(
        clipBehavior: Clip.antiAliasWithSaveLayer, // one offscreen pass per frame
        borderRadius: BorderRadius.all(Radius.circular(1)),
        child: Material(
          color: Colors.white,
          child: Stack(children: [
            Positioned.fill(child: ColoredBox(color: Colors.indigo)),
            Positioned(left: 40, top: 40, right: 40, bottom: 40,
                child: ColoredBox(color: Colors.orange)),
          ]),
        ),
      ),
    );
  }
}

Screenshots or Video

Not applicable — the result is the backend line in logcat and dumpsys meminfo numbers.

Logs

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

GL mtrack sampled once per second from process start of the production app on SM-A137F.
3.47.1/GLES: 6.0 MB at 3.2 s → 17.7 MB at 4.8 s → peak 22.3 MB → flat 18.9 MB; the step lands
~1 s after the backend line, before any Flutter view is attached. 3.44.2/Vulkan: flat 4.5 MB.

Related: #186405 (the gate change), #186067 (MT8788 / Mali-G57 bug it fixed), #192467
(release-mode ImpellerBackend is intended to be ignored), #193009 (Impeller GLES on MediaTek
MT6765 in 3.47.1), #190640 (GLES ImageDecoderImpeller SIGABRT on Android 10 Mali devices), #189190 (GLES crash on
MediaTek Android 13), #190613 (render-target cache / GPU memory on EGL), #190618 / #175577 (GLES
cold start slower), #192798 (MT8788 Vulkan platform-view corruption — the chip the gate was meant for).

Flutter Doctor output

[!] Flutter (Channel stable, 3.47.1, on macOS 14.8.2 23J126 darwin-arm64) [2.8s]
    • Flutter version 3.47.1 on channel stable at ~/fvm/versions/3.47.1
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 6655482ec0 (5 weeks ago), 2026-08-19 10:07:23 -0700
    • Engine revision 5d53178869
    • Dart version 3.13.1
    • 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
[!] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [4.4s]
    • Android SDK at ~/Library/Android/sdk

Activity

  1. added
    in triagePresently being triaged by the triage team
    platform-androidAndroid applications specifically
    engineflutter/engine related. See also e: labels.
    e: impellerImpeller rendering backend issues and features requests
    c: regressionIt was better in the past than it is now
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    and removed
    in triagePresently being triaged by the triage team
    on Sep 22, 2026
  2. mbcorona commented on Sep 22, 2026

    @mbcorona
    Member

    Hi @Daracul, thanks for the excellent reporting.

    Routing to team-engine for further investigation

  3. self-assigned this
    on Sep 28, 2026
  4. added
    P2Important issues not at the top of the work list
    on Sep 28, 2026
  5. gaaclarke commented on Oct 14, 2026

    @gaaclarke
    Member

    Thanks for the report.

    Stability: Crashlytics for SM-A137F over the 3.44.2-based release (Vulkan) shows no crash issues
    with libflutter, Mali, Vulkan or Impeller in the title or subtitle; the same search over the
    3.47.1-based release (GLES) is also empty. So on this SoC the gate removes no observed Vulkan crash —
    it only removes Vulkan. (The Impeller GLES path on Mali has open crash reports of its own, e.g.
    #190640 on Android 10 devices.)

    #186067 wasn't a crash, it was a visual glitch. One app running successfully with vulkan doesn't mean all vulkan apps will render successfully. We have to choose based off of all the things a user could do (platform views, external textures, etc.).

    We're open to broadening the gate if you can provide testing for the A13 and A32 on 3.44.2. Run the following tests:

    cd ~/fvm/versions/3.44.2/dev/integration_tests/android_engine_test
    flutter run lib/external_texture/surface_producer_smiley_face_main.dart
    flutter run lib/platform_view/texture_layer_hybrid_composition_platform_view_main.dart
    

    The first should show a full-screen smiley face on a yellow background. The second should show a blue/orange gradient, and it should still look right after you background and resume the app. Please include the Using the Impeller rendering backend line from logcat to confirm it ran on Vulkan, and attach screenshots.

  6. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Oct 14, 2026
  7. M0n7y5 commented on Oct 19, 2026

    @M0n7y5
    Contributor

    Second device, same symptom: Redmi Note 12 Pro 5G (MT6877, Mali-G68 MC4, Android 14, vendor SDK 31).

    Redmi Note 12 Pro 5G
    SoC MediaTek Dimensity 1080 (MT6877)
    GPU Mali-G68 MC4
    Android / vendor SDK 14 (API 34) / 31
    Vulkan driver 1.1.177, v1.r32p1-01eac0
    LAZILY_ALLOCATED yes
    GLES MSRTT yes (_texture and _texture2)

    On 3.47.7, an engine patched to log each fallback branch shows the MediaTek vendor-SDK gate firing: MediaTek vendor API level 31 is below 32 (ro.vendor.mediatek.platform=MT6877), falling back to OpenGLES. (android_context_dynamic_impeller.cc(116)).

    3.44.2 android_engine_test (smiley and gradient apps, profile), backend line for both apps:

    as shipped (ImpellerBackend=vulkan):  Using the Impeller rendering backend (Vulkan).
    default (meta-data removed):          Using the Impeller rendering backend (Vulkan).
    

    Default selection picks Vulkan on 3.44.2 because its MediaTek gate compares the device API level (34) against 31, not the vendor SDK.
    Both apps render correctly, with 0 px diff after resume and no crash. Screenshots below are from the default build. The forced (meta-data) and default screenshots are byte-identical, so only the default ones are attached.

    Screenshots (default build): smiley at 10 s, gradient at 10 s, gradient after background and resume.

    Forced Vulkan on 3.47.7 renders correctly, with raster p50 of Skia 1.59 / GLES 5.35 / Vulkan 3.74 ms.

    Caveat: Vulkan logs the #186067 gralloc rejection as 4 failed 4x4 R8/R10G10B10A10 probes at startup and once per resume, never continuously. It causes no visible defect (pixel diff vs GLES max 1/255).

    Could the gate key on the Mali driver range (r26p0 in #186067 vs r32p1 here) or the platform instead of the vendor SDK? As written it applies to every MediaTek device regardless of GPU.

    Raw artifacts (logcat, vkjson, Perfetto traces) are available on request.

    This comment was prepared with AI assistance.

    Image Image Image
  8. Daracul commented on Oct 20, 2026

    @Daracul
    Author

    Thanks — ran both tests on two devices on Flutter 3.44.2 (engine 77e2e94), debug builds of dev/integration_tests/android_engine_test from the SDK (--target-platform android-arm for the A13's 32-bit ROM, android-arm64 for the A32).

    Devices:

    • Galaxy A13 SM-A137F — MediaTek MT6769V/CT (ro.board.platform / ro.hardware = mt6768), Mali-G52 MC2, GLES driver OpenGL ES 3.2 v1.r32p1-01eac0, Vulkan ICD vulkan.mt6768.so, Android 13 (API 33), ro.vendor.build.version.sdk = 31.
    • Galaxy A32 SM-A325F — MediaTek MT6769V/CT (ro.board.platform = mt6768, ro.hardware = mt6769t), Mali-G52 MC2, GLES driver OpenGL ES 3.2 v1.r26p0-01eac0 (the same r26p0 driver generation as the #186067 device), Vulkan ICD vulkan.mt6768.so, Android 13 (API 33), ro.vendor.build.version.sdk = 31.

    All four runs log:

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

    1. lib/external_texture/surface_producer_smiley_face_main.dart — full-screen smiley on yellow on both devices, unchanged after 14 s.

    A13 / A32:

    A13 smiley A32 smiley

    2. lib/platform_view/texture_layer_hybrid_composition_platform_view_main.dart — blue/orange gradient with the Flutter overlay on both devices; after HOME and resume the frame is pixel-identical to the launch screenshot (same PNG hash). For completeness: on both devices the test's green box under the platform view is visible for ~60–100 ms (2–4 recorded frames) before the first platform-view frame lands; a build with ImpellerBackend=opengles on the A32 shows the same, so it is the texture-layer handoff, not backend-specific.

    A13, launch / after background + resume:

    A13 platform view at launch A13 platform view after resume

    A32, launch / after background + resume:

    A32 platform view at launch A32 platform view after resume

    A32 screen recording (launch → background → resume):

    a32-platform-view-launch-background-resume.mp4

    No E/flutter lines in any run.

    One observation that may help with the gate decision: both devices log the same gralloc lines that #186067 shows at startup (Unrecognized and/or unsupported format 0x38 and usage 0xb00, isSupported(1, 1, 56, 1, ...) failed with 5, Failed to allocate (4 x 4) ... format 56 usage b00). As far as I can tell they come from Android's libvulkan (GetPhysicalDeviceSurfaceFormatsKHR probes AHARDWAREBUFFER_FORMAT_R8_UNORM as a swapchain format; usage 0xb00 = COMPOSER_OVERLAY | GPU_SAMPLED_IMAGE | GPU_FRAMEBUFFER), this gralloc rejects R8 and libvulkan leaves it out of the list, while Impeller requests RGBA8 for its swapchain. On these two devices rendering is correct with those lines present, so they may not be a reliable signal of a broken Vulkan path by themselves. The defect reported in #186067 was in WebRTC video output, which these two tests do not cover — if there is a test for that path, I am happy to run it on both devices.

    Together with @M0n7y5's Redmi Note 12 Pro 5G above (MT6877, Mali-G68 MC4, driver r32p1) this covers three MediaTek Mali devices with vendor SDK 31 — Mali-G52 on both driver generations (r26p0 and r32p1) and Mali-G68 — all rendering both tests correctly on Vulkan. The A32 result also narrows the options from the issue description: it runs the same r26p0 driver generation as the #186067 device and renders correctly, so the driver release alone does not separate the two cases. Keying the gate on the platform (ro.board.platform / Vulkan ICD name, mt8788 vs mt6768), or on GPU model plus driver release through the existing known-bad-driver path (Mali-G57 r26p0), would cover #186067 without sweeping in these devices.

    Full logcat of each run is available on request.

  9. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listc: regressionIt was better in the past than it is nowe: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.found in release: 3.44Found to occur in 3.44found in release: 3.47Found to occur in 3.47has 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