diff --git a/src/core/fbcon.c b/src/core/fbcon.c index df287078..72bfae2a 100644 --- a/src/core/fbcon.c +++ b/src/core/fbcon.c @@ -99,190 +99,7 @@ static void fbcon_set_default_background ( struct fbcon *fbcon ) { } /** - * Store character at specified position - * - * @v fbcon Frame buffer console - * @v cell Text cell - * @v xpos X position - * @v ypos Y position - */ -static void fbcon_store_character ( struct fbcon *fbcon, - struct fbcon_text_cell *cell, - unsigned int xpos, unsigned int ypos ) { - size_t offset; - - /* Store cell */ - offset = ( ( ( ypos * fbcon->character.width ) + xpos ) * - sizeof ( *cell ) ); - copy_to_user ( fbcon->text.start, offset, cell, sizeof ( *cell ) ); -} - -/** - * Draw character at specified position - * - * @v fbcon Frame buffer console - * @v cell Text cell - * @v xpos X position - * @v ypos Y position - */ -static void fbcon_draw_character ( struct fbcon *fbcon, - struct fbcon_text_cell *cell, - unsigned int xpos, unsigned int ypos ) { - static uint32_t black[FBCON_CHAR_WIDTH]; - struct fbcon_font_glyph glyph; - userptr_t picture_start; - size_t picture_offset; - size_t picture_stride; - size_t offset; - size_t pixel_len; - size_t skip_len; - unsigned int row; - unsigned int column; - uint8_t bitmask; - int transparent; - void *src; - - /* Get font character */ - copy_from_user ( &glyph, fbcon->font->start, - ( cell->character * sizeof ( glyph ) ), - sizeof ( glyph ) ); - - /* Calculate pixel geometry */ - offset = ( fbcon->indent + - ( ypos * fbcon->character.stride ) + - ( xpos * fbcon->character.len ) ); - pixel_len = fbcon->pixel->len; - skip_len = ( fbcon->pixel->stride - fbcon->character.len ); - - /* Calculate background picture geometry */ - if ( ( xpos < fbcon->picture.character.width ) && - ( ypos < fbcon->picture.character.height ) ) { - picture_start = fbcon->picture.start; - picture_offset = ( fbcon->picture.indent + - ( ypos * fbcon->picture.character.stride ) + - ( xpos * fbcon->picture.character.len ) ); - picture_stride = fbcon->picture.pixel.stride; - } else { - picture_start = virt_to_user ( black ); - picture_offset = 0; - picture_stride = 0; - } - assert ( fbcon->character.len <= sizeof ( black ) ); - - /* Check for transparent background colour */ - transparent = ( cell->background == FBCON_TRANSPARENT ); - - /* Draw character rows */ - for ( row = 0 ; row < FBCON_CHAR_HEIGHT ; row++ ) { - - /* Draw background picture */ - memcpy_user ( fbcon->start, offset, picture_start, - picture_offset, fbcon->character.len ); - - /* Draw character row */ - for ( column = FBCON_CHAR_WIDTH, bitmask = glyph.bitmask[row] ; - column ; column--, bitmask <<= 1, offset += pixel_len ) { - if ( bitmask & 0x80 ) { - src = &cell->foreground; - } else if ( ! transparent ) { - src = &cell->background; - } else { - continue; - } - copy_to_user ( fbcon->start, offset, src, pixel_len ); - } - - /* Move to next row */ - offset += skip_len; - picture_offset += picture_stride; - } -} - -/** - * Redraw margins - * - * @v fbcon Frame buffer console - */ -static void fbcon_redraw_margins ( struct fbcon *fbcon ) { - struct fbcon_picture *picture = &fbcon->picture; - size_t pixel_len = fbcon->pixel->len; - size_t offset = 0; - size_t picture_offset = 0; - size_t row_len; - size_t left_len; - size_t right_len; - size_t right_offset; - unsigned int y; - - /* Calculate margin parameters */ - row_len = ( picture->pixel.width * pixel_len ); - left_len = ( picture->margin.left * pixel_len ); - right_offset = ( picture->margin.right * pixel_len ); - right_len = ( ( picture->pixel.width - picture->margin.right ) * - pixel_len ); - - /* Redraw margins */ - for ( y = 0 ; y < picture->pixel.height ; y++ ) { - if ( ( y < picture->margin.top ) || - ( y >= picture->margin.bottom ) ) { - - /* Within top or bottom margin: draw whole row */ - memcpy_user ( fbcon->start, offset, picture->start, - picture_offset, row_len ); - - } else { - - /* Otherwise, draw left and right margins */ - memcpy_user ( fbcon->start, offset, picture->start, - picture_offset, left_len ); - memcpy_user ( fbcon->start, ( offset + right_offset ), - picture->start, - ( picture_offset + right_offset ), - right_len ); - } - offset += fbcon->pixel->stride; - picture_offset += picture->pixel.stride; - } -} - -/** - * Redraw characters - * - * @v fbcon Frame buffer console - */ -static void fbcon_redraw_characters ( struct fbcon *fbcon ) { - struct fbcon_text_cell cell; - size_t offset = 0; - unsigned int xpos; - unsigned int ypos; - - /* Redraw characters */ - for ( ypos = 0 ; ypos < fbcon->character.height ; ypos++ ) { - for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) { - copy_from_user ( &cell, fbcon->text.start, offset, - sizeof ( cell ) ); - fbcon_draw_character ( fbcon, &cell, xpos, ypos ); - offset += sizeof ( cell ); - } - } -} - -/** - * Redraw screen - * - * @v fbcon Frame buffer console - */ -static void fbcon_redraw ( struct fbcon *fbcon ) { - - /* Redraw margins */ - fbcon_redraw_margins ( fbcon ); - - /* Redraw characters */ - fbcon_redraw_characters ( fbcon ); -} - -/** - * Clear portion of screen + * Clear rows of characters * * @v fbcon Frame buffer console * @v ypos Starting Y position @@ -305,9 +122,114 @@ static void fbcon_clear ( struct fbcon *fbcon, unsigned int ypos ) { offset += sizeof ( cell ); } } +} - /* Redraw screen */ - fbcon_redraw ( fbcon ); +/** + * Store character at specified position + * + * @v fbcon Frame buffer console + * @v cell Text cell + * @v xpos X position + * @v ypos Y position + */ +static void fbcon_store ( struct fbcon *fbcon, struct fbcon_text_cell *cell, + unsigned int xpos, unsigned int ypos ) { + size_t offset; + + /* Store cell */ + offset = ( ( ( ypos * fbcon->character.width ) + xpos ) * + sizeof ( *cell ) ); + copy_to_user ( fbcon->text.start, offset, cell, sizeof ( *cell ) ); +} + +/** + * Draw character at specified position + * + * @v fbcon Frame buffer console + * @v cell Text cell + * @v xpos X position + * @v ypos Y position + */ +static void fbcon_draw ( struct fbcon *fbcon, struct fbcon_text_cell *cell, + unsigned int xpos, unsigned int ypos ) { + struct fbcon_font_glyph glyph; + size_t offset; + size_t pixel_len; + size_t skip_len; + unsigned int row; + unsigned int column; + uint8_t bitmask; + int transparent; + void *src; + + /* Get font character */ + copy_from_user ( &glyph, fbcon->font->start, + ( cell->character * sizeof ( glyph ) ), + sizeof ( glyph ) ); + + /* Calculate pixel geometry */ + offset = ( fbcon->indent + + ( ypos * fbcon->character.stride ) + + ( xpos * fbcon->character.len ) ); + pixel_len = fbcon->pixel->len; + skip_len = ( fbcon->pixel->stride - fbcon->character.len ); + + /* Check for transparent background colour */ + transparent = ( cell->background == FBCON_TRANSPARENT ); + + /* Draw character rows */ + for ( row = 0 ; row < FBCON_CHAR_HEIGHT ; row++ ) { + + /* Draw background picture, if applicable */ + if ( transparent ) { + if ( fbcon->picture.start ) { + memcpy_user ( fbcon->start, offset, + fbcon->picture.start, offset, + fbcon->character.len ); + } else { + memset_user ( fbcon->start, offset, 0, + fbcon->character.len ); + } + } + + /* Draw character row */ + for ( column = FBCON_CHAR_WIDTH, bitmask = glyph.bitmask[row] ; + column ; column--, bitmask <<= 1, offset += pixel_len ) { + if ( bitmask & 0x80 ) { + src = &cell->foreground; + } else if ( ! transparent ) { + src = &cell->background; + } else { + continue; + } + copy_to_user ( fbcon->start, offset, src, pixel_len ); + } + + /* Move to next row */ + offset += skip_len; + } +} + +/** + * Redraw all characters + * + * @v fbcon Frame buffer console + */ +static void fbcon_redraw ( struct fbcon *fbcon ) { + struct fbcon_text_cell cell; + size_t offset = 0; + unsigned int xpos; + unsigned int ypos; + + /* Redraw characters */ + for ( ypos = 0 ; ypos < fbcon->character.height ; ypos++ ) { + for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) { + copy_from_user ( &cell, fbcon->text.start, offset, + sizeof ( cell ) ); + fbcon_draw ( fbcon, &cell, xpos, ypos ); + offset += sizeof ( cell ); + } + } } /** @@ -329,6 +251,9 @@ static void fbcon_scroll ( struct fbcon *fbcon ) { /* Update cursor position */ fbcon->ypos--; + + /* Redraw all characters */ + fbcon_redraw ( fbcon ); } /** @@ -349,7 +274,7 @@ static void fbcon_draw_cursor ( struct fbcon *fbcon, int show_cursor ) { cell.foreground = ( ( fbcon->background == FBCON_TRANSPARENT ) ? 0 : fbcon->background ); } - fbcon_draw_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); + fbcon_draw ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); } /** @@ -391,9 +316,12 @@ static void fbcon_handle_ed ( struct ansiesc_context *ctx, /* We assume that we always clear the whole screen */ assert ( params[0] == ANSIESC_ED_ALL ); - /* Clear screen */ + /* Clear character array */ fbcon_clear ( fbcon, 0 ); + /* Redraw all characters */ + fbcon_redraw ( fbcon ); + /* Reset cursor position */ fbcon->xpos = 0; fbcon->ypos = 0; @@ -541,8 +469,8 @@ void fbcon_putchar ( struct fbcon *fbcon, int character ) { cell.foreground = ( fbcon->foreground | fbcon->bold ); cell.background = fbcon->background; cell.character = character; - fbcon_store_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos); - fbcon_draw_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); + fbcon_store ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); + fbcon_draw ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); /* Advance cursor */ fbcon->xpos++; @@ -561,72 +489,6 @@ void fbcon_putchar ( struct fbcon *fbcon, int character ) { fbcon_draw_cursor ( fbcon, fbcon->show_cursor ); } -/** - * Calculate character geometry from pixel geometry - * - * @v pixel Pixel geometry - * @v character Character geometry to fill in - */ -static void fbcon_char_geometry ( const struct fbcon_geometry *pixel, - struct fbcon_geometry *character ) { - - character->width = ( pixel->width / FBCON_CHAR_WIDTH ); - character->height = ( pixel->height / FBCON_CHAR_HEIGHT ); - character->len = ( pixel->len * FBCON_CHAR_WIDTH ); - character->stride = ( pixel->stride * FBCON_CHAR_HEIGHT ); -} - -/** - * Calculate margins from pixel geometry - * - * @v pixel Pixel geometry - * @v margin Margins to fill in - */ -static void fbcon_margin ( const struct fbcon_geometry *pixel, - struct fbcon_margin *margin ) { - unsigned int xgap; - unsigned int ygap; - - xgap = ( pixel->width % FBCON_CHAR_WIDTH ); - ygap = ( pixel->height % FBCON_CHAR_HEIGHT ); - margin->left = ( xgap / 2 ); - margin->top = ( ygap / 2 ); - margin->right = ( pixel->width - ( xgap - margin->left ) ); - margin->bottom = ( pixel->height - ( ygap - margin->top ) ); -} - -/** - * Align to first indented boundary - * - * @v value Original value - * @v blocksize Block size - * @v indent Indent - * @v max Maximum allowed value - * @ret value Aligned value - */ -static unsigned int fbcon_align ( unsigned int value, unsigned int blocksize, - unsigned int indent, unsigned int max ) { - unsigned int overhang; - - /* Special case: 0 is always a boundary regardless of the indent */ - if ( value == 0 ) - return value; - - /* Special case: first boundary is the indent */ - if ( value < indent ) - return indent; - - /* Round up to next indented boundary */ - overhang = ( ( value - indent ) % blocksize ); - value = ( value + ( ( blocksize - overhang ) % blocksize ) ); - - /* Limit to maximum value */ - if ( value > max ) - value = max; - - return value; -} - /** * Initialise background picture * @@ -636,52 +498,26 @@ static unsigned int fbcon_align ( unsigned int value, unsigned int blocksize, */ static int fbcon_picture_init ( struct fbcon *fbcon, struct pixel_buffer *pixbuf ) { + struct fbcon_geometry *pixel = fbcon->pixel; struct fbcon_picture *picture = &fbcon->picture; - size_t pixel_len = fbcon->pixel->len; size_t len; + size_t pixbuf_stride; + size_t indent; + size_t pixbuf_indent; size_t offset; size_t pixbuf_offset; uint32_t rgb; uint32_t raw; unsigned int x; unsigned int y; + unsigned int width; + unsigned int height; + int xgap; + int ygap; int rc; - /* Calculate pixel geometry */ - picture->pixel.width = fbcon_align ( pixbuf->width, FBCON_CHAR_WIDTH, - fbcon->margin.left, - fbcon->pixel->width ); - picture->pixel.height = fbcon_align ( pixbuf->height, FBCON_CHAR_HEIGHT, - fbcon->margin.top, - fbcon->pixel->height ); - picture->pixel.len = pixel_len; - picture->pixel.stride = ( picture->pixel.width * picture->pixel.len ); - - /* Calculate character geometry */ - fbcon_char_geometry ( &picture->pixel, &picture->character ); - - /* Calculate margins */ - memcpy ( &picture->margin, &fbcon->margin, sizeof ( picture->margin ) ); - if ( picture->margin.left > picture->pixel.width ) - picture->margin.left = picture->pixel.width; - if ( picture->margin.top > picture->pixel.height ) - picture->margin.top = picture->pixel.height; - if ( picture->margin.right > picture->pixel.width ) - picture->margin.right = picture->pixel.width; - if ( picture->margin.bottom > picture->pixel.height ) - picture->margin.bottom = picture->pixel.height; - picture->indent = ( ( picture->margin.top * picture->pixel.stride ) + - ( picture->margin.left * picture->pixel.len ) ); - DBGC ( fbcon, "FBCON %p picture is pixel %dx%d, char %dx%d at " - "[%d-%d),[%d-%d)\n", fbcon, picture->pixel.width, - picture->pixel.height, picture->character.width, - picture->character.height, picture->margin.left, - picture->margin.right, picture->margin.top, - picture->margin.bottom ); - /* Allocate buffer */ - len = ( picture->pixel.width * picture->pixel.height * - picture->pixel.len ); + len = ( pixel->height * pixel->stride ); picture->start = umalloc ( len ); if ( ! picture->start ) { DBGC ( fbcon, "FBCON %p could not allocate %zd bytes for " @@ -690,20 +526,36 @@ static int fbcon_picture_init ( struct fbcon *fbcon, goto err_umalloc; } + /* Centre picture on console */ + pixbuf_stride = ( pixbuf->width * sizeof ( rgb ) ); + xgap = ( ( ( int ) ( pixel->width - pixbuf->width ) ) / 2 ); + ygap = ( ( ( int ) ( pixel->height - pixbuf->height ) ) / 2 ); + indent = ( ( ( ( ygap >= 0 ) ? ygap : 0 ) * pixel->stride ) + + ( ( ( xgap >= 0 ) ? xgap : 0 ) * pixel->len ) ); + pixbuf_indent = ( ( ( ( ygap < 0 ) ? -ygap : 0 ) * pixbuf_stride ) + + ( ( ( xgap < 0 ) ? -xgap : 0 ) * sizeof ( rgb ) ) ); + width = pixbuf->width; + if ( width > pixel->width ) + width = pixel->width; + height = pixbuf->height; + if ( height > pixel->height ) + height = pixel->height; + DBGC ( fbcon, "FBCON %p picture is pixel %dx%d at [%d,%d),[%d,%d)\n", + fbcon, width, height, xgap, ( xgap + pixbuf->width ), ygap, + ( ygap + pixbuf->height ) ); + /* Convert to frame buffer raw format */ memset_user ( picture->start, 0, 0, len ); - pixbuf_offset = 0; - for ( y = 0 ; ( y < pixbuf->height ) && - ( y < picture->pixel.height ) ; y++ ) { - offset = ( y * picture->pixel.stride ); - pixbuf_offset = ( y * pixbuf->width * sizeof ( rgb ) ); - for ( x = 0 ; ( x < pixbuf->width ) && - ( x < picture->pixel.width ) ; x++ ) { + for ( y = 0 ; y < height ; y++ ) { + offset = ( indent + ( y * pixel->stride ) ); + pixbuf_offset = ( pixbuf_indent + ( y * pixbuf_stride ) ); + for ( x = 0 ; x < width ; x++ ) { copy_from_user ( &rgb, pixbuf->data, pixbuf_offset, sizeof ( rgb ) ); raw = fbcon_colour ( fbcon, rgb ); - copy_to_user ( picture->start, offset, &raw, pixel_len); - offset += pixel_len; + copy_to_user ( picture->start, offset, &raw, + pixel->len ); + offset += pixel->len; pixbuf_offset += sizeof ( rgb ); } } @@ -731,6 +583,8 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start, struct fbcon_colour_map *map, struct fbcon_font *font, struct pixel_buffer *pixbuf ) { + unsigned int xgap; + unsigned int ygap; int rc; /* Initialise data structure */ @@ -750,21 +604,33 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start, user_to_phys ( fbcon->start, fbcon->len ) ); /* Derive character geometry from pixel geometry */ - fbcon_char_geometry ( pixel, &fbcon->character ); - fbcon_margin ( pixel, &fbcon->margin ); + fbcon->character.width = ( pixel->width / FBCON_CHAR_WIDTH ); + fbcon->character.height = ( pixel->height / FBCON_CHAR_HEIGHT ); + fbcon->character.len = ( pixel->len * FBCON_CHAR_WIDTH ); + fbcon->character.stride = ( pixel->stride * FBCON_CHAR_HEIGHT ); + + /* Calculate margin */ + xgap = ( pixel->width % FBCON_CHAR_WIDTH ); + ygap = ( pixel->height % FBCON_CHAR_HEIGHT ); + fbcon->margin.left = ( xgap / 2 ); + fbcon->margin.top = ( ygap / 2 ); + fbcon->margin.right = ( xgap - fbcon->margin.left ); + fbcon->margin.bottom = ( ygap - fbcon->margin.top ); fbcon->indent = ( ( fbcon->margin.top * pixel->stride ) + ( fbcon->margin.left * pixel->len ) ); DBGC ( fbcon, "FBCON %p is pixel %dx%d, char %dx%d at " "[%d-%d),[%d-%d)\n", fbcon, fbcon->pixel->width, fbcon->pixel->height, fbcon->character.width, - fbcon->character.height, fbcon->margin.left, fbcon->margin.right, - fbcon->margin.top, fbcon->margin.bottom ); + fbcon->character.height, fbcon->margin.left, + ( fbcon->pixel->width - fbcon->margin.right ), + fbcon->margin.top, + ( fbcon->pixel->height - fbcon->margin.bottom ) ); /* Set default colours */ fbcon_set_default_foreground ( fbcon ); fbcon_set_default_background ( fbcon ); - /* Allocate stored character array */ + /* Allocate and initialise stored character array */ fbcon->text.start = umalloc ( fbcon->character.width * fbcon->character.height * sizeof ( struct fbcon_text_cell ) ); @@ -772,13 +638,20 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start, rc = -ENOMEM; goto err_text; } + fbcon_clear ( fbcon, 0 ); + + /* Set framebuffer to all black (including margins) */ + memset_user ( fbcon->start, 0, 0, fbcon->len ); /* Generate pixel buffer from background image, if applicable */ if ( pixbuf && ( ( rc = fbcon_picture_init ( fbcon, pixbuf ) ) != 0 ) ) goto err_picture; - /* Clear screen */ - fbcon_clear ( fbcon, 0 ); + /* Draw background picture (including margins), if applicable */ + if ( fbcon->picture.start ) { + memcpy_user ( fbcon->start, 0, fbcon->picture.start, 0, + fbcon->len ); + } /* Update console width and height */ console_set_size ( fbcon->character.width, fbcon->character.height ); diff --git a/src/include/ipxe/fbcon.h b/src/include/ipxe/fbcon.h index 603e52ca..007e7e72 100644 --- a/src/include/ipxe/fbcon.h +++ b/src/include/ipxe/fbcon.h @@ -103,14 +103,6 @@ struct fbcon_text { struct fbcon_picture { /** Start address */ userptr_t start; - /** Pixel geometry */ - struct fbcon_geometry pixel; - /** Character geometry */ - struct fbcon_geometry character; - /** Margin */ - struct fbcon_margin margin; - /** Indent to first character (in bytes) */ - size_t indent; }; /** A frame buffer console */