From ea13d36710bcb5a4502fe2281528665ee5ac61cd Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 13 Sep 2006 13:37:00 -0700 Subject: [PATCH] Beginnings of supporting multiple pixel formats --- com32/lib/sys/vesa/drawtxt.c | 65 +++++++++++++++++++++++++++++++++++-------- com32/lib/sys/vesa/initvesa.c | 49 ++++++++++++++++++++++---------- com32/lib/sys/vesa/video.h | 4 ++- 3 files changed, 91 insertions(+), 27 deletions(-) diff --git a/com32/lib/sys/vesa/drawtxt.c b/com32/lib/sys/vesa/drawtxt.c index ddb1720..08b0e91 100644 --- a/com32/lib/sys/vesa/drawtxt.c +++ b/com32/lib/sys/vesa/drawtxt.c @@ -29,6 +29,7 @@ #include #include "vesa.h" #include "video.h" +#include "fmtpixel.h" /* * Visible cursor information @@ -72,15 +73,37 @@ static void vesacon_update_characters(int row, int col, int nrows, int ncols) { const int height = __vesacon_font_height; const int width = FONT_WIDTH; - uint32_t *bgrowptr, *bgptr, *fbrowptr, *fbptr, bgval, fgval; + uint32_t *bgrowptr, *bgptr, bgval, fgval; uint32_t fgcolor = 0, bgcolor = 0, color; uint8_t chbits = 0, chxbits = 0, chsbits = 0; int i, j, pixrow, pixsrow; struct vesa_char *rowptr, *rowsptr, *cptr, *csptr; - + unsigned long pixel_offset, bytes_per_pixel, bytes_per_row; + uint8_t row_buffer[VIDEO_X_SIZE*4], *rowbufptr; + uint8_t *fbrowptr; + bgrowptr = &__vesacon_background[row*height+VIDEO_BORDER][col*width+VIDEO_BORDER]; - fbrowptr = ((uint32_t *)__vesa_info.mi.lfb_ptr)+ - ((row*height+VIDEO_BORDER)*VIDEO_X_SIZE)+(col*width+VIDEO_BORDER); + + pixel_offset = ((row*height+VIDEO_BORDER)*VIDEO_X_SIZE)+ + (col*width+VIDEO_BORDER); + + switch (__vesacon_pixel_format) { + case PXF_BGR24: + bytes_per_pixel = 3; + break; + case PXF_BGRA32: + bytes_per_pixel = 4; + break; + case PXF_LE_RGB16_565: + bytes_per_pixel = 2; + break; + default: + bytes_per_pixel = 0; + break; + } + + bytes_per_row = bytes_per_pixel*VIDEO_X_SIZE; + fbrowptr = ((uint8_t *)__vesa_info.mi.lfb_ptr)+pixel_offset*bytes_per_pixel; /* Note that we keep a 1-character guard area around the real text area... */ rowptr = &__vesacon_text_display[(row+1)*(TEXT_PIXEL_COLS/FONT_WIDTH+2)+(col+1)]; @@ -90,7 +113,7 @@ static void vesacon_update_characters(int row, int col, int nrows, int ncols) for (i = height*nrows; i >= 0; i--) { bgptr = bgrowptr; - fbptr = fbrowptr; + rowbufptr = row_buffer; cptr = rowptr; csptr = rowsptr; @@ -100,16 +123,21 @@ static void vesacon_update_characters(int row, int col, int nrows, int ncols) chsbits |= cursor_pattern[pixsrow]; chsbits &= (csptr->sha & 0x02) ? 0xff : 0x00; chsbits ^= (csptr->sha & 0x01) ? 0xff : 0x00; - chsbits <<= 6; + chsbits <<= (width-2); csptr++; - for (j = width*ncols; j >= 0; j--) { + /* Draw two pixels beyond the end of the line. One for the shadow, + and one to make sure we have a whole dword of data for the copy + operation at the end. Note that this code depends on the fact that + all characters begin on dword boundaries in the frame buffer. */ + + for (j = width*ncols+1; j >= 0; j--) { chbits <<= 1; chsbits <<= 1; chxbits <<= 1; - switch (j % FONT_WIDTH) { - case 0: + switch (j % width) { + case 1: chbits = __vesacon_graphics_font[cptr->ch][pixrow]; if (__unlikely(cptr == cursor_pointer)) chbits |= cursor_pattern[pixrow]; @@ -120,7 +148,7 @@ static void vesacon_update_characters(int row, int col, int nrows, int ncols) bgcolor = console_color_table[cptr->attr].argb_bg; cptr++; break; - case FONT_WIDTH-1: + case 0: chsbits = __vesacon_graphics_font[csptr->ch][pixsrow]; if (__unlikely(csptr == cursor_pointer)) chsbits |= cursor_pattern[pixsrow]; @@ -148,11 +176,24 @@ static void vesacon_update_characters(int row, int col, int nrows, int ncols) color &= 0x3f3f3f; } - *fbptr++ = color; + rowbufptr = format_pixel(rowbufptr, color, __vesacon_pixel_format); + } + + /* Copy to frame buffer */ + { + void *fb_ptr = fbrowptr; + void *rb_ptr = row_buffer; + unsigned int dword_count = (rowbufptr-row_buffer) >> 2; + + /* Note that the dword_count is rounded down, not up. That's because + the row_buffer includes a spillover pixel. */ + + asm volatile("cld; rep; movsl" + : "+D" (fb_ptr), "+S" (rb_ptr), "+c" (dword_count)); } bgrowptr += VIDEO_X_SIZE; - fbrowptr += VIDEO_X_SIZE; + fbrowptr += bytes_per_row; if (++pixrow == height) { rowptr += TEXT_PIXEL_COLS/FONT_WIDTH+2; diff --git a/com32/lib/sys/vesa/initvesa.c b/com32/lib/sys/vesa/initvesa.c index c42a7b3..ebef304 100644 --- a/com32/lib/sys/vesa/initvesa.c +++ b/com32/lib/sys/vesa/initvesa.c @@ -47,6 +47,7 @@ struct vesa_info __vesa_info; struct vesa_char *__vesacon_text_display; int __vesacon_font_height, __vesacon_text_rows; +enum vesa_pixel_format __vesacon_pixel_format; uint8_t __vesacon_graphics_font[FONT_MAX_CHARS][FONT_MAX_HEIGHT]; uint32_t __vesacon_background[VIDEO_Y_SIZE][VIDEO_X_SIZE]; @@ -90,9 +91,10 @@ static int vesacon_set_mode(void) { com32sys_t rm; uint8_t *rom_font; - uint16_t mode, *mode_ptr; + uint16_t mode, bestmode, *mode_ptr; struct vesa_general_info *gi; struct vesa_mode_info *mi; + enum vesa_pixel_format pxf, bestpxf; /* Allocate space in the bounce buffer for these structures */ gi = &((struct vesa_info *)__com32.cs_bounce)->gi; @@ -118,11 +120,10 @@ static int vesacon_set_mode(void) /* Search for a 640x480 32-bit linear frame buffer mode */ mode_ptr = GET_PTR(gi->video_mode_ptr); + bestmode = 0; + bestpxf = PXF_NONE; - for(;;) { - if ((mode = *mode_ptr++) == 0xFFFF) - return 4; /* No mode found */ - + while ((mode = *mode_ptr++) != 0xFFFF) { debug("Found mode: 0x%04x\r\n", mode); rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ @@ -142,21 +143,41 @@ static int vesacon_set_mode(void) /* Must be an LFB color graphics mode supported by the hardware */ if ( (mi->mode_attr & 0x0099) != 0x0099 ) continue; + /* Must be 640x480, 32 bpp */ - if ( mi->h_res != VIDEO_X_SIZE || mi->v_res != VIDEO_Y_SIZE || - mi->bpp != 32 ) + if ( mi->h_res != VIDEO_X_SIZE || mi->v_res != VIDEO_Y_SIZE ) continue; + /* Must either be a packed-pixel mode or a direct color mode (depending on VESA version ) */ - if ( mi->memory_layout != 4 && /* Packed pixel */ - (mi->memory_layout != 6 || mi->rpos != 16 || - mi->gpos != 8 || mi->bpos != 0) ) - continue; - - /* Hey, looks like we found something we can live with */ - break; + if (mi->bpp == 32 && + (mi->memory_layout == 4 || + (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 && + mi->bpos == 0))) + pxf = PXF_BGRA32; + else if (mi->bpp == 24 && + (mi->memory_layout == 4 || + (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 && + mi->bpos == 0))) + pxf = PXF_BGR24; + else if (mi->bpp == 16 && + (mi->memory_layout == 4 || + (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 && + mi->bpos == 0))) + pxf = PXF_LE_RGB16_565; + else + pxf = PXF_NONE; /* Not a usable mode for us */ + + if (pxf < bestpxf) { + /* Best mode so far... */ + bestmode = mode; + bestpxf = pxf; + } } + if (bestpxf == PXF_NONE) + return 4; /* No mode found */ + /* Download the SYSLINUX- or BIOS-provided font */ rm.eax.w[0] = 0x0018; /* Query custom font */ __intcall(0x22, &rm, &rm); diff --git a/com32/lib/sys/vesa/video.h b/com32/lib/sys/vesa/video.h index 3bf93e3..ab3c765 100644 --- a/com32/lib/sys/vesa/video.h +++ b/com32/lib/sys/vesa/video.h @@ -52,9 +52,10 @@ struct vesa_char { }; /* Pixel formats in order of decreasing preference; PXF_NONE should be last */ +/* BGR24 is preferred over BGRA32 since the I/O overhead is smaller. */ enum vesa_pixel_format { - PXF_BGRA32, /* 32-bit BGRA */ PXF_BGR24, /* 24-bit BGR */ + PXF_BGRA32, /* 32-bit BGRA */ PXF_LE_RGB16_565, /* 16-bit littleendian 5:6:5 RGB */ PXF_NONE }; @@ -62,6 +63,7 @@ enum vesa_pixel_format { extern struct vesa_char *__vesacon_text_display; extern int __vesacon_font_height, __vesacon_text_rows; +extern enum vesa_pixel_format __vesacon_pixel_format; extern uint8_t __vesacon_graphics_font[FONT_MAX_CHARS][FONT_MAX_HEIGHT]; extern uint32_t __vesacon_background[VIDEO_Y_SIZE][VIDEO_X_SIZE]; extern uint32_t __vesacon_shadowfb[VIDEO_Y_SIZE][VIDEO_X_SIZE]; -- 2.7.4