From 1cdea8eff42e4d26caf257edc23b3aac2f96a96b Mon Sep 17 00:00:00 2001 From: Fl1tzi Date: Sun, 26 Nov 2023 02:54:52 +0100 Subject: [PATCH] add image cache for faster image display --- Cargo.toml | 1 + src/device.rs | 24 ++++++++++--- src/modules.rs | 81 +++++++++++++++++++++++++++++++++++++++--- src/modules/blank.rs | 6 +++- src/modules/counter.rs | 8 +++-- src/modules/image.rs | 32 ++++++++++------- src/modules/space.rs | 6 +++- 7 files changed, 133 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fdf3996..217fcac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } lazy_static = "1.4.0" font-loader = "0.11.0" +clru = "0.6.1" diff --git a/src/device.rs b/src/device.rs index c3c1efb..3df00d1 100644 --- a/src/device.rs +++ b/src/device.rs @@ -3,9 +3,11 @@ use crate::{ modules::{retrieve_module_from_name, start_module, HostEvent}, unwrap_or_error, }; +use clru::CLruCache; use deck_driver as streamdeck; use hidapi::HidApi; -use std::{collections::HashMap, fmt::Display, sync::Arc}; +use image::DynamicImage; +use std::{collections::HashMap, fmt::Display, num::NonZeroUsize, sync::Arc}; use streamdeck::{ asynchronous::{AsyncStreamDeck, ButtonStateUpdate}, info::Kind, @@ -14,7 +16,10 @@ use streamdeck::{ use tokio::{ process::Command, runtime::Runtime, - sync::mpsc::{self, error::TrySendError}, + sync::{ + mpsc::{self, error::TrySendError}, + Mutex, + }, }; use tracing::{debug, error, info_span, trace, warn}; @@ -41,6 +46,11 @@ impl Display for Device { } } +/// image cache +/// +/// (button, key), image data +pub type ImageCache = CLruCache<(u8, u32), Arc>; + /// Handles everything related to a single device pub struct Device { modules: HashMap, @@ -50,6 +60,7 @@ pub struct Device { spaces: Arc>, selected_space: Option, serial: String, + image_cache: Arc>, } impl Device { @@ -90,6 +101,9 @@ impl Device { spaces, selected_space: None, serial, + image_cache: Arc::new(Mutex::new(CLruCache::new( + NonZeroUsize::new(button_count.into()).unwrap(), + ))), }) } @@ -130,9 +144,11 @@ impl Device { let ser = self.serial.clone(); let dev = self.device.clone(); let b = btn.clone(); + let image_cache = self.image_cache.clone(); - runtime - .spawn(async move { start_module(ser, b, module, dev, module_receiver).await }); + runtime.spawn(async move { + start_module(ser, b, module, dev, module_receiver, image_cache).await + }); } // if the receiver already dropped the listener then just directly insert none. // Optimizes performance because the key_listener just does not try to send the event. diff --git a/src/modules.rs b/src/modules.rs index d807345..a651fa6 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -10,6 +10,9 @@ use self::space::Space; // other things use crate::config::{Button, ButtonConfigError}; +use crate::device::ImageCache; +use crate::image_rendering::load_image; +use ::image::imageops::FilterType; use ::image::DynamicImage; use async_trait::async_trait; pub use deck_driver as streamdeck; @@ -19,8 +22,8 @@ use streamdeck::info::ImageFormat; use streamdeck::info::Kind; use streamdeck::AsyncStreamDeck; use streamdeck::StreamDeckError; -use tokio::sync::mpsc; -use tracing::{debug, error}; +use tokio::sync::{mpsc, Mutex}; +use tracing::{debug, error, trace}; /// Events that are coming from the host #[derive(Clone, Copy, Debug)] @@ -34,7 +37,7 @@ pub enum HostEvent { pub type ModuleObject = Box; pub type ModuleFuture = Pin> + Send>>; -pub type ModuleInitFunction = fn(Arc