feat(compositor): implement surface compositing and layer shell rendering

Replace the clear-colour-only stub in render_output with full
surface compositing via Space::render_elements_for_output.

Changes:
- drm_device.rs: add start_time: Instant to WeftDrmData for elapsed-
 time frame callbacks
- drm.rs: rewrite render_output rendering block
 - collect SpaceRenderElements from Space via render_elements_for_output
 which includes both mapped windows and wlr-layer-shell surfaces from
 layer_map_for_output (sorted by z-index, clipped to output geometry)
 - pass collected elements to DrmOutput::render_frame
 - fix send_frame timing from Duration::ZERO to start_time.elapsed()
 with 16ms throttle hint
 - add space.refresh() and popups.cleanup() after each frame
 Use explicit inner block to scope space+drm borrows so post-render
 bookkeeping can access state mutably

Cursor rendering deferred requires cursor theme loading or MemoryRenderBuffer
setup; tracked separately.
This commit is contained in:
Marco Allegretti 2026-03-11 00:03:33 +01:00
parent 732e572c43
commit 61bef1a0a7
2 changed files with 66 additions and 48 deletions

View file

@ -5,7 +5,12 @@ pub fn run() -> anyhow::Result<()> {
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use std::{collections::HashMap, path::Path, sync::Arc, time::Duration}; use std::{
collections::HashMap,
path::Path,
sync::Arc,
time::{Duration, Instant},
};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use anyhow::Context; use anyhow::Context;
@ -71,6 +76,7 @@ const SUPPORTED_FORMATS: &[Fourcc] = &[
const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888]; const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888];
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
#[allow(dead_code)]
type WeftMultiRenderer<'a> = MultiRenderer< type WeftMultiRenderer<'a> = MultiRenderer<
'a, 'a,
'a, 'a,
@ -239,6 +245,7 @@ pub fn run() -> anyhow::Result<()> {
devices: HashMap::new(), devices: HashMap::new(),
keyboards: Vec::new(), keyboards: Vec::new(),
display_handle, display_handle,
start_time: Instant::now(),
}); });
let existing: Vec<(DrmNode, std::path::PathBuf)> = state let existing: Vec<(DrmNode, std::path::PathBuf)> = state
@ -581,6 +588,13 @@ fn render_output(state: &mut WeftCompositorState, node: DrmNode, crtc: crtc::Han
.unwrap_or(d.primary_gpu) .unwrap_or(d.primary_gpu)
}; };
let elapsed = state
.drm
.as_ref()
.map(|d| d.start_time.elapsed())
.unwrap_or_default();
{
let WeftCompositorState { let WeftCompositorState {
ref mut drm, ref mut drm,
ref space, ref space,
@ -615,12 +629,13 @@ fn render_output(state: &mut WeftCompositorState, node: DrmNode, crtc: crtc::Han
} }
}; };
// Wave 2: clear-colour-only frame to establish the VBlank pipeline. let elements = space
// Surface compositing is added in Wave 3. .render_elements_for_output(&mut renderer, &output, 1.0)
let elements: &[WaylandSurfaceRenderElement<WeftMultiRenderer<'_>>] = &[]; .unwrap_or_default();
match surface.drm_output.render_frame( match surface.drm_output.render_frame(
&mut renderer, &mut renderer,
elements, &elements,
[0.08_f32, 0.08, 0.08, 1.0], [0.08_f32, 0.08, 0.08, 1.0],
FrameFlags::DEFAULT, FrameFlags::DEFAULT,
) { ) {
@ -632,12 +647,14 @@ fn render_output(state: &mut WeftCompositorState, node: DrmNode, crtc: crtc::Han
Ok(_) => {} Ok(_) => {}
Err(e) => tracing::warn!(?e, "render_frame failed"), Err(e) => tracing::warn!(?e, "render_frame failed"),
} }
}
space.elements().for_each(|window| { state.space.elements().for_each(|window| {
window.send_frame(&output, Duration::ZERO, Some(Duration::ZERO), |_, _| { window.send_frame(&output, elapsed, Some(Duration::from_millis(16)), |_, _| {
Some(output.clone()) Some(output.clone())
}); });
}); });
state.space.refresh();
state.popups.cleanup();
let _ = state.display_handle.flush_clients(); let _ = state.display_handle.flush_clients();
} }

View file

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, time::Instant};
use smithay::{ use smithay::{
backend::{ backend::{
@ -55,4 +55,5 @@ pub struct WeftDrmData {
pub devices: HashMap<DrmNode, WeftDrmDevice>, pub devices: HashMap<DrmNode, WeftDrmDevice>,
pub keyboards: Vec<smithay::reexports::input::Device>, pub keyboards: Vec<smithay::reexports::input::Device>,
pub display_handle: DisplayHandle, pub display_handle: DisplayHandle,
pub start_time: Instant,
} }