Skip to content

macOS: ask for a fresh capture while a resize waits for its paint - #61

Merged
wenkaifan0720 merged 1 commit into
mainfrom
fix/resize-stall
Sep 29, 2026
Merged

wenkaifan0720 merged 1 commit into
mainfrom
fix/resize-stall

Conversation

@wenkaifan0720

Copy link
Copy Markdown
Collaborator

Follow-up to #59. Checking the published c0576c5 prebuilt, device_frame failed one switch of 30. The view didn't freeze (frames kept coming), but one switch took over 4 s to repaint at the new size. The ad-hoc build did it too, just less often: #59's stall fallback ("kick") fired in 1 to 12 switches per run.

Cause

On macOS, CEF paints by capturing the root frame (CefVideoConsumerOSR). The capture size is the renderer's last activated frame size, set in OnRenderFrameMetadataChangedAfterActivation. A Chromium trace of a stall shows the sequence:

  1. The new geometry goes out. The renderer is busy with the page's resize handler, and the display draws fallback frames.
  2. The renderer's frame at the new size activates, and the capture size changes.
  3. After one more capture, the display reports "No damage yet" on every begin frame, so the capturer has nothing to capture.

The capturer also drops refresh requests while it still sees the content as animating. ApplyGeometry's single Invalidate comes before all of this. No paint at the new size arrives until the 1 s kick swaps in a new surface id, which creates damage. Sometimes one kick wasn't enough, and it took 1 s + 2 s.

Fix

While a resize is in flight, CheckResizeStall (run every begin frame) calls Invalidate(PET_VIEW) every 100 ms. The kick stays as the fallback. Nothing changes when no resize is in flight.

Verification

  • device_frame:
    • 5 runs: 0 kicks, 0 stuck. Before: 1 to 12 kicks per run; the published c0576c5 build failed 1 of 30.
    • Slowest switch: 1.3 s, down from 1.6 to 3.7 s. The page blocks for 600 ms on every resize.
    • One of the 5 runs was traced, which made stalls much more frequent before the fix (12 kicks); it had 0.
  • hidden_at_create, surface_handoff, warm_host_paint, wedge_recovery, alert, multiview, profile_reopen: pass.
  • New cef_host input hash: a91e6834…. The prebuilt needs republishing.

Windows is unchanged. windows-build fails the same software-compositing check on main (control run #60).

🤖 Generated with Claude Code

On macOS CEF paints by capturing the root frame at the size of the
renderer's last activated frame. After a big resize (mid-way through an
animated device switch, typically), the renderer's new-size frame
activates and the capture size changes, but a page with nothing else
changing gives the capturer no damage, and the capturer drops refresh
requests while it still sees the content as animating. The single
Invalidate at the start of the resize comes before all of that, so no
paint at the new size arrived until the 1 s stall kick, sometimes two
(about 4 s).

cef_host now calls Invalidate every 100 ms while a resize is in flight.
device_frame: 0 kicks in 5 runs (before: 1 to 12 per run, and the
published c0576c5 build failed one switch after 2 kicks). Slowest switch
1.3 s, down from 1.6 to 3.7 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@wenkaifan0720
wenkaifan0720 merged commit 32952cc into main Sep 29, 2026
3 checks passed
wenkaifan0720 added a commit that referenced this pull request Sep 29, 2026
The #61 comment said the capturer drops refresh requests while it sees
the content as animating. A trace with gpu.capture on shows the actual
sequence: the renderer's first new-size frame is captured at the old
size, CEF then sets the new capture size, the capture that asks for is
rate-limited, and the capturer's own retries (every ~33 ms) are all
turned away by the stricter check for non-compositor refreshes (nothing
pending, no recent animation) until the stall kick. Invalidate's refresh
demand is treated like a compositor update and captures at once.
Comment and changelog only.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

1 participant