Skip to content

[Linux][Desktop] Tracking issue for frame pacing and display synchronization gaps affecting animation smoothness #191245

Open

Description

@Axiaobo7788

This issue tracks Linux desktop frame pacing, display synchronization, presentation cadence, and high-refresh-rate support.

The target is smooth normal-mode Flutter animation, including concurrent animations, without relying on reduced-motion settings or disabling animations.

Last reviewed: 2026-11-08

Current status

Linux rendering and presentation infrastructure has improved substantially since this issue was opened:

The main frame-scheduling problem is still unresolved.

On the checked master revision:

  • Linux does not install FlutterProjectArgs.vsync_callback.
  • The engine therefore still falls back to a fixed 60 Hz VsyncWaiterFallback.
  • Display refresh-rate metadata does not drive or phase-lock frame scheduling.
  • The merged Wayland subsurface path still schedules GTK work after each presented frame.
  • There is no compositor presentation-timestamp feedback integrated into this path.
  • Mixed-refresh, multi-view, and VRR behavior remain undefined.

So there is still no merged end-to-end Linux frame-pacing solution.

The most significant recent progress is #195287: the proposed Wayland presentation change has now been tested by a Linux maintainer and appears close to landing, but it does not address the missing VSync source.

Checked master:

acade0f6b53278737d9af89df87afeffe040c3eb

Relevant source:

Wayland update: #195287

#195287 changes the Wayland child subsurface from synchronized to desynchronized operation during normal rendering.

Today, each Flutter frame is committed to the child surface and followed by GTK-thread work which queues a redraw of the parent window. Because a synchronized wl_subsurface only makes pending state visible when the parent commits, that GTK repaint effectively becomes part of frame presentation.

#195287 removes that dependency during steady-state rendering:

  • the child surface is desynchronized by default;
  • raster-thread commits can become visible without repainting the GTK parent;
  • resize temporarily re-synchronizes parent and child so geometry changes remain atomic;
  • after GTK commits the resized parent, the child becomes desynchronized again.

This directly addresses one of the main presentation-path inefficiencies without changing the engine's VSync source.

Reported performance

The PR author measured a continuously animating CircularProgressIndicator in a 2560×1400 release-mode window on GNOME 50.1, Wayland, Mesa 26.0.8, radeonsi:

Configuration App CPU gnome-shell CPU
master (66b3ad9) 16.4% 13.4%
#195287 3.2% 2.8%
Flutter 3.47 stable 33.6% 5.9%

GNOME Shell idle baseline was reported as 1.9%.

An empty continuously animating Flame application reportedly dropped from 15.6% to 2.3% application CPU.

A perf profile attributed much of the previous cost to pixman_fill and cairo_fill under gdk_window_begin_draw_frame, consistent with redundant parent-window repainting.

These results show that the current Wayland path can do substantial unnecessary GTK work during animation. They do not show that Flutter is synchronized to the physical display: #195287 does not change the fixed-60 Hz fallback or add compositor presentation timing.

Maintainer review

On November 6, Linux maintainer Robert Ancell tested the PR and reported that it worked in his environment. The remaining review comments are primarily API and style cleanup:

  • keep FlSubsurface as a lightweight wrapper;
  • expose explicit sync/desync operations rather than a boolean setter;
  • simplify where the initial synchronization state is selected;
  • simplify the after-paint signal connection.

The maintainer indicated that after these changes the PR should be ready to land.

#194211, which tracks the full-window GTK repaint and pixman_fill cost caused by the current subsurface path, has also been explicitly pointed to #195287 by the maintainer as the expected fix.

As of this review, #195287 is still open and not merged. Its current head still predates the November 6 review changes, so the reviewed cleanup has not yet appeared on the PR branch.

The X11 renderer is unchanged.

Remaining gaps

Area Current state
VSync Linux still falls back to a fixed 60 Hz scheduling source
High refresh 120/144/165 Hz display modes do not directly drive frame scheduling
Wayland presentation #195287 is close to removing redundant per-frame GTK redraws, but has not landed yet
Wayland scheduling Compositor frame opportunities still do not drive Flutter frame production
Presentation feedback Child commits are not physical presentation timestamps
Mixed refresh / multi-view No clear per-view/per-output scheduling model
VRR A single nominal frame interval is insufficient for adaptive presentation
X11 Uses a different GTK/GLX/EGL path and needs separate investigation
Compatibility Wayland behavior still varies across compositor, driver, scaling, and GPU combinations

Frame production and presentation should continue to be treated separately. A frame can be built, rasterized, submitted, and committed without being displayed at the intended time.

