From 76a17b0986250117e15c2c64cccd0694acf8142b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 25 Apr 2025 13:24:21 +0100 Subject: [PATCH] [fbcon] Avoid redrawing unchanged characters when scrolling Scrolling currently involves redrawing every character cell, which can be frustratingly slow on large framebuffer consoles. Accelerate this operation by skipping the redraw for any unchanged character cells. In the common case that large areas of the screen contain whitespace, this optimises away the vast majority of the redrawing operations. Signed-off-by: Michael Brown --- src/core/fbcon.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/core/fbcon.c b/src/core/fbcon.c index f2b2ea566..43f73fbac 100644 --- a/src/core/fbcon.c +++ b/src/core/fbcon.c @@ -233,22 +233,46 @@ static void fbcon_redraw ( struct fbcon *fbcon ) { * @v fbcon Frame buffer console */ static void fbcon_scroll ( struct fbcon *fbcon ) { - size_t row_len; + const struct fbcon_text_cell *old; + struct fbcon_text_cell *new; + unsigned int xpos; + unsigned int ypos; + unsigned int character; + uint32_t foreground; + uint32_t background; /* Sanity check */ assert ( fbcon->ypos == fbcon->character.height ); /* Scroll up character array */ - row_len = ( fbcon->character.width * sizeof ( fbcon->text.cells[0] ) ); - memmove ( fbcon_cell ( fbcon, 0, 0 ), fbcon_cell ( fbcon, 0, 1 ), - ( row_len * ( fbcon->character.height - 1 ) ) ); - fbcon_clear ( fbcon, ( fbcon->character.height - 1 ) ); + new = fbcon_cell ( fbcon, 0, 0 ); + old = fbcon_cell ( fbcon, 0, 1 ); + for ( ypos = 0 ; ypos < ( fbcon->character.height - 1 ) ; ypos++ ) { + for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) { + /* Redraw character (if changed) */ + character = old->character; + foreground = old->foreground; + background = old->background; + if ( ( new->character != character ) || + ( new->foreground != foreground ) || + ( new->background != background ) ) { + new->character = character; + new->foreground = foreground; + new->background = background; + fbcon_draw ( fbcon, new, xpos, ypos ); + } + new++; + old++; + } + } + + /* Clear bottom row */ + fbcon_clear ( fbcon, ypos ); + for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) + fbcon_draw ( fbcon, new++, xpos, ypos ); /* Update cursor position */ fbcon->ypos--; - - /* Redraw all characters */ - fbcon_redraw ( fbcon ); } /**