From 0ac1558b843bec032cc39d055b6e66d6f43c5f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20G=C3=B6hrs?= Date: Thu, 31 Aug 2023 16:00:25 +0200 Subject: [PATCH 1/2] ui: display: the framebuffer is actually 32bpp not 16bpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the display itself is 16bpp the emulated framebuffer device is not. Make sure the demo_mode and png-ification code match this expectation. Signed-off-by: Leonard Göhrs --- src/ui/display.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/ui/display.rs b/src/ui/display.rs index fbb58532..201c1fa3 100644 --- a/src/ui/display.rs +++ b/src/ui/display.rs @@ -29,7 +29,7 @@ mod backend { pub device: (), pub var_screen_info: VarScreeninfo, pub fix_screen_info: FixScreeninfo, - pub frame: [u8; 240 * 240 * 2], + pub frame: [u8; 240 * 240 * 4], } impl Framebuffer { @@ -37,16 +37,16 @@ mod backend { Ok(Self { device: (), var_screen_info: VarScreeninfo { - bits_per_pixel: 16, + bits_per_pixel: 32, xres: 240, yres: 240, ..Default::default() }, fix_screen_info: FixScreeninfo { - line_length: 480, + line_length: 240 * 4, ..Default::default() }, - frame: [0; 240 * 240 * 2], + frame: [0; 240 * 240 * 4], }) } @@ -108,14 +108,21 @@ impl ScreenShooter { let (image, xres, yres) = { let fb = &self.inner.lock().unwrap().0; - let bpp = (fb.var_screen_info.bits_per_pixel / 8) as usize; - let xres = fb.var_screen_info.xres; - let yres = fb.var_screen_info.yres; - let res = (xres as usize) * (yres as usize); + assert!(fb.var_screen_info.bits_per_pixel == 32); + let xres = fb.var_screen_info.xres as usize; + let yres = fb.var_screen_info.yres as usize; - let image: Vec = (0..res) - .map(|i| if fb.frame[i * bpp] != 0 { 0xff } else { 0 }) - .collect(); + let mut image = vec![0; xres * yres * 3]; + + for y in 0..yres { + for x in 0..xres { + let idx = y * xres + x; + + image[idx * 3] = fb.frame[idx * 4 + 2]; + image[idx * 3 + 1] = fb.frame[idx * 4 + 1]; + image[idx * 3 + 2] = fb.frame[idx * 4]; + } + } (image, xres, yres) }; @@ -123,8 +130,8 @@ impl ScreenShooter { let mut dst = Cursor::new(Vec::new()); let mut writer = { - let mut enc = Encoder::new(&mut dst, xres, yres); - enc.set_color(ColorType::Grayscale); + let mut enc = Encoder::new(&mut dst, xres as u32, yres as u32); + enc.set_color(ColorType::Rgb); enc.set_depth(BitDepth::Eight); enc.write_header().unwrap() }; From db3ee5c6ee14c7caeaee16576bccb1e4f7bc007e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20G=C3=B6hrs?= Date: Thu, 31 Aug 2023 16:02:35 +0200 Subject: [PATCH 2/2] ui: display: draw a background image behind all screens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the screen a bit less boring while still requiring minimal implementation effort. The background image is included in the tacd binary as uncompressed bitmap. This has a couple of benefits and drawbacks: + Loading the background can never fail + The background is available instantly + We do not have to keep the decompressed background in RAM, as it is backed by the binary file. - The tacd binary size increases by 240 * 240 * 3 = 172800 bytes - The build.rs becomes more complex Signed-off-by: Leonard Göhrs --- Cargo.toml | 1 + assets/background.png | Bin 0 -> 15628 bytes build.rs | 66 +++++++++++++++++++++++++++++++++++++++++- src/ui/display.rs | 23 +++++++++------ 4 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 assets/background.png diff --git a/Cargo.toml b/Cargo.toml index 6bc7021e..37b2a486 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "GPL-2.0-only" [build-dependencies] chrono = "0.4" +png = "0.17" serde_json = "1.0" serde_yaml = "0.9" diff --git a/assets/background.png b/assets/background.png new file mode 100644 index 0000000000000000000000000000000000000000..a67e9e7ea13c673b3c2744d388bb228b491ac8e0 GIT binary patch literal 15628 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 mrcm*+=tKJq<~=~W+4a8;ip9cUrfD|-0000 Vec<(u8, u8, u8)> { + let mut reader = Decoder::new(File::open(path).unwrap()).read_info().unwrap(); + + let mut buf = vec![0; reader.output_buffer_size()]; + let info = reader.next_frame(&mut buf).unwrap(); + + let width = info.width as usize; + let height = info.height as usize; + + let bytes_per_pixel = match (info.bit_depth, info.color_type) { + (BitDepth::Eight, ColorType::Rgb) => 3, + (BitDepth::Eight, ColorType::Rgba) => 4, + _ => unimplemented!(), + }; + + let mut pixels = vec![(0, 0, 0); width * height]; + + for y in 0..height { + for x in 0..width { + let idx = y * width + x; + + pixels[idx] = ( + buf[idx * bytes_per_pixel], + buf[idx * bytes_per_pixel + 1], + buf[idx * bytes_per_pixel + 2], + ); + } + } + + pixels +} + +fn generate_background() { + let cargo_dir = { + let dir = var_os("CARGO_MANIFEST_DIR").unwrap(); + Path::new(&dir).to_path_buf() + }; + + let out_dir = { + let dir = var_os("OUT_DIR").unwrap(); + Path::new(&dir).to_path_buf() + }; + + let mut output = { + let output_path = out_dir.join("background.rs"); + File::create(output_path).unwrap() + }; + + println!("cargo:rerun-if-changed=assets/background.png"); + + let pixels = decode_png(&cargo_dir.join("assets/background.png")); + + writeln!(&mut output, "&[").unwrap(); + + for (r, g, b) in pixels { + writeln!(&mut output, " ({}, {}, {}),", r, g, b).unwrap(); + } + + writeln!(&mut output, "]").unwrap(); +} + fn main() { generate_openapi_include(); generate_version_string(); generate_build_date(); + generate_background(); } diff --git a/src/ui/display.rs b/src/ui/display.rs index 201c1fa3..a91816e9 100644 --- a/src/ui/display.rs +++ b/src/ui/display.rs @@ -63,6 +63,8 @@ mod backend { use backend::Framebuffer; +const BACKGROUND: &[(u8, u8, u8)] = include!(concat!(env!("OUT_DIR"), "/background.rs")); + pub struct DisplayExclusive(Framebuffer); pub struct Display { @@ -93,7 +95,7 @@ impl Display { } pub fn clear(&self) { - self.with_lock(|target| target.0.frame.iter_mut().for_each(|p| *p = 0x00)); + self.with_lock(|target| target.clear(BinaryColor::Off).unwrap()); } pub fn screenshooter(&self) -> ScreenShooter { @@ -151,7 +153,7 @@ impl DrawTarget for DisplayExclusive { where I: IntoIterator>, { - let bpp = self.0.var_screen_info.bits_per_pixel / 8; + assert!(self.0.var_screen_info.bits_per_pixel == 32); let xres = self.0.var_screen_info.xres; let yres = self.0.var_screen_info.yres; let line_length = self.0.fix_screen_info.line_length; @@ -164,14 +166,17 @@ impl DrawTarget for DisplayExclusive { continue; } - let offset = line_length * y + bpp * x; + let offset_bg = (y * xres + x) as usize; + let offset_fb = (line_length * y + 4 * x) as usize; - for b in 0..bpp { - self.0.frame[(offset + b) as usize] = match color { - BinaryColor::Off => 0x00, - BinaryColor::On => 0xff, - } - } + let rgb = match color { + BinaryColor::Off => BACKGROUND[offset_bg], + BinaryColor::On => (255, 255, 255), + }; + + self.0.frame[offset_fb] = rgb.2; + self.0.frame[offset_fb + 1] = rgb.1; + self.0.frame[offset_fb + 2] = rgb.0; } Ok(())