mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 15:55:25 +00:00
get fps better
This commit is contained in:
@@ -65,10 +65,10 @@ pub mod display {
|
|||||||
abi_sys::lock_display(lock);
|
abi_sys::lock_display(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const BUF_SIZE: usize = 15 * 1024; // tune this for performance
|
const BUF_SIZE: usize = 15 * 1024; // tune this for performance
|
||||||
// static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE];
|
static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE];
|
||||||
const BUF_SIZE: usize = 250 * 1024; // tune this for performance
|
// const BUF_SIZE: usize = 250 * 1024; // tune this for performance
|
||||||
static mut BUF: Lazy<Vec<CPixel>> = Lazy::new(|| vec![const { CPixel::new() }; BUF_SIZE]);
|
// static mut BUF: Lazy<Vec<CPixel>> = Lazy::new(|| vec![const { CPixel::new() }; BUF_SIZE]);
|
||||||
|
|
||||||
pub struct Display;
|
pub struct Display;
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ pub mod display {
|
|||||||
unsafe { BUF[count] = p.into() };
|
unsafe { BUF[count] = p.into() };
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
||||||
if count == BUF_SIZE {
|
if count == BUF_SIZE - 1 {
|
||||||
abi_sys::draw_iter(unsafe { BUF.as_ptr() }, count);
|
abi_sys::draw_iter(unsafe { BUF.as_ptr() }, count);
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ use embedded_sdmmc::{DirEntry, LfnBuffer};
|
|||||||
use heapless::spsc::Queue;
|
use heapless::spsc::Queue;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display::{FB_PAUSED, FRAMEBUFFER},
|
display::FRAMEBUFFER,
|
||||||
|
framebuffer::FB_PAUSED,
|
||||||
storage::{Dir, File, SDCARD},
|
storage::{Dir, File, SDCARD},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ pub extern "C" fn get_ms() -> u64 {
|
|||||||
|
|
||||||
const _: LockDisplay = lock_display;
|
const _: LockDisplay = lock_display;
|
||||||
pub extern "C" fn lock_display(lock: bool) {
|
pub extern "C" fn lock_display(lock: bool) {
|
||||||
FB_PAUSED.store(lock, Ordering::Relaxed);
|
FB_PAUSED.store(lock, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: DrawIterAbi = draw_iter;
|
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 cpixels = unsafe { core::slice::from_raw_parts(cpixels, len) };
|
||||||
|
|
||||||
let iter = cpixels.iter().copied().map(|c: CPixel| c.into());
|
let iter = cpixels.iter().copied().map(|c: CPixel| c.into());
|
||||||
|
|
||||||
|
FB_PAUSED.store(true, Ordering::Release);
|
||||||
unsafe { FRAMEBUFFER.draw_iter(iter).unwrap() }
|
unsafe { FRAMEBUFFER.draw_iter(iter).unwrap() }
|
||||||
|
FB_PAUSED.store(false, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
pub static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ pub static mut FRAMEBUFFER: Lazy<AtomicFrameBuffer> = Lazy::new(|| {
|
|||||||
static mut BUF: [u16; framebuffer::SIZE] = [0; framebuffer::SIZE];
|
static mut BUF: [u16; framebuffer::SIZE] = [0; framebuffer::SIZE];
|
||||||
AtomicFrameBuffer::new(unsafe { &mut BUF })
|
AtomicFrameBuffer::new(unsafe { &mut BUF })
|
||||||
});
|
});
|
||||||
pub static FB_PAUSED: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
pub async fn init_display(
|
pub async fn init_display(
|
||||||
spi: Spi<'static, SPI1, Async>,
|
spi: Spi<'static, SPI1, Async>,
|
||||||
@@ -54,9 +53,7 @@ pub async fn init_display(
|
|||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn display_handler(mut display: DISPLAY) {
|
pub async fn display_handler(mut display: DISPLAY) {
|
||||||
loop {
|
loop {
|
||||||
if !FB_PAUSED.load(Ordering::Acquire) {
|
unsafe { FRAMEBUFFER.safe_draw(&mut display).await.unwrap() };
|
||||||
unsafe { FRAMEBUFFER.partial_draw(&mut display).await.unwrap() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// small yield to allow other tasks to run
|
// small yield to allow other tasks to run
|
||||||
Timer::after_nanos(100).await;
|
Timer::after_nanos(100).await;
|
||||||
|
|||||||
@@ -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
|
pub const TILE_COUNT: usize = (SCREEN_WIDTH / TILE_SIZE) * (SCREEN_HEIGHT / TILE_SIZE); // 400 tiles
|
||||||
|
|
||||||
// Group of tiles for batching
|
// 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<Rectangle, { TILE_COUNT / MAX_META_TILES }>;
|
type MetaTileVec = heapless::Vec<Rectangle, { TILE_COUNT / MAX_META_TILES }>;
|
||||||
|
|
||||||
pub const SIZE: usize = SCREEN_HEIGHT * SCREEN_WIDTH;
|
pub const SIZE: usize = SCREEN_HEIGHT * SCREEN_WIDTH;
|
||||||
|
|
||||||
|
pub static FB_PAUSED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
static mut DIRTY_TILES: LazyLock<heapless::Vec<AtomicBool, TILE_COUNT>> = LazyLock::new(|| {
|
static mut DIRTY_TILES: LazyLock<heapless::Vec<AtomicBool, TILE_COUNT>> = LazyLock::new(|| {
|
||||||
let mut tiles = heapless::Vec::new();
|
let mut tiles = heapless::Vec::new();
|
||||||
for _ in 0..TILE_COUNT {
|
for _ in 0..TILE_COUNT {
|
||||||
@@ -50,7 +52,7 @@ impl<'a> AtomicFrameBuffer<'a> {
|
|||||||
for ty in start_ty..=end_ty {
|
for ty in start_ty..=end_ty {
|
||||||
for tx in start_tx..=end_tx {
|
for tx in start_tx..=end_tx {
|
||||||
let tile_idx = ty * tiles_x + 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
|
// Grow horizontally, but keep under MAX_TILES_PER_METATILE
|
||||||
while tx + width_tiles < tiles_x
|
while tx + width_tiles < tiles_x
|
||||||
&& unsafe {
|
&& 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
|
&& (width_tiles + height_tiles) <= MAX_META_TILES
|
||||||
{
|
{
|
||||||
@@ -176,6 +178,57 @@ impl<'a> AtomicFrameBuffer<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn safe_draw<SPI, DC, RST, DELAY>(
|
||||||
|
&mut self,
|
||||||
|
display: &mut ST7365P<SPI, DC, RST, DELAY>,
|
||||||
|
) -> 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<u16, { TILE_SIZE * TILE_SIZE }> = 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
|
/// Sends only dirty tiles (16x16px) in batches to the display
|
||||||
pub async fn partial_draw<SPI, DC, RST, DELAY>(
|
pub async fn partial_draw<SPI, DC, RST, DELAY>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
BINARY_CH,
|
BINARY_CH, display::FRAMEBUFFER, elf::load_binary, framebuffer::FB_PAUSED,
|
||||||
display::{FB_PAUSED, FRAMEBUFFER},
|
peripherals::keyboard, storage::FileName,
|
||||||
elf::load_binary,
|
|
||||||
peripherals::keyboard,
|
|
||||||
storage::FileName,
|
|
||||||
};
|
};
|
||||||
use abi_sys::keyboard::{KeyCode, KeyState};
|
use abi_sys::keyboard::{KeyCode, KeyState};
|
||||||
use alloc::{str::FromStr, string::String, vec::Vec};
|
use alloc::{str::FromStr, string::String, vec::Vec};
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ pub fn main() {
|
|||||||
for frame in gif.frames() {
|
for frame in gif.frames() {
|
||||||
let start = get_ms();
|
let start = get_ms();
|
||||||
|
|
||||||
lock_display(true);
|
// lock_display(true);
|
||||||
frame.draw(&mut display).unwrap();
|
frame.draw(&mut display).unwrap();
|
||||||
lock_display(false);
|
// lock_display(false);
|
||||||
|
|
||||||
// frame_num += 1;
|
// frame_num += 1;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user