Present() arms wl_surface.frame and frame_pending_ is cleared only by the
frame callback. Compositors are entitled to stop acknowledging frames for
occluded or minimized surfaces - wlroots-lineage compositors (Hyprland) do
exactly that - and nothing bounded the wait: one missed callback froze the
plane on its last buffer forever, because every later render bailed on
frame_pending(). That is the 2.13.0 black-video report on Hyprland: the
first commit is the pre-allocated 1x1 (or pre-video black) buffer, fully
occluded by the opaque Flutter surface, and the callback it armed never
arrives.
Two changes, one stall:
- A 500 ms frame-acknowledgement watchdog in Present(): on expiry the dead
callback is withdrawn and a fresh present is asked for, so the plane
re-commits instead of sitting on the latch. A miss budget (5) stops
poking a surface the compositor is still ignoring; a real
acknowledgement resets it.
- The very first present is refused until mpv actually has a frame: the
first forced render happens at setVideoRect time, before anything is
decoded, and committing that empty buffer is exactly the commit an
occluded surface ignores. The sticky plane_needs_render flag keeps the
owed resize refresh pending until content exists, so the first present
still happens at the right size the moment the first frame lands.