Likewise:

  • Flutter frame count is not display frame count.
  • GTK paint count is not presentation count.
  • Wayland commit count is not presentation count.
  • wl_surface.frame callback count is not precise presentation timing.

Related work

#192342 remains closed without merge. Its experiments are still useful, but it is not an active implementation.

#192873 was fixed by the already-merged #193268.

Experimental evidence

Existing experiments in #183703 and #189584 show why simply increasing the engine timer rate is not enough:

  • one GTK path produced roughly 90–95 engine frames/s while GTK paint remained around 60/s;
  • one NVIDIA/KDE Wayland 144 Hz Vulkan experiment committed the synchronized parent surface at roughly 48/s;
  • a separate experiment using the child surface's wl_surface.frame callback with a desynchronized subsurface produced roughly 144 frames/s and 137–144 child commits/s.

The last result is particularly relevant to the direction taken by #195287, but child commits still do not tell us when buffers were actually shown.

The remaining scheduling problem is therefore not just "run the ticker faster". The frame source should follow the mechanism that actually owns presentation.

There have been no new Linux PRs since the previous review that implement FlutterProjectArgs.vsync_callback, wl_surface.frame-driven scheduling, or an equivalent compositor-driven VSync source.

Compatibility findings

Recent reports also reinforce that presentation changes need testing on real Wayland driver/compositor combinations.

#195822 reports a black client area with the subsurface renderer on:

  • GNOME 50.6 / Wayland;
  • NVIDIA proprietary driver 615;
  • fractional scaling;
  • Flutter 3.50 beta.

The same application reportedly renders through X11.

Flutter triage could not reproduce the issue in a Wayland environment using llvmpipe, so it has been routed to team-linux for further investigation.

This does not establish a general subsurface regression, but it is a useful validation case for #195287 and future Wayland presentation work.

#195821 separately reports a long-running stale-frame problem on Flutter 3.47's older shared-framebuffer path with NVIDIA/Wayland. That path has already been replaced by the subsurface renderer on newer builds, so it is primarily relevant as additional evidence that Linux presentation behavior can be highly driver-dependent.

Suggested direction

1. Land and validate independent Wayland child-surface presentation

#195287 should be validated across:

  • normal animation;
  • resize and maximize/restore;
  • fractional scaling;
  • minimize/restore;
  • output changes;
  • secondary views;
  • surface replacement;
  • shutdown and destruction;
  • GNOME and KDE/Plasma;
  • Mesa and NVIDIA proprietary drivers.

The #195822 NVIDIA/GNOME case should be included where possible.

Steady-state presentation and resize synchronization should continue to be handled separately.

2. Drive scheduling from presentation opportunities

For a Flutter-controlled Wayland child surface, investigate using an appropriate compositor-facing mechanism such as wl_surface.frame to provide frame opportunities to the embedder instead of relying on the fixed 60 Hz fallback.

GTK-controlled and X11 presentation paths should be evaluated separately.

A faster periodic timer can remain a fallback, but it is not a substitute for compositor-aligned scheduling.

3. Add presentation feedback

wl_surface.frame provides a next-frame opportunity, not an accurate presentation timestamp.

wp_presentation_feedback should be investigated for measuring:

  • actual presentation time;
  • submission-to-presentation latency;
  • discarded or superseded buffers;
  • repeated frames;
  • presentation interval distribution.

Tracing should distinguish frame request, rasterization, submission, child commit, parent commit, and compositor presentation.

4. Define multi-display behavior

A complete solution also needs to handle:

  • windows moving between outputs;
  • mixed-refresh displays;
  • multiple Flutter views;
  • VRR/adaptive sync.

A single process-wide fixed interval is unlikely to be sufficient for all of these cases.

Validation

At minimum, test:

  • 60, 120, 144, and 165 Hz;
  • fixed refresh and VRR;
  • GNOME and KDE/Plasma Wayland;
  • X11 separately;
  • Mesa and NVIDIA proprietary drivers;
  • current OpenGL and relevant Vulkan paths;
  • single and mixed-refresh displays;
  • fractional scaling;
  • resize, maximize, minimize/restore, output changes, view creation/destruction, and shutdown.

Useful measurements include:

  • delivered frame opportunities;
  • produced and rasterized frames;
  • submitted buffers;
  • child and parent commits;
  • actually presented or discarded frames where feedback is available;
  • presentation interval distribution;
  • produced-to-presented ratio;
  • submission-to-presentation latency;
  • GTK main-thread cost;
  • raster blocking;
  • CPU/GPU usage and idle behavior.

Tests should record the exact engine revision, renderer, compositor, desktop environment, GPU/driver, display mode, scaling configuration, VRR state, and workload.

Scope and success condition

