Skip to content

macOS: Don't stall window resize on frames with no layers - #191862

Open
edde746 wants to merge 1 commit into
flutter:masterfrom
edde746:macos-empty-frame-resize
Open

edde746 wants to merge 1 commit into
flutter:masterfrom
edde746:macos-empty-frame-resize

Conversation

@edde746

@edde746 edde746 commented Aug 27, 2026 •

Copy link
Copy Markdown

FlutterSurfaceManager derives the committed frame size from the presented surfaces, starting at CGSizeZero (GetRequiredFrameSize). A frame with nothing to rasterize has no layers at all, because the embedder's layer builder only adds a backing store layer when HasEngineRenderedContents() is true. The committed size is then (0, 0), which never matches the size ResizeSynchronizer.beginResize waits for, so every resize step blocked the platform thread for the full one second timeout and logged Resize timed out.

Such a frame displays nothing that could be out of sync with the window, so FlutterCompositor now presents it with a new presentEmptyFrameAtTime:notify:, which reaches ResizeSynchronizer as an empty frame and unblocks a pending resize whatever size that resize waits for. Windows does the same in OnEmptyFrameGenerated, covered there by TestEmptyFrameResizes.

The empty frame is keyed on the frame having no layers, not on it presenting no surfaces. A frame whose only layer is a platform view also presents no surfaces, but that platform view is on screen and is positioned from the frame being committed, so unblocking on it would leave the platform view at the pre-resize geometry. Those frames keep their existing behavior and still stall, measured at 1017.10 ms per resize step with this PR versus 1019.15 ms without it. That case needs the frame's real size to synchronize against, which the embedder does not currently give the macOS compositor, so I left it out of this PR and filed #191865 for it.

An empty frame reports the view's current size to FlutterViewContentDelegate, since it has no content size of its own. Reporting zero, as the old code did, would shrink a window sized to its contents to nothing. The delegate still has to be notified, since viewDidUpdateContents:withSize: is what reveals a window waiting for its first frame.

FlutterSurfaceManagerDelegate is not a public framework header, so its new required method is not an API change for embedders.

Verification

Sample and probe from the issue, 20 resize steps through -[FlutterView setFrameSize:], local mac_debug_unopt_arm64 engine at de37392db47, macOS 27.0.1 arm64:

scene mean per resize step Resize timed out
before 1021.04 ms 20 / 20
after 9.44 ms 0 / 20

flutter_desktop_darwin_unittests (240 tests) and flutter_desktop_darwin_swift_unittests (5 tests) pass, and clang-tidy is clean. Each new test was confirmed to fail with the corresponding part of the fix reverted.

Fixes #190075

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. platform-macos Building on or for macOS specifically a: desktop Running on desktop team-macos Owned by the macOS platform team labels Aug 27, 2026
@edde746
edde746 force-pushed the macos-empty-frame-resize branch 5 times, most recently from 71333df to bd2a3b5 Compare August 27, 2026 08:50
@edde746 edde746 changed the title macOS: Don't stall window resize on frames with nothing to rasterize macOS: Don't stall window resize on frames with no layers Aug 27, 2026
@edde746
edde746 marked this pull request as ready for review August 27, 2026 09:25
@edde746
edde746 requested a review from a team as a code owner August 27, 2026 09:25

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for presenting empty frames (frames with no layers) on macOS. It updates FlutterCompositor, FlutterSurfaceManager, FlutterView, and ResizeSynchronizer to handle empty frames without reporting a zero frame size, which previously caused issues during window resizing. Specifically, an empty frame now unblocks the resize synchronizer regardless of the target size it is waiting for. Unit tests have been added to verify this behavior. I have no feedback to provide.

