From 2940dcf793deabd318beaadd9f8e0765cecfd668 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 8 Aug 2024 10:36:15 -0700 Subject: [PATCH] WIP Performance improvements --- Cargo.lock | 45 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/scaler.rs | 36 +++++++++++++++++------------------- src/wallpaper.rs | 39 ++++++++++++++++++++++++++------------- 4 files changed, 89 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 650a429..771fa4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "arrayref" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "atomicwrites" version = "0.4.2" @@ -212,6 +224,7 @@ dependencies = [ "ron", "slab", "smithay-client-toolkit", + "tiny-skia", "tracing", "tracing-subscriber", "walkdir", @@ -1362,6 +1375,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + [[package]] name = "strsim" version = "0.10.0" @@ -1443,6 +1462,32 @@ dependencies = [ "weezl", ] +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tracing" version = "0.1.40" diff --git a/Cargo.toml b/Cargo.toml index e5b7f67..5797735 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ rand = "0.8" ron = { workspace = true } sctk = { package = "smithay-client-toolkit", git = "https://github.com/smithay/client-toolkit", rev = "2e9bf9f" } slab = "0.4.9" +tiny-skia = "0.11.4" tracing = { workspace=true } tracing-subscriber = "0.3.18" walkdir = "2.4" diff --git a/src/scaler.rs b/src/scaler.rs index 8066b72..9a8aa1f 100644 --- a/src/scaler.rs +++ b/src/scaler.rs @@ -45,24 +45,22 @@ pub fn stretch( } pub fn zoom(img: &image::DynamicImage, layer_width: u32, layer_height: u32) -> image::DynamicImage { - let (w, h) = (img.width(), img.height()); - - let ratio = (layer_width as f64 / w as f64).max(layer_height as f64 / h as f64); - - let (new_width, new_height) = ( - (w as f64 * ratio).round() as u32, - (h as f64 * ratio).round() as u32, + // TODO HDR? + let img = img.to_rgba8(); + let pixmap = tiny_skia::PixmapRef::from_bytes(&img, img.width(), img.height()).unwrap(); + let mut target_pixmap = tiny_skia::Pixmap::new(layer_width, layer_height).unwrap(); + target_pixmap.draw_pixmap( + 0, + 0, + pixmap, + &tiny_skia::PixmapPaint::default(), + tiny_skia::Transform::from_scale( + layer_width as f32 / img.width() as f32, + layer_height as f32 / img.height() as f32, + ), + None, ); - - let mut new_image = image::imageops::resize(img, new_width, new_height, FilterType::Lanczos3); - - image::imageops::crop( - &mut new_image, - (new_width - layer_width) / 2, - (new_height - layer_height) / 2, - layer_width, - layer_height, - ) - .to_image() - .into() + image::RgbaImage::from_vec(layer_width, layer_height, target_pixmap.take()) + .unwrap() + .into() } diff --git a/src/wallpaper.rs b/src/wallpaper.rs index ce16c55..967895e 100644 --- a/src/wallpaper.rs +++ b/src/wallpaper.rs @@ -36,6 +36,8 @@ pub struct Wallpaper { loop_handle: calloop::LoopHandle<'static, CosmicBg>, queue_handle: QueueHandle, current_source: Option, + // Cache of source image, if `current_source` is a `Source::Path` + current_image: Option, timer_token: Option, new_image: bool, } @@ -59,6 +61,7 @@ impl Wallpaper { entry, layers: Vec::new(), current_source: None, + current_image: None, image_queue: VecDeque::default(), new_image: false, timer_token: None, @@ -117,21 +120,28 @@ impl Wallpaper { }; cur_resized_img = match source { Source::Path(ref path) => { - let img = &match ImageReader::open(&path) { - Ok(img) => { - match img.with_guessed_format().ok().and_then(|f| f.decode().ok()) { - Some(img) => img, - None => { - tracing::warn!( - "Could not decode image: {}", - path.display() - ); - continue; + if self.current_image.is_none() { + self.current_image = Some(match ImageReader::open(&path) { + Ok(img) => { + match img + .with_guessed_format() + .ok() + .and_then(|f| f.decode().ok()) + { + Some(img) => img, + None => { + tracing::warn!( + "Could not decode image: {}", + path.display() + ); + continue; + } } } - } - Err(_) => continue, - }; + Err(_) => continue, + }); + } + let img = self.current_image.as_ref().unwrap(); match self.entry.scaling_mode { ScalingMode::Fit(color) => { @@ -260,12 +270,14 @@ impl Wallpaper { image_queue.pop_front().map(|current_image_path| { self.current_source = Some(Source::Path(current_image_path.clone())); + self.current_image = None; image_queue.push_back(current_image_path); }); } Source::Color(ref c) => { self.current_source = Some(Source::Color(c.clone())); + self.current_image = None; } }; if let Err(err) = self.save_state() { @@ -328,6 +340,7 @@ impl Wallpaper { while let Some(next) = item.image_queue.pop_front() { item.current_source = Some(Source::Path(next.clone())); + item.current_image = None; if let Err(err) = item.save_state() { error!("{err}"); }