[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 <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-04-25 13:24:21 +01:00
parent aa3cc56ab2
commit 76a17b0986

View File

@@ -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 );
}
/**