Wake the event loop when wallpaper decoding completes
This commit is contained in:
1 parent
6dd132a4a5
commit
b469929847
4 files changed
+49
-12
No files matched your search
@@ -90,12 +90,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
event_loop.handle().insert_source(
|
event_loop.handle().insert_source(
|
||||||
Timer::from_duration(Duration::from_millis(150)),
|
Timer::from_duration(Duration::from_millis(150)),
|
||||||
move |_, _, state: &mut Ferese| {
|
move |_, _, state: &mut Ferese| {
|
||||||
// Decoders finish on a worker even when an idle DRM output has no
|
|
||||||
// pending frame. Wake rendering once, never continuously for wallpaper.
|
|
||||||
if state.wallpaper.poll() {
|
|
||||||
state.backdrop_generation = state.backdrop_generation.wrapping_add(1);
|
|
||||||
backends::direct::render_all(state);
|
|
||||||
}
|
|
||||||
if let Some(result) = monitor
|
if let Some(result) = monitor
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.and_then(|monitor| monitor.poll(std::time::Instant::now()))
|
.and_then(|monitor| monitor.poll(std::time::Instant::now()))
|
||||||
@@ -124,9 +118,15 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
let result = event_loop.run(None, &mut state, |state| {
|
let result = event_loop.run(None, &mut state, |state| {
|
||||||
|
// The decoder wakes the loop after publishing its result, including
|
||||||
|
// when no output has a pending frame.
|
||||||
|
let wallpaper_changed = state.wallpaper.poll();
|
||||||
|
if wallpaper_changed {
|
||||||
|
state.backdrop_generation = state.backdrop_generation.wrapping_add(1);
|
||||||
|
}
|
||||||
// All input/Wayland callbacks have returned, releasing seat locks.
|
// All input/Wayland callbacks have returned, releasing seat locks.
|
||||||
// Coalesce cursor changes and redraw here, never inside cursor_image.
|
// Coalesce cursor changes and redraw here, never inside cursor_image.
|
||||||
if std::mem::take(&mut state.cursor_redraw_pending) {
|
if std::mem::take(&mut state.cursor_redraw_pending) || wallpaper_changed {
|
||||||
backends::direct::render_all(state);
|
backends::direct::render_all(state);
|
||||||
}
|
}
|
||||||
// Registry/sync/configure replies must not depend on a submitted
|
// Registry/sync/configure replies must not depend on a submitted
|
||||||
|
|||||||
@@ -602,7 +602,10 @@ impl Ferese {
|
|||||||
resize_transactions: HashMap::new(),
|
resize_transactions: HashMap::new(),
|
||||||
resize_snapshots: HashMap::new(),
|
resize_snapshots: HashMap::new(),
|
||||||
nested_backend: None,
|
nested_backend: None,
|
||||||
wallpaper: crate::wallpaper::WallpaperState::new(config.wallpaper),
|
wallpaper: crate::wallpaper::WallpaperState::with_wakeup(
|
||||||
|
config.wallpaper,
|
||||||
|
Some(event_loop.get_signal()),
|
||||||
|
),
|
||||||
maximized_windows: HashSet::new(),
|
maximized_windows: HashSet::new(),
|
||||||
maximized_column_widths: HashMap::new(),
|
maximized_column_widths: HashMap::new(),
|
||||||
window_stack: crate::stacking::WindowStack::default(),
|
window_stack: crate::stacking::WindowStack::default(),
|
||||||
|
|||||||
@@ -67,15 +67,25 @@ pub(crate) struct WallpaperState {
|
|||||||
pixels: Option<image::RgbaImage>,
|
pixels: Option<image::RgbaImage>,
|
||||||
textures: HashMap<ErasedContextId, WallpaperTexture>,
|
textures: HashMap<ErasedContextId, WallpaperTexture>,
|
||||||
upload_retries: HashMap<ErasedContextId, Instant>,
|
upload_retries: HashMap<ErasedContextId, Instant>,
|
||||||
|
wakeup: Option<smithay::reexports::calloop::LoopSignal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WallpaperState {
|
impl WallpaperState {
|
||||||
|
#[cfg(test)]
|
||||||
pub fn new(config: WallpaperConfig) -> Self {
|
pub fn new(config: WallpaperConfig) -> Self {
|
||||||
|
Self::with_wakeup(config, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_wakeup(
|
||||||
|
config: WallpaperConfig,
|
||||||
|
wakeup: Option<smithay::reexports::calloop::LoopSignal>,
|
||||||
|
) -> Self {
|
||||||
let retained = config.clone();
|
let retained = config.clone();
|
||||||
let (sender, receiver) = mpsc::channel();
|
let (sender, receiver) = mpsc::channel();
|
||||||
let owned = config.path.as_ref().is_some_and(|path| path.is_file());
|
let owned = config.path.as_ref().is_some_and(|path| path.is_file());
|
||||||
if owned {
|
if owned {
|
||||||
let path = config.path.unwrap();
|
let path = config.path.unwrap();
|
||||||
|
let wakeup = wakeup.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let load = || -> Result<image::RgbaImage, String> {
|
let load = || -> Result<image::RgbaImage, String> {
|
||||||
let (width, height) =
|
let (width, height) =
|
||||||
@@ -88,6 +98,9 @@ impl WallpaperState {
|
|||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
};
|
};
|
||||||
let _ = sender.send(load());
|
let _ = sender.send(load());
|
||||||
|
if let Some(wakeup) = wakeup {
|
||||||
|
wakeup.wakeup();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
@@ -100,6 +113,7 @@ impl WallpaperState {
|
|||||||
pixels: None,
|
pixels: None,
|
||||||
textures: HashMap::new(),
|
textures: HashMap::new(),
|
||||||
upload_retries: HashMap::new(),
|
upload_retries: HashMap::new(),
|
||||||
|
wakeup,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +140,7 @@ impl WallpaperState {
|
|||||||
tracing::warn!("new wallpaper is unavailable; retaining previous image");
|
tracing::warn!("new wallpaper is unavailable; retaining previous image");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut replacement = Self::new(config);
|
let mut replacement = Self::with_wakeup(config, self.wakeup.clone());
|
||||||
self.config = replacement.config;
|
self.config = replacement.config;
|
||||||
self.mode = replacement.mode;
|
self.mode = replacement.mode;
|
||||||
self.owned = replacement.owned;
|
self.owned = replacement.owned;
|
||||||
@@ -296,6 +310,29 @@ fn image_geometry(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decoder_wakes_an_idle_event_loop() {
|
||||||
|
use smithay::reexports::calloop::{EventLoop, timer::Timer};
|
||||||
|
let mut event_loop = EventLoop::<WallpaperState>::try_new().unwrap();
|
||||||
|
event_loop
|
||||||
|
.handle()
|
||||||
|
.insert_source(Timer::from_duration(Duration::from_secs(5)), |_, _, _| {
|
||||||
|
panic!("wallpaper decoder failed to wake the idle event loop");
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let signal = event_loop.get_signal();
|
||||||
|
let mut state =
|
||||||
|
WallpaperState::with_wakeup(WallpaperConfig::default(), Some(signal.clone()));
|
||||||
|
event_loop
|
||||||
|
.run(None, &mut state, |state| {
|
||||||
|
if state.poll() {
|
||||||
|
assert!(state.pixels.is_some());
|
||||||
|
signal.stop();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn failed_uploads_back_off_per_context_and_reset_for_new_pixels() {
|
fn failed_uploads_back_off_per_context_and_reset_for_new_pixels() {
|
||||||
use smithay::backend::renderer::ContextId;
|
use smithay::backend::renderer::ContextId;
|
||||||
|
|||||||
@@ -1068,9 +1068,6 @@ fn output_elements(
|
|||||||
);
|
);
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
if state.wallpaper.poll() {
|
|
||||||
state.backdrop_generation = state.backdrop_generation.wrapping_add(1);
|
|
||||||
}
|
|
||||||
let Some(output_geometry) = state.space.output_geometry(output) else {
|
let Some(output_geometry) = state.space.output_geometry(output) else {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in new issue
Block a user