From a4316e2aa71c282d646c84b1dc4fa9df80d4854e Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 24 May 2026 00:45:13 +0800 Subject: [PATCH] add dry-run api to gfx dry-runs are useful for warming up "hot paths" in UI code to improve latency. This is specifically a feature for tuning interactions on systems that have swap memory. --- libs/ux-api/src/service/api.rs | 4 ++++ libs/ux-api/src/service/gfx.rs | 15 +++++++++++++++ services/bao-video/src/main.rs | 23 +++++++++++++++++------ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/libs/ux-api/src/service/api.rs b/libs/ux-api/src/service/api.rs index 344dfc561..8da3d1ecc 100644 --- a/libs/ux-api/src/service/api.rs +++ b/libs/ux-api/src/service/api.rs @@ -117,6 +117,10 @@ pub enum GfxOpcode { Brightness, #[cfg(feature = "board-baosec")] FlipScreen, + /// This is used to toggle DryRun mode. The purpose of this mode is to + /// warm up UI routines from swap memory to improve UI latency. + #[cfg(feature = "board-baosec")] + DryRun, /// Gutter for invalid calls InvalidCall, diff --git a/libs/ux-api/src/service/gfx.rs b/libs/ux-api/src/service/gfx.rs index 1c88a073e..3222b68d4 100644 --- a/libs/ux-api/src/service/gfx.rs +++ b/libs/ux-api/src/service/gfx.rs @@ -848,6 +848,21 @@ impl Gfx { .map(|_| ()) } + #[cfg(feature = "board-baosec")] + pub fn dry_run(&self, dry_run: bool) -> Result<(), xous::Error> { + send_message( + self.conn, + Message::new_blocking_scalar( + GfxOpcode::DryRun.to_usize().unwrap(), + if dry_run { 1 } else { 0 }, + 0, + 0, + 0, + ), + ) + .map(|_| ()) + } + #[cfg(feature = "hosted-baosec")] pub fn acquire_qr(&self) -> Result { let dummy = "otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30".to_string(); diff --git a/services/bao-video/src/main.rs b/services/bao-video/src/main.rs index ea6f9f744..b291de921 100644 --- a/services/bao-video/src/main.rs +++ b/services/bao-video/src/main.rs @@ -433,6 +433,7 @@ pub fn wrapped_main(main_thread_token: MainThreadToken) -> ! { let mut qr_request: Option = None; let mut kbd_listeners: Vec<(CID, usize)> = Vec::new(); let cam_started = Arc::new(AtomicBool::new(false)); + let mut dry_run = false; #[allow(unused_mut)] let mut orientation = DisplayOrientation::Normal; loop { @@ -851,9 +852,11 @@ pub fn wrapped_main(main_thread_token: MainThreadToken) -> ! { GfxOpcode::Flush => { if qr_request.is_none() { log::trace!("***gfx flush*** redraw##"); - display - .redraw() - .unwrap_or_else(|_| display_timeout_handler(&udma_global, &mut display)); + if !dry_run { + display + .redraw() + .unwrap_or_else(|_| display_timeout_handler(&udma_global, &mut display)); + } } } GfxOpcode::Clear => { @@ -1001,12 +1004,20 @@ pub fn wrapped_main(main_thread_token: MainThreadToken) -> ! { display .flip_vertical(scalar.arg1 != 0) .unwrap_or_else(|_| display_timeout_handler(&udma_global, &mut display)); - display - .redraw() - .unwrap_or_else(|_| display_timeout_handler(&udma_global, &mut display)); + if !dry_run { + display + .redraw() + .unwrap_or_else(|_| display_timeout_handler(&udma_global, &mut display)); + } } } } + #[cfg(feature = "board-baosec")] + GfxOpcode::DryRun => { + if let Some(scalar) = msg.body.scalar_message_mut() { + dry_run = scalar.arg1 != 0; + } + } GfxOpcode::Quit => { log::info!("refusing to quit, this operation is not supported on this platform!"); }