wayland: Phase 18 fix — create scene before wlr_backend_start

handle_backend_new_output fires during wlr_backend_start (the nested
Wayland backend triggers a host compositor roundtrip that delivers the
new_output event synchronously).  The scene graph and output layout
were previously created *after* wlr_backend_start, so scene_output was
never created, no buffer was ever committed to the host surface, and the
nested window remained invisible.

Move wlr_output_layout_create() and wlr_scene_create() to just before
the backend_new_output listener is wired, ensuring handle_backend_new_output
finds a valid wl_state.scene and can create the scene_output on the spot.
Smoke test: 9/9 checks pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-28 21:48:13 +01:00
parent f4cc8a803e
commit 96b4531ec0
1 changed files with 20 additions and 21 deletions

View File

@ -966,15 +966,29 @@ wl_display_open(const char *name)
if (!wl_state.allocator)
wwarning("wl_backend: allocator unavailable; wlr_output_init_render will be skipped");
/* Phase 18: wire new_output BEFORE starting the backend so we catch
* outputs that appear synchronously during wlr_backend_start. */
/* Phase 34: output layout for multi-head geometry tracking.
* Must be created before backend start so handle_backend_new_output
* can add the output to the layout when it fires. */
wl_state.output_layout = wlr_output_layout_create();
/* Phase 18: scene graph — MUST be created before wlr_backend_start so
* that handle_backend_new_output can create the scene_output immediately
* when the output fires (for nested Wayland, new_output fires during
* wlr_backend_start via the host compositor roundtrip). */
wl_state.scene = wlr_scene_create();
if (wl_state.scene)
wwarning("wl_backend: scene graph created");
else
wwarning("wl_backend: wlr_scene_create failed (no compositing)");
/* Wire new_output BEFORE starting the backend. */
wl_state.backend_new_output_listener.notify = handle_backend_new_output;
wl_signal_add(&wl_state.backend->events.new_output,
&wl_state.backend_new_output_listener);
/* For nested mode, request an output window before start so it is
* created during wlr_backend_start (wlr_wl_output_create returns NULL
* before the backend is started, which is the expected "queued" path). */
/* For nested mode, queue an output window before start; wlr_wl_output_create
* returns NULL before the backend is initialised — the output is created
* during wlr_backend_start and delivered via new_output. */
if (wl_state.is_nested && wl_state.wl_backend_inner)
wlr_wl_output_create(wl_state.wl_backend_inner);
@ -990,7 +1004,7 @@ wl_display_open(const char *name)
}
/* For headless mode, add the output explicitly after start; this fires
* handle_backend_new_output synchronously via backend->events.new_output. */
* handle_backend_new_output synchronously (scene already exists). */
if (!wl_state.is_nested)
wlr_headless_add_output(wl_state.headless_inner, 1920, 1080);
@ -1010,21 +1024,6 @@ wl_display_open(const char *name)
setenv("WAYLAND_DISPLAY", wl_state.socket_name, 1);
wwarning("wl_backend: compositor socket WAYLAND_DISPLAY=%s", wl_state.socket_name);
/* Phase 34: output layout for multi-head geometry tracking. */
wl_state.output_layout = wlr_output_layout_create();
/* (output is added to layout inside handle_backend_new_output) */
/* Phase 18: create the scene graph for compositing. */
wl_state.scene = wlr_scene_create();
if (wl_state.scene)
wwarning("wl_backend: scene graph created");
else
wwarning("wl_backend: wlr_scene_create failed (no compositing)");
/* Expose the output as a wl_output global so clients get geometry. */
if (wl_state.output)
wlr_output_create_global(wl_state.output);
/* Phase 35: advertise core Wayland protocol globals. */
wl_state.compositor =
wlr_compositor_create(wl_state.display, wl_state.renderer);