From a7daa4c5fcaf350634e7d525feb7b7892d733e48 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Tue, 28 Oct 2025 12:20:02 -0600 Subject: [PATCH] get fps better --- abi/src/lib.rs | 10 +++---- kernel/src/abi.rs | 8 ++++-- kernel/src/display.rs | 5 +--- kernel/src/framebuffer.rs | 59 +++++++++++++++++++++++++++++++++++++-- kernel/src/ui.rs | 7 ++--- user-apps/gif/src/main.rs | 4 +-- 6 files changed, 72 insertions(+), 21 deletions(-) diff --git a/abi/src/lib.rs b/abi/src/lib.rs index f549a93..096758c 100644 --- a/abi/src/lib.rs +++ b/abi/src/lib.rs @@ -65,10 +65,10 @@ pub mod display { abi_sys::lock_display(lock); } - // const BUF_SIZE: usize = 15 * 1024; // tune this for performance - // static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE]; - const BUF_SIZE: usize = 250 * 1024; // tune this for performance - static mut BUF: Lazy> = Lazy::new(|| vec![const { CPixel::new() }; BUF_SIZE]); + const BUF_SIZE: usize = 15 * 1024; // tune this for performance + static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE]; + // const BUF_SIZE: usize = 250 * 1024; // tune this for performance + // static mut BUF: Lazy> = Lazy::new(|| vec![const { CPixel::new() }; BUF_SIZE]); pub struct Display; @@ -97,7 +97,7 @@ pub mod display { unsafe { BUF[count] = p.into() }; count += 1; - if count == BUF_SIZE { + if count == BUF_SIZE - 1 { abi_sys::draw_iter(unsafe { BUF.as_ptr() }, count); count = 0; } diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index 16eb847..2f1497b 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -11,7 +11,8 @@ use embedded_sdmmc::{DirEntry, LfnBuffer}; use heapless::spsc::Queue; use crate::{ - display::{FB_PAUSED, FRAMEBUFFER}, + display::FRAMEBUFFER, + framebuffer::FB_PAUSED, storage::{Dir, File, SDCARD}, }; @@ -74,7 +75,7 @@ pub extern "C" fn get_ms() -> u64 { const _: LockDisplay = lock_display; pub extern "C" fn lock_display(lock: bool) { - FB_PAUSED.store(lock, Ordering::Relaxed); + FB_PAUSED.store(lock, Ordering::Release); } const _: DrawIterAbi = draw_iter; @@ -83,7 +84,10 @@ pub extern "C" fn draw_iter(cpixels: *const CPixel, len: usize) { let cpixels = unsafe { core::slice::from_raw_parts(cpixels, len) }; let iter = cpixels.iter().copied().map(|c: CPixel| c.into()); + + FB_PAUSED.store(true, Ordering::Release); unsafe { FRAMEBUFFER.draw_iter(iter).unwrap() } + FB_PAUSED.store(false, Ordering::Release); } pub static mut KEY_CACHE: Queue = Queue::new(); diff --git a/kernel/src/display.rs b/kernel/src/display.rs index dd0d147..b645a40 100644 --- a/kernel/src/display.rs +++ b/kernel/src/display.rs @@ -26,7 +26,6 @@ pub static mut FRAMEBUFFER: Lazy = Lazy::new(|| { static mut BUF: [u16; framebuffer::SIZE] = [0; framebuffer::SIZE]; AtomicFrameBuffer::new(unsafe { &mut BUF }) }); -pub static FB_PAUSED: AtomicBool = AtomicBool::new(false); pub async fn init_display( spi: Spi<'static, SPI1, Async>, @@ -54,9 +53,7 @@ pub async fn init_display( #[embassy_executor::task] pub async fn display_handler(mut display: DISPLAY) { loop { - if !FB_PAUSED.load(Ordering::Acquire) { - unsafe { FRAMEBUFFER.partial_draw(&mut display).await.unwrap() } - } + unsafe { FRAMEBUFFER.safe_draw(&mut display).await.unwrap() }; // small yield to allow other tasks to run Timer::after_nanos(100).await; diff --git a/kernel/src/framebuffer.rs b/kernel/src/framebuffer.rs index f450691..918857f 100644 --- a/kernel/src/framebuffer.rs +++ b/kernel/src/framebuffer.rs @@ -18,11 +18,13 @@ pub const TILE_SIZE: usize = 16; // 16x16 tile pub const TILE_COUNT: usize = (SCREEN_WIDTH / TILE_SIZE) * (SCREEN_HEIGHT / TILE_SIZE); // 400 tiles // Group of tiles for batching -pub const MAX_META_TILES: usize = SCREEN_WIDTH / TILE_SIZE; // max number of meta tiles in buffer +pub const MAX_META_TILES: usize = (SCREEN_WIDTH / TILE_SIZE) * 2; // max number of meta tiles in buffer type MetaTileVec = heapless::Vec; pub const SIZE: usize = SCREEN_HEIGHT * SCREEN_WIDTH; +pub static FB_PAUSED: AtomicBool = AtomicBool::new(false); + static mut DIRTY_TILES: LazyLock> = LazyLock::new(|| { let mut tiles = heapless::Vec::new(); for _ in 0..TILE_COUNT { @@ -50,7 +52,7 @@ impl<'a> AtomicFrameBuffer<'a> { for ty in start_ty..=end_ty { for tx in start_tx..=end_tx { let tile_idx = ty * tiles_x + tx; - unsafe { DIRTY_TILES.get_mut()[tile_idx].store(true, Ordering::Relaxed) }; + unsafe { DIRTY_TILES.get_mut()[tile_idx].store(true, Ordering::Release) }; } } } @@ -111,7 +113,7 @@ impl<'a> AtomicFrameBuffer<'a> { // Grow horizontally, but keep under MAX_TILES_PER_METATILE while tx + width_tiles < tiles_x && unsafe { - DIRTY_TILES.get()[ty * tiles_x + tx + width_tiles].load(Ordering::Relaxed) + DIRTY_TILES.get()[ty * tiles_x + tx + width_tiles].load(Ordering::Acquire) } && (width_tiles + height_tiles) <= MAX_META_TILES { @@ -176,6 +178,57 @@ impl<'a> AtomicFrameBuffer<'a> { Ok(()) } + pub async fn safe_draw( + &mut self, + display: &mut ST7365P, + ) -> Result<(), ()> + where + SPI: SpiDevice, + DC: OutputPin, + RST: OutputPin, + DELAY: DelayNs, + { + let tiles_x = SCREEN_WIDTH / TILE_SIZE; + let _tiles_y = SCREEN_HEIGHT / TILE_SIZE; + + let tiles = unsafe { DIRTY_TILES.get_mut() }; + let mut pixel_buffer: heapless::Vec = heapless::Vec::new(); + + for tile_idx in 0..TILE_COUNT { + if tiles[tile_idx].swap(false, Ordering::AcqRel) { + let tx = tile_idx % tiles_x; + let ty = tile_idx / tiles_x; + + let x_start = tx * TILE_SIZE; + let y_start = ty * TILE_SIZE; + + let x_end = (x_start + TILE_SIZE).min(SCREEN_WIDTH); + let y_end = (y_start + TILE_SIZE).min(SCREEN_HEIGHT); + + pixel_buffer.clear(); + + for y in y_start..y_end { + let start = y * SCREEN_WIDTH + x_start; + let end = y * SCREEN_WIDTH + x_end; + pixel_buffer.extend_from_slice(&self.0[start..end]).unwrap(); + } + + display + .set_pixels_buffered( + x_start as u16, + y_start as u16, + (x_end - 1) as u16, + (y_end - 1) as u16, + &pixel_buffer, + ) + .await + .unwrap(); + } + } + + Ok(()) + } + /// Sends only dirty tiles (16x16px) in batches to the display pub async fn partial_draw( &mut self, diff --git a/kernel/src/ui.rs b/kernel/src/ui.rs index ceeb7f9..64f81f6 100644 --- a/kernel/src/ui.rs +++ b/kernel/src/ui.rs @@ -1,9 +1,6 @@ use crate::{ - BINARY_CH, - display::{FB_PAUSED, FRAMEBUFFER}, - elf::load_binary, - peripherals::keyboard, - storage::FileName, + BINARY_CH, display::FRAMEBUFFER, elf::load_binary, framebuffer::FB_PAUSED, + peripherals::keyboard, storage::FileName, }; use abi_sys::keyboard::{KeyCode, KeyState}; use alloc::{str::FromStr, string::String, vec::Vec}; diff --git a/user-apps/gif/src/main.rs b/user-apps/gif/src/main.rs index 25a6d3a..48e7e1a 100644 --- a/user-apps/gif/src/main.rs +++ b/user-apps/gif/src/main.rs @@ -42,9 +42,9 @@ pub fn main() { for frame in gif.frames() { let start = get_ms(); - lock_display(true); + // lock_display(true); frame.draw(&mut display).unwrap(); - lock_display(false); + // lock_display(false); // frame_num += 1;