Flush Wayland events before having to send too many file descriptors at once

Works around a bug in the wayland-backend dependency failing to limit
the number of file descriptors sent in one message to MAX_FDS_OUT = 28
This commit is contained in:
Gergő Sályi 2025-04-24 14:50:24 +02:00
parent cd22b9bebe
commit 6eec049e48
2 changed files with 30 additions and 9 deletions

View file

@ -13,7 +13,8 @@ use std::{
sync::{ sync::{
Arc, Arc,
mpsc::{channel, Receiver}, mpsc::{channel, Receiver},
} },
rc::Rc,
}; };
use clap::Parser; use clap::Parser;
@ -50,6 +51,7 @@ use crate::{
}; };
pub struct State { pub struct State {
pub connection: Rc<Connection>,
pub compositor_state: CompositorState, pub compositor_state: CompositorState,
pub registry_state: RegistryState, pub registry_state: RegistryState,
pub output_state: OutputState, pub output_state: OutputState,
@ -95,7 +97,7 @@ fn run() -> anyhow::Result<()> {
// Initialize wayland client // Initialize wayland client
// ******************************** // ********************************
let conn = Connection::connect_to_env().unwrap(); let conn = Rc::new(Connection::connect_to_env().unwrap());
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap(); let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
let qh = event_queue.handle(); let qh = event_queue.handle();
@ -150,6 +152,7 @@ fn run() -> anyhow::Result<()> {
.unwrap_or(Compositor::Sway); .unwrap_or(Compositor::Sway);
let mut state = State { let mut state = State {
connection: Rc::clone(&conn),
compositor_state, compositor_state,
registry_state, registry_state,
output_state: OutputState::new(&globals, &qh), output_state: OutputState::new(&globals, &qh),
@ -185,7 +188,7 @@ fn run() -> anyhow::Result<()> {
let token_signal = signal_pipe.as_ref().map(|pipe| poll.add_readable(pipe)); let token_signal = signal_pipe.as_ref().map(|pipe| poll.add_readable(pipe));
loop { loop {
flush_blocking(&event_queue); flush_blocking(&conn);
let read_guard = ensure_prepare_read(&mut state, &mut event_queue); let read_guard = ensure_prepare_read(&mut state, &mut event_queue);
poll.poll().expect("Main event loop poll failed"); poll.poll().expect("Main event loop poll failed");
if poll.ready(token_wayland) { if poll.ready(token_wayland) {
@ -218,15 +221,15 @@ fn run() -> anyhow::Result<()> {
} }
} }
fn flush_blocking(event_queue: &EventQueue<State>) { fn flush_blocking(connection: &Connection) {
loop { loop {
let result = event_queue.flush(); let result = connection.flush();
if result.is_ok() { return } if result.is_ok() { return }
if let Err(WaylandError::Io(io_error)) = &result { if let Err(WaylandError::Io(io_error)) = &result {
if io_error.kind() == io::ErrorKind::WouldBlock { if io_error.kind() == io::ErrorKind::WouldBlock {
warn!("Wayland flush needs to block"); warn!("Wayland flush needs to block");
let mut poll_fds = [PollFd::from_borrowed_fd( let mut poll_fds = [PollFd::from_borrowed_fd(
event_queue.as_fd(), connection.as_fd(),
PollFlags::OUT, PollFlags::OUT,
)]; )];
retry_on_intr(|| poll(&mut poll_fds, -1)).unwrap(); retry_on_intr(|| poll(&mut poll_fds, -1)).unwrap();

View file

@ -49,7 +49,7 @@ use smithay_client_toolkit::reexports::protocols::wp::{
}; };
use crate::{ use crate::{
State, flush_blocking, State,
gpu::{ gpu::{
DRM_FORMAT_XRGB8888, fmt_modifier, DRM_FORMAT_XRGB8888, fmt_modifier,
GpuMemory, GpuUploader, GpuWallpaper, GpuMemory, GpuUploader, GpuWallpaper,
@ -57,6 +57,8 @@ use crate::{
image::{load_wallpaper, output_wallpaper_files, WallpaperFile}, image::{load_wallpaper, output_wallpaper_files, WallpaperFile},
}; };
const MAX_FDS_OUT: usize = 28;
impl CompositorHandler for State { impl CompositorHandler for State {
fn scale_factor_changed( fn scale_factor_changed(
&mut self, &mut self,
@ -937,6 +939,8 @@ fn load_wallpapers(
let mut reused_count = 0usize; let mut reused_count = 0usize;
let mut loaded_count = 0usize; let mut loaded_count = 0usize;
let mut error_count = 0usize; let mut error_count = 0usize;
flush_blocking(&state.connection);
let mut fds_need_flush = 0usize;
for wallpaper_file in wallpaper_files { for wallpaper_file in wallpaper_files {
if log::log_enabled!(log::Level::Debug) { if log::log_enabled!(log::Level::Debug) {
if wallpaper_file.path == wallpaper_file.canon_path { if wallpaper_file.path == wallpaper_file.canon_path {
@ -992,6 +996,12 @@ fn load_wallpapers(
} }
match uploader.upload() { match uploader.upload() {
Ok(gpu_wallpaper) => { Ok(gpu_wallpaper) => {
let fds_count = gpu_wallpaper.memory_planes_len;
if fds_need_flush + fds_count > MAX_FDS_OUT {
flush_blocking(&state.connection);
fds_need_flush = 0;
}
fds_need_flush += fds_count;
let wallpaper = wallpaper_dmabuf( let wallpaper = wallpaper_dmabuf(
&state.dmabuf_state, &state.dmabuf_state,
qh, qh,
@ -1015,6 +1025,11 @@ fn load_wallpapers(
} }
} }
} }
if fds_need_flush + 1 > MAX_FDS_OUT {
flush_blocking(&state.connection);
fds_need_flush = 0;
}
fds_need_flush += 1;
let mut shm_pool = match RawPool::new(shm_size, &state.shm) { let mut shm_pool = match RawPool::new(shm_size, &state.shm) {
Ok(shm_pool) => shm_pool, Ok(shm_pool) => shm_pool,
Err(e) => { Err(e) => {
@ -1058,8 +1073,11 @@ fn load_wallpapers(
}); });
loaded_count += 1; loaded_count += 1;
} }
debug!("Wallpapers for new output: {} reused, {} loaded, {} errors", if fds_need_flush > 0 {
reused_count, loaded_count, error_count); flush_blocking(&state.connection);
}
debug!("Wallpapers for new output: {} loaded, {} reused, {} errors",
loaded_count, reused_count, error_count);
debug!("Wallpapers are available for workspaces: {}", debug!("Wallpapers are available for workspaces: {}",
workspace_backgrounds.iter() workspace_backgrounds.iter()
.map(|bg| bg.workspace_name.as_str()) .map(|bg| bg.workspace_name.as_str())