From 54195f079810410eb9456348e7e44d382d3c4d3f Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Thu, 15 May 2025 20:45:00 +0200 Subject: Extend GPU rendering to every head, not just the first Phase 2 of the GPU-rendering plan deliberately targeted a single head (GpuContext::output: Option<(crtc::Handle, GpuOutput)>) as a narrow proof that GBM+EGL+DrmCompositor rendering works at all on this hardware. DrmOutputManager already supports driving several crtcs at once - initialize_output is a per-crtc call on one shared manager, the same way anvil drives multiple outputs - so this was purely an unexercised restriction, not an architectural limit. GpuContext::output is now GpuContext::outputs: Vec<(crtc::Handle, GpuOutput)>, and udev/platform.rs calls initialize_output for every connected head in its own bring-up loop instead of only the first after that loop finishes. A head this fails for individually (already logged, not fatal) still just has no entry and falls back to the existing legacy Pixman path, unchanged from before. session.rs's VBlank handler and its VT-switch resume path (which excludes GPU-driven crtcs from the legacy set_crtc reassert loop, a different device fd that must never issue mode-set commands against a crtc DrmOutputManager already owns) both now look a crtc up in the Vec instead of comparing against a single stored one. render.rs's own render-loop lookup uses direct field access (gpu.outputs.iter_mut().find(...)) rather than an equivalent &mut self method: the borrow checker treats a method call as borrowing all of GpuContext, including gpu.renderer needed a few lines later for the same head, where direct field access lets it see the two borrows are disjoint. Still gated behind SRDWM_GPU=1 (unset by default) and untested on real multi-monitor hardware with the flag on - this machine has one display, so the actual multi-head path itself only gets exercised whenever it's set on hardware that has more than one. --- crates/wayland/src/udev/platform.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'crates/wayland/src/udev/platform.rs') diff --git a/crates/wayland/src/udev/platform.rs b/crates/wayland/src/udev/platform.rs index 6826cde..19991e8 100644 --- a/crates/wayland/src/udev/platform.rs +++ b/crates/wayland/src/udev/platform.rs @@ -88,6 +88,19 @@ impl UdevPlatform { let resolved_scale = head.output.current_scale().fractional_scale(); x_offset += head.size.0; logical_x += (head.size.0 as f64 / resolved_scale).round() as i32; + // Every connected head gets a chance at the GPU path, not just + // the first - `DrmOutputManager` already supports driving + // several crtcs at once (`GpuContext::outputs`' own doc + // comment), Phase 2 simply never called this more than once. + // A no-op whenever `gpu_context` is `None` (every session that + // doesn't set `SRDWM_GPU=1`, or where `gpu::probe` itself + // failed). A head this fails for individually (logged inside + // `initialize_output`) just falls back to the legacy Pixman + // path below, same as before - this loop doesn't need to know + // which outcome happened. + if let Some(ctx) = gpu_context.as_mut() { + ctx.initialize_output(head.crtc, head.mode, head.connector, &head.output); + } heads.push(head); output_entries.push(entry); } @@ -101,15 +114,6 @@ impl UdevPlatform { // `WaylandPlatform::connect` for why this isn't optional. smithay::wayland::output::OutputManagerState::new_with_xdg_output::(&display_handle); - // Phase 2 of the GPU-rendering plan (`gpu.rs`'s own module doc - // comment) only ever targets one head - the first, same as the - // pointer-centring choice just above - not every head at once. - // A no-op whenever `gpu_context` is `None` (every session that - // doesn't set `SRDWM_GPU=1`, or where `gpu::probe` itself failed). - if let Some(ctx) = gpu_context.as_mut() { - ctx.initialize_output(first.crtc, first.mode, first.connector, &first.output); - } - let compositor_state = CompositorState::new::(&display_handle); let xdg_shell_state = XdgShellState::new::(&display_handle); let xdg_decoration_state = XdgDecorationState::new::(&display_handle); -- cgit v1.2.3