From 69a608a536a9c3895d48b39f632195e7bc639ab1 Mon Sep 17 00:00:00 2001 From: Miles B Huff Date: Wed, 21 Apr 2021 22:28:20 -0400 Subject: [PATCH] Refactored to (hopefully) improve performance. Also fixed uninterruptible sleeps at high FPSes. --- application/Cargo.toml | 2 +- application/src/main.rs | 98 ++++++++++++++++++++++++----------------- 2 files changed, 59 insertions(+), 41 deletions(-) diff --git a/application/Cargo.toml b/application/Cargo.toml index 6f99077..1876036 100644 --- a/application/Cargo.toml +++ b/application/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ambient-kb" -version = "1.2.0" +version = "1.3.0" license = "LAGPL3" authors = ["Miles B Huff "] description = "Calculates the average color of the display, and sets the keyboard to that color." diff --git a/application/src/main.rs b/application/src/main.rs index ca9904a..d6d19e9 100644 --- a/application/src/main.rs +++ b/application/src/main.rs @@ -3,7 +3,6 @@ //////////////////////////////////////////////////////////////////////////////// use std::fs; use std::io::ErrorKind::WouldBlock; -use std::mem::drop; use std::thread; use std::time::Duration; @@ -29,75 +28,98 @@ struct ArgStruct { verbose: bool, /// Only processes every n pixels - #[structopt(short, long, default_value = "4")] // 30 works well at 1080p. Causes flickering when not a multiple of both display axes. Causes flickering when set too high. + #[structopt(short, long, default_value = "30")] // 30 works well at 1080p. Causes flickering when not a multiple of both display axes. Causes flickering when set too high. divisor: usize, /// Runs this many times per second - #[structopt(short, long, default_value = "4")] // 20 is smooth. Any lower risks creating a strobing effect. Everyone's eyes are different; YMMV. + #[structopt(short, long, default_value = "18")] // 20 is smooth. Any lower risks creating a strobing effect. Everyone's eyes are different; YMMV. fps: f32, /// The priority to run at #[structopt(short, long, default_value = "19")] // 19 is the highest niceness possible - niceness: usize, + niceness: i32, } //////////////////////////////////////////////////////////////////////////////// fn main() { - - // Get input - let args = ArgStruct::from_args(); - let divisor = args.divisor; - let niceness = args.niceness; - let fps = args.fps; - let verbose = args.verbose; - drop(args); + let args = ArgStruct::from_args(); // Get input // // // // // // // // // // // // // // // // // // // // - // Colors - let color_channels = 3usize; + + let color_channels: usize = 3; // Could be a u8 if it weren't used for array indexing. + let color_channels_index: usize = color_channels - 1; // Could be a u8 if it weren't used for array indexing. + let mut color_totals = [0u32, 0u32, 0u32]; // Theoretical maximum of 528,768,000 for 1920x1080; so a large integer (ie, u32) is needed. - let mut color_averages = [0u8, 0u8, 0u8]; + let mut color_averages = [0u8, 0u8, 0u8 ]; // Theoretical maximum of 256 each; so we only need 8 bits. + debug_assert_eq!(color_totals.len(), color_channels); debug_assert_eq!(color_averages.len(), color_channels); + // // // // // // // // // // // // // // // // // // // // // Display + let display = Display::primary().expect("Failed to load primary display."); let mut capturer = Capturer::new(display).expect("Failed to capture screenshot."); + struct Dim { w: usize, h: usize, - } let dim = Dim { - w: capturer.width() / divisor, - h: capturer.height() / divisor, + } + let dim = Dim { + w: capturer.width() / args.divisor, + h: capturer.height() / args.divisor, }; let pixels = dim.w * dim.h; // Theoretical maximum of 2,073,600 for 1920x1080; so a large integer (ie, u32) is needed. - // Reduce priority - unsafe {setpriority(PRIO_PROCESS, getpid() as u32, niceness as i32);} + // // // // // // // // // // // // // // // // // // // // + // Strides + + struct Stride { + h: usize, + w: usize, + x: usize, + y: usize, + s: usize, + } + let mut stride = Stride { + h: 0, + w: 4 * args.divisor, + x: 0, + y: 0, + s: 0, + }; + + // // // // // // // // // // // // // // // // // // // // + // Misc + + let frequency = Duration::from_millis((1000.0 / args.fps).round() as u64); // Set update frequency + unsafe {setpriority(PRIO_PROCESS, getpid() as u32, args.niceness);} // Reduce priority - // Core loop - let frequency = Duration::from_millis((1000.0 / fps).round() as u64); - // drop(fps); + //////////////////////////////////////////////////////////////////////////////// loop { - thread::sleep(frequency); + //TODO: Set keyboard backlight brightness to display backlight brightness + // // // // // // // // // // // // // // // // // // // // // Take a screenshot match capturer.frame() { Ok(buffer) => { + // Reset certain re-used variables + color_totals = [0, 0, 0]; + color_averages = [0, 0, 0]; + // Loop through the screenshot - let stride = buffer.len() / dim.h; + stride.h = buffer.len() / dim.h; for y in 0..dim.h { - let y_stride = stride * y; + stride.y = stride.h * y; for x in 0..dim.w { - let x_stride = x * 4 * divisor; - let xy_stride = x_stride + y_stride; - // drop(x_stride); + stride.x = stride.w * x; // Total the pixels + stride.s = stride.x + stride.y; for i in 0..color_channels { - color_totals[(color_channels - 1) - i] += buffer[xy_stride + i] as u32; + color_totals[color_channels_index - i] += buffer[stride.s + i] as u32; } } } @@ -109,30 +131,26 @@ fn main() { // Convert to hex and send to acpi let hex: String = format!("{:02x}{:02x}{:02x}", color_averages[0], color_averages[1], color_averages[2]); - // Command::new("sys76-kb").arg("set").arg("-c").arg(format!("{}", hex)).spawn().expect("Error while executing `sys76-kb`."); fs::write("/sys/class/leds/system76_acpi::kbd_backlight/color", hex.to_string()).expect("Unable to set keyboard color."); // Debug text - if verbose { + if args.verbose { println!("{} {}", format!("#{}", hex), format!("[{:03}, {:03}, {:03}]", color_averages[0], color_averages[1], color_averages[2]), ); } + + // Pause before taking another screenshot + thread::sleep(frequency); }, + + // // // // // // // // // // // // // // // // // // // // Err(error) => { if error.kind() != WouldBlock { panic!("Error: {}", error); } }, }; - - // Reset re-used variables - color_totals = [0, 0, 0]; - color_averages = [0, 0, 0]; - - // // // // // // // // // // // // // // // // // // // // - - //TODO: Set keyboard backlight brightness to display backlight brightness } }