#49757 remains the canonical cross-platform desktop display-synchronization issue.

#183703 remains the Linux high-refresh investigation.

This issue focuses on the Linux interaction between frame scheduling, GTK/GDK, Wayland/X11 presentation, renderer synchronization, high-refresh displays, presentation feedback, multi-view behavior, and lifecycle correctness.

Success means normal-mode Flutter animation follows useful presentation opportunities with stable visible cadence, low latency, minimal wasted rendering work, and correct behavior across high-refresh, mixed-refresh, resize, and lifecycle scenarios.

A higher engine FPS counter, a rendering-backend change, removal of redundant GTK redraws, or reduced animation alone is not sufficient.

Activity

  1. changed the title [-][Linux][Desktop] Track frame pacing and display synchronization gaps affecting animation smoothness[/-] [+][Linux][Desktop] Tracking issue for frame pacing and display synchronization gaps affecting animation smoothness[/+] on Aug 18, 2026
  2. suryaKommana2662 commented on Aug 18, 2026

    @suryaKommana2662
    Contributor

    @Axiaobo7788 Thanks for the issue and for collecting the related Linux frame pacing, display synchronization, high-refresh-rate, and presentation issues. Since this is a tracking/meta issue covering multiple existing Linux desktop issues rather than a single independently reproducible bug, I’m routing it to team-linux for further evaluation of the proposed tracking scope.

  3. added
    team-linuxOwned by the Linux platform team
    and removed
    in triagePresently being triaged by the triage team
    on Aug 18, 2026
  4. added
    P2Important issues not at the top of the work list
    triaged-linuxTriaged by the Linux platform team
    on Aug 19, 2026
  5. LFRon commented on Nov 11, 2026

    @LFRon

    So when flutter will change from GTK3 to GTK4, I can't wait it ((

  6. o-murphy commented on Nov 13, 2026

    @o-murphy

    I can reproduce the black client area on a Wayland session with a plain
    flutter create app and no plugins, and it looks like a regression between
    3.47 stable and 3.50. Adding data points from a different setup than the
    original report.

    Environment

    • GPU: NVIDIA GeForce GTX 1050 Ti
    • Driver: NVIDIA 580.178.04 (proprietary, OpenGL 4.6 core)
    • Desktop: KDE Plasma, Wayland session
    • Display: single monitor, default scaling

    Reproduction

    1. flutter create --platforms=linux plain_app
    2. In lib/main.dart, replace the template with a minimal app (no dot
      shorthands, so it also builds on 3.47):
      import 'package:flutter/material.dart';
      
      void main() {
        runApp(MaterialApp(
          title: 'plain_app',
          theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple)),
          home: Scaffold(
            appBar: AppBar(title: const Text('plain_app')),
            body: const Center(child: Text('hello')),
          ),
        ));
      }
    3. flutter build linux --release, then run
      build/linux/x64/release/bundle/plain_app.

    Results

    Flutter Session Result
    3.47.9 (stable) Wayland (native) Correct: window, white body, "hello" centered
    3.50.0 (stable) Wayland (native) Black client area; only a small light patch in the lower-left corner of the window
    3.50.0 (stable) X11 (GDK_BACKEND=x11) Still black, same patch
    3.50.0 (stable) Wayland + LIBGL_ALWAYS_SOFTWARE=1 Still black, so this does not look like a GPU driver issue
    3.49.0-0.2.pre Wayland (native) Black, same light patch in the lower-left corner
    3.48.0-0.3.pre Wayland (native) Correct: white body, "hello" centered
    3.48.0-0.5.pre Wayland (native) Correct: white body, "hello" centered
    3.49.0-0.1.pre Wayland (native) Black, same light patch in the lower-left corner

    Notes:

    • The window frame, title and size are correct in every failing case.
    • On 3.50 the visible content looks offset from the window origin as well as
      smaller than the window, which is consistent with a subsurface being placed
      or sized incorrectly.
    • The X11 result differs from the original report, where GDK_BACKEND=x11
      rendered correctly. Possibly a different driver or compositor combination.
    • Bisect: 3.47.9, 3.48.0-0.3.pre and 3.48.0-0.5.pre work; 3.49.0-0.1.pre,
      3.49.0-0.2.pre and 3.50.0 fail. So the regression appears between
      3.48.0-0.5.pre and 3.49.0-0.1.pre.
    • Only Linux was tested. macOS, Windows and web were not checked, so I cannot
      say whether they are affected.

    The steps above are enough to reproduce on any Linux machine with Flutter 3.47 and 3.50 installed.

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 listteam-linuxOwned by the Linux platform teamtriaged-linuxTriaged by the Linux platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions