From f0ff6a7976c7359aba8e6ee08059ea5f2de915c3 Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 6 Jul 2026 23:06:03 +0300 Subject: [PATCH] fix(fbcond): buffer TextScreen writes while display map is unavailable fbcond can start before vesad has registered the display, leaving TextScreen.display.map as None. The old write() silently dropped all output in that state, so getty/login prompts written during the race window never appeared. - Add pending_writes buffer to TextScreen. - Buffer writes when display.map is None and log a warning. - Flush buffered writes after a successful display handoff. - Upgrade handoff success logs from debug to info so they appear in the default boot log. --- drivers/graphics/fbcond/src/display.rs | 4 +-- drivers/graphics/fbcond/src/text.rs | 39 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/graphics/fbcond/src/display.rs b/drivers/graphics/fbcond/src/display.rs index eb09b97e9c..186af4bf85 100644 --- a/drivers/graphics/fbcond/src/display.rs +++ b/drivers/graphics/fbcond/src/display.rs @@ -33,11 +33,11 @@ impl Display { }; let new_display_handle = V2GraphicsHandle::from_file(display_file).unwrap(); - log::debug!("fbcond: Opened new display"); + log::info!("fbcond: Opened new display"); match V2DisplayMap::new(new_display_handle) { Ok(map) => { - log::debug!( + log::info!( "fbcond: Mapped new display with size {}x{}", map.buffer.buffer().size().0, map.buffer.buffer().size().1, diff --git a/drivers/graphics/fbcond/src/text.rs b/drivers/graphics/fbcond/src/text.rs index 8a24bbebe6..ddb77d657c 100644 --- a/drivers/graphics/fbcond/src/text.rs +++ b/drivers/graphics/fbcond/src/text.rs @@ -10,6 +10,7 @@ pub struct TextScreen { inner: console_draw::TextScreen, ctrl: bool, input: VecDeque, + pending_writes: Vec>, } impl TextScreen { @@ -19,12 +20,16 @@ impl TextScreen { inner: console_draw::TextScreen::new(), ctrl: false, input: VecDeque::new(), + pending_writes: Vec::new(), } } pub fn handle_handoff(&mut self) { log::info!("fbcond: Performing handoff"); self.display.reopen_for_handoff(); + if self.display.map.is_some() { + self.flush_pending_writes(); + } } pub fn input(&mut self, event: &Event) { @@ -127,8 +132,42 @@ impl TextScreen { let damage = self.inner.write(map, buf, &mut self.input); self.display.sync_rect(damage); + } else { + log::warn!( + "fbcond: TextScreen::write() called while display map is None; \ + buffering {} bytes ({} pending chunks). Will flush after handoff.", + buf.len(), + self.pending_writes.len() + 1, + ); + self.pending_writes.push(buf.to_vec()); } Ok(buf.len()) } + + pub fn flush_pending_writes(&mut self) { + if self.pending_writes.is_empty() { + return; + } + + let count = self.pending_writes.len(); + log::info!( + "fbcond: Flushing {} pending write chunks after display handoff", + count, + ); + + if let Some(map) = &mut self.display.map { + for pending in self.pending_writes.drain(..) { + Display::handle_resize(map, &mut self.inner); + let damage = self.inner.write(map, &pending, &mut self.input); + map.dirty_fb(damage).unwrap(); + } + } else { + log::error!( + "fbcond: flush_pending_writes called but display map is still None; \ + keeping {} buffered chunks", + self.pending_writes.len(), + ); + } + } }