@LouiseHsu
LouiseHsu requested a review from knopp August 27, 2026 22:00
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 2, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 2, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 2, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 7, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 7, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 7, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 7, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 7, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 18, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 18, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 18, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 18, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 18, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 23, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Sep 23, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Sep 23, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Oct 1, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Oct 1, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Oct 1, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Oct 1, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Oct 1, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Oct 13, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Oct 13, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
@vashworth vashworth added the CICD Run CI/CD label Oct 14, 2026
@knopp
knopp force-pushed the macos-empty-frame-resize branch from bd2a3b5 to 6ac7d4b Compare October 19, 2026 14:15
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Oct 19, 2026
@knopp knopp added the CICD Run CI/CD label Oct 20, 2026
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Oct 23, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Oct 23, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Oct 28, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Oct 28, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
@knopp

knopp commented Nov 5, 2026

Copy link
Copy Markdown
Member

Unfortunately this got stale and the macOS build fails. @edde746 any chance you'll have time to update the PR?

`FlutterSurfaceManager` derived the committed frame size from the presented
surfaces, starting at `CGSizeZero`. A frame with nothing to rasterize has no
layers, so it committed a size of (0, 0), which never matches the size
`ResizeSynchronizer.beginResize` waits for. Every resize step blocked the
platform thread for the full one second timeout and logged "Resize timed out".

Such a frame displays nothing that could be out of sync with the window, so
`FlutterCompositor` now presents it with `presentEmptyFrameAtTime:notify:`,
which commits it as an empty frame and unblocks a pending resize whatever size
that resize waits for. Windows does the same in
`FlutterWindowsView::OnEmptyFrameGenerated`.

The empty frame is keyed on the frame having no layers, not on it presenting no
surfaces. A frame whose only layer is a platform view also presents no
surfaces, but that platform view is on screen and is positioned from the frame
being committed, so it stays on the existing path.

An empty frame reports the view's current size to `FlutterViewContentDelegate`,
since it has no content size of its own. Reporting zero would resize a window
sized to its contents down to nothing. The delegate still has to be notified,
because `viewDidUpdateContents:withSize:` is what reveals a window waiting for
its first frame.

Measured with the sample and probe from the issue, 20 resize steps: 1021.04 ms
mean per step and 20 timeouts before, 9.44 ms and none after.
@edde746
edde746 force-pushed the macos-empty-frame-resize branch from 6ac7d4b to 835da96 Compare November 5, 2026 20:52
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Nov 5, 2026
@edde746

edde746 commented Nov 5, 2026

Copy link
Copy Markdown
Author

Rebased onto master and switched the empty-frame notification to contentDelegate after #185256 split viewDidUpdateContents:withSize: out of FlutterViewSizingDelegate.

@knopp knopp added the CICD Run CI/CD label Nov 5, 2026
@knopp
knopp enabled auto-merge November 6, 2026 15:43

@knopp knopp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Re-reviewing this - I am wondering why do we need to present methods, why not handle empty surfaces list instead?

@edde746

edde746 commented Nov 6, 2026

Copy link
Copy Markdown
Author

An empty surfaces list doesn't mean an empty frame. Present only creates surfaces for backing store layers, so a platform-view-only frame also has surfaces.count == 0, yet that platform view is on screen.

An empty frame has no size, so it unblocks beginResize for any target size. That's safe with no layers, but for a platform-view-only frame, a stale pre-resize frame would unblock it and leave the platform view at the old geometry. FlutterSurfaceManager can't tell the two cases apart, so the check is layers_count == 0 in the compositor. Platform-view-only frames are tracked in #191865.

If you prefer keying on surfaces.count == 0 anyway (simpler, also fixes the platform-view stall, at the cost of a possible one-frame geometry mismatch), I can switch.

RyanTheTechMan added a commit to RyanTheTechMan/plezy that referenced this pull request Nov 9, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

flutter/flutter#191862
github-actions Bot pushed a commit to RyanTheTechMan/plezy that referenced this pull request Nov 9, 2026
Keep a one-pixel Flutter backing store alive on macOS so each resize can synchronize immediately.

This is a temporary workaround until flutter/flutter#191862 is merged and available in Plezy's Flutter SDK.

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

Labels

a: desktop Running on desktop CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-macos Building on or for macOS specifically team-macos Owned by the macOS platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[macOS] Window resize blocks the main thread for 1s per step when the Flutter scene has nothing to rasterize

3 participants