Skip to content

fix(android): defer first frame to reduce splash freeze on Xiaomi/MediaTek#1107

Closed
SERDUN wants to merge 4 commits into
developfrom
fix/impeller-splash-freeze-defer-first-frame
Closed

fix(android): defer first frame to reduce splash freeze on Xiaomi/MediaTek#1107
SERDUN wants to merge 4 commits into
developfrom
fix/impeller-splash-freeze-defer-first-frame

Conversation

@SERDUN

@SERDUN SERDUN commented Apr 12, 2026

Copy link
Copy Markdown
Member

Problem

On devices with non-standard Gralloc HALs (Xiaomi, MediaTek), the Impeller Vulkan backend probes for pixel format 0x38 (56) during engine startup:

```
E Failed to allocate (4 x 4) layerCount 1 format 56 usage b00: 5
E GraphicBuffer(w=4, h=4, lc=1) failed (Unknown error -5), handle=0x0
```

The probe fails with EINVAL and Impeller falls back to a compatible format. This fallback runs on the raster thread and races with the first vsync signal — occasionally causing a one-frame freeze on the splash screen (intermittent, device-specific).

Root cause confirmed in upstream Flutter issue: flutter/flutter#182808 (Flutter 3.41.2, Vivo/MediaTek, identical errors).

Fix

Use WidgetsBinding.deferFirstFrame() / allowFirstFrame() to hold the first Flutter frame until async bootstrap() completes. During that time (~100–500ms of Firebase/prefs init), the raster thread finishes the Impeller probe and swapchain fallback — so by the time the first frame is submitted for rasterization, Impeller is already ready.

Side effect (positive): FlutterActivity keeps the native LaunchTheme visible until allowFirstFrame() is called, making the splash-to-UI transition smoother.

Changes

  • lib/main.dart: capture binding reference, add deferFirstFrame() after ensureInitialized(), add allowFirstFrame() before runApp()

Test

Verify on a Xiaomi or MediaTek device that the one-frame splash freeze no longer occurs on app launch.

This comment was marked as resolved.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Defers Flutter’s first frame during startup initialization to reduce intermittent one-frame splash freezes on certain Android devices (Xiaomi/MediaTek) affected by Impeller Vulkan format probing/fallback behavior.

Changes:

  • Capture WidgetsFlutterBinding and call deferFirstFrame() during startup.
  • Wrap async bootstrap() + Crashlytics setup in try/finally to ensure allowFirstFrame() is always called.
  • Add an in-code rationale comment describing the Impeller/Gralloc motivation.

Comment thread lib/main.dart Outdated
Comment on lines +29 to +33
final binding = WidgetsFlutterBinding.ensureInitialized();
// Defer the first frame until after async initialization completes.
// This reduces the risk of a one-frame splash freeze on devices with
// non-standard Gralloc HALs (e.g. Xiaomi/MediaTek) where the Impeller
// Vulkan capability probe fails and falls back — a process that competes
Comment thread lib/main.dart Outdated
final instanceRegistry = await bootstrap();

if (!kIsWeb && kDebugMode) {
FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(false);
Comment thread lib/main.dart
Comment on lines +47 to +51
FlutterError.onError = (details) {
logger.severe('FlutterError', details.exception, details.stack);
if (!kIsWeb && !kDebugMode) {
FirebaseCrashlytics.instance.recordFlutterFatalError(details);
}
Comment thread lib/main.dart Outdated
Comment on lines +27 to +31
runZonedGuarded(
() async {
WidgetsFlutterBinding.ensureInitialized();

final instanceRegistry = await bootstrap();

if (!kIsWeb && kDebugMode) {
FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(false);
await FirebaseCrashlytics.instance.deleteUnsentReports();
}

FlutterError.onError = (details) {
logger.severe('FlutterError', details.exception, details.stack);
if (!kIsWeb && !kDebugMode) {
FirebaseCrashlytics.instance.recordFlutterFatalError(details);
final binding = WidgetsFlutterBinding.ensureInitialized();
// Defer the first frame until after async initialization completes.
// This reduces the risk of a one-frame splash freeze on devices with
SERDUN added 4 commits April 13, 2026 17:03
…iaTek

On devices with non-standard Gralloc HALs (e.g. Xiaomi, MediaTek), the
Impeller Vulkan backend probes for format 0x38 during engine startup. The
probe fails with EINVAL and falls back to a compatible format — but this
fallback races with the first vsync signal, occasionally causing a one-frame
freeze on the splash screen.

Deferring the first Flutter frame until async bootstrap completes gives the
raster thread time to finish the probe and swapchain fallback before any
frame is submitted for rasterization, reducing the risk of the visible stutter.

Related upstream issue: flutter/flutter#182808
Wraps the async init block in try/finally so binding.allowFirstFrame()
is called on both success and error paths. Previously, if bootstrap()
or any subsequent init threw, the runZonedGuarded error handler would
log the error but allowFirstFrame() would never be called — leaving
the app stuck on the native launch theme indefinitely.
…setup

- Wrap deferFirstFrame/allowFirstFrame in a `deferFrame` flag so the
  delay applies only on Android, where the Impeller Vulkan format-0x38
  probe race exists. iOS/web/desktop are unaffected and no longer incur
  the deferred-frame path.
- Add missing `await` before setCrashlyticsCollectionEnabled so it
  completes before deleteUnsentReports is called.
@SERDUN SERDUN force-pushed the fix/impeller-splash-freeze-defer-first-frame branch from 915dffd to b83d6ce Compare April 13, 2026 14:09
@SERDUN SERDUN closed this Apr 13, 2026
@SERDUN SERDUN deleted the fix/impeller-splash-freeze-defer-first-frame branch May 22, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants