From 185b1c3a6c1f3ba8566507f1d8fe555480495a9c Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 28 Aug 2006 00:28:31 -0700 Subject: [PATCH] More work on VESA graphical console support --- com32/lib/Makefile | 10 ++- com32/lib/sys/vesa/background.c | 171 ++++++++++++++++++++++++++++++++++++++++ com32/lib/sys/vesa/drawtxt.c | 148 ++++++++++++++++++++++++++++++++++ com32/lib/sys/vesa/initvesa.c | 156 +++++++++++++++++++++++++++++++++--- com32/lib/sys/vesa/video.h | 29 ++++++- 5 files changed, 502 insertions(+), 12 deletions(-) create mode 100644 com32/lib/sys/vesa/background.c create mode 100644 com32/lib/sys/vesa/drawtxt.c diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 0f65852..cfbeeb2 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -33,6 +33,9 @@ LIBOBJS = \ sys/null_read.o sys/null_write.o sys/serial_write.o \ sys/ansicon_write.o sys/ansiserial_write.o \ \ + sys/vesa/initvesa.o sys/vesa/alphatbl.o sys/vesa/drawtxt.o \ + sys/vesa/background.o \ + \ pci/cfgtype.o \ pci/readb.o pci/readw.o pci/readl.o pci/readbios.o \ pci/writeb.o pci/writew.o pci/writel.o pci/writebios.o \ @@ -61,7 +64,7 @@ libcom32.a : $(LIBOBJS) $(RANLIB) $@ tidy: - rm -f *.o .*.d */*.o */.*.d + rm -f *.o .*.d */*.o */.*.d lib/sys/vesa/alphatbl.c clean: tidy rm -f *.a @@ -75,4 +78,9 @@ install: all -rm -rf $(INSTALLROOT)$(COM32DIR)/include cp -r ../include $(INSTALLROOT)$(COM32DIR) +sys/vesa/alphatbl.o: sys/vesa/alphatbl.c + +sys/vesa/alphatbl.c: sys/vesa/alphatbl.pl + $(PERL) $< > $@ || ( rm -f $@ ; exit 1 ) + -include .*.d */.*.d diff --git a/com32/lib/sys/vesa/background.c b/com32/lib/sys/vesa/background.c new file mode 100644 index 0000000..7de2d5a --- /dev/null +++ b/com32/lib/sys/vesa/background.c @@ -0,0 +1,171 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2006 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include +#include +#include +#include "vesa.h" +#include "video.h" + +static void draw_background(void) +{ + uint32_t *outp = (uint32_t *)__vesa_info.mi.lfb_ptr; + uint32_t *inp = (uint32_t *)__vesacon_background; + size_t n = sizeof __vesacon_background; + uint32_t v; + + while (n--) { + v = *inp++; + *outp++ = (__vesacon_alpha_tbl[(uint8_t)(v >> 16)][0] << 16)| + (__vesacon_alpha_tbl[(uint8_t)(v >> 8)][0] << 8)| + (__vesacon_alpha_tbl[(uint8_t)v][0]); + } +} + +int vesacon_load_background(const char *filename) +{ + FILE *fp; + uint8_t header[8]; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_infop end_ptr = NULL; + png_color_16p image_background; + static const png_color_16 my_background = {0,0,0,0,0}; + double gamma; + const double screen_gamma = 2.2; + png_bytep row_pointers[VIDEO_Y_SIZE]; + int passes; + int i; + int rv = -1; + + if (!filename) { + draw_background(); + return 0; + } + + fp = fopen(filename, "r"); + + if (!fp) + goto err; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + + info_ptr = png_create_info_struct(png_ptr); + end_ptr = png_create_info_struct(png_ptr); + + if (fread(header, 1, 8, fp) != 8 || png_sig_cmp(header, 0, 8) || + !png_ptr || !info_ptr || !end_ptr || + setjmp(png_jmpbuf(png_ptr))) + goto err; + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, 8); + + png_set_user_limits(png_ptr, VIDEO_X_SIZE, VIDEO_Y_SIZE); + + png_read_info(png_ptr, info_ptr); + + /* Set the appropriate set of transformations. We need to end up + with 32-bit BGRA format, no more, no less. */ + + switch (info_ptr->color_type) { + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_set_gray_to_rgb(png_ptr); + /* fall through */ + + case PNG_COLOR_TYPE_RGB_ALPHA: + break; + + case PNG_COLOR_TYPE_GRAY: + png_set_gray_to_rgb(png_ptr); + /* fall through */ + + case PNG_COLOR_TYPE_RGB: + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + else + png_set_add_alpha(png_ptr, ~0, PNG_FILLER_AFTER); + break; + + case PNG_COLOR_TYPE_PALETTE: + png_set_palette_to_rgb(png_ptr); + break; + + default: + /* Huh? */ + break; + } + + png_set_bgr(png_ptr); + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + + if (info_ptr->bit_depth == 16) + png_set_strip_16(png_ptr); + else if (info_ptr->bit_depth < 8) + png_set_packing(png_ptr); + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + + /* Whew! Now we should get the stuff we want... */ + for (i = 0; i < info_ptr->height; i++) + row_pointers[i] = (png_bytep *)__vesacon_background[i]; + + passes = png_set_interlace_handling(png_ptr); + + for (i = 0; i < passes; i++) + png_read_rows(png_ptr, row_pointers, NULL, info_ptr->height); + + /* This actually displays the stuff */ + draw_background(); + + rv = 0; + + err: + if (png_ptr) + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + if (fp) + fclose(fp); + return rv; +} + +int __vesacon_init_background(void) +{ + memset(__vesacon_background, 0, sizeof __vesacon_background); + + /* The VESA BIOS has already cleared the screen */ +} diff --git a/com32/lib/sys/vesa/drawtxt.c b/com32/lib/sys/vesa/drawtxt.c new file mode 100644 index 0000000..6713063 --- /dev/null +++ b/com32/lib/sys/vesa/drawtxt.c @@ -0,0 +1,148 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2006 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include +#include "vesa.h" +#include "video.h" + +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, bgxval; + int fr = 0, fg = 0, fb = 0; + int br = 0, bg = 0, bb = 0; + uint8_t r, g, b; + uint8_t chbits = 0, chxbits = 0, chsbits = 0; + int i, j, pixrow, pixsrow; + struct vesa_char *rowptr, *rowsptr, *cptr, *csptr; + + 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); + + /* 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)]; + rowsptr = rowptr - ((TEXT_PIXEL_COLS/FONT_WIDTH+2)+1); + pixrow = 0; + pixsrow = height-1; + + for (i = height*nrows; i >= 0; i--) { + bgptr = bgrowptr; + fbptr = fbrowptr; + + cptr = rowptr; + csptr = rowsptr; + + chsbits = __vesacon_graphics_font[csptr->ch][pixsrow]; + chsbits &= (csptr->sha & 0x02) ? 0xff : 0x00; + chsbits ^= (csptr->sha & 0x01) ? 0xff : 0x00; + chsbits <<= 7; + csptr++; + + for (j = width*ncols; j >= 0; j--) { + chbits <<= 1; + chsbits <<= 1; + chxbits <<= 1; + + switch (j % FONT_WIDTH) { + case 0: + chbits = __vesacon_graphics_font[cptr->ch][pixrow]; + chxbits = chbits; + chxbits &= (cptr->sha & 0x02) ? 0xff : 0x00; + chxbits ^= (cptr->sha & 0x01) ? 0xff : 0x00; + fr = ((cptr->attr & 4) >> 1) + ((cptr->attr & 8) >> 3); + fg = ((cptr->attr & 2)) + ((cptr->attr & 8) >> 3); + fb = ((cptr->attr & 1) << 1) + ((cptr->attr & 8) >> 3); + br = ((cptr->attr & 0x40) >> 5) + ((cptr->attr & 0x80) >> 7); + bg = ((cptr->attr & 0x20) >> 4) + ((cptr->attr & 0x80) >> 7); + bb = ((cptr->attr & 0x10) >> 3) + ((cptr->attr & 0x80) >> 7); + cptr++; + break; + case FONT_WIDTH-1: + chsbits = __vesacon_graphics_font[csptr->ch][pixsrow]; + chsbits &= (csptr->sha & 0x02) ? 0xff : 0x00; + chsbits ^= (csptr->sha & 0x01) ? 0xff : 0x00; + csptr++; + break; + default: + break; + } + + bgval = *bgptr; + bgxval = bgptr[VIDEO_X_SIZE+1]; + bgptr++; + + if (chbits & 0x80) { + r = __vesacon_alpha_tbl[(uint8_t)(bgxval >> 16)][fr]; + g = __vesacon_alpha_tbl[(uint8_t)(bgxval >> 8)][fg]; + b = __vesacon_alpha_tbl[(uint8_t)bgxval][fb]; + } else if ((chsbits & ~chxbits) & 0x80) { + r = __vesacon_alpha_tbl[(uint8_t)(bgval >> 16)][br] >> 2; + g = __vesacon_alpha_tbl[(uint8_t)(bgval >> 8)][bg] >> 2; + b = __vesacon_alpha_tbl[(uint8_t)bgval][bb] >> 2; + } else { + r = __vesacon_alpha_tbl[(uint8_t)(bgval >> 16)][br]; + g = __vesacon_alpha_tbl[(uint8_t)(bgval >> 8)][bg]; + b = __vesacon_alpha_tbl[(uint8_t)bgval][bb]; + } + + *fbptr++ = (r << 16)|(g << 8)|b; + } + + bgrowptr += VIDEO_X_SIZE; + fbrowptr += VIDEO_X_SIZE; + + if (++pixrow == height) { + rowptr += TEXT_PIXEL_COLS/FONT_WIDTH+2; + pixrow = 0; + } + if (++pixsrow == height) { + rowsptr += TEXT_PIXEL_COLS/FONT_WIDTH+2; + pixsrow = 0; + } + } +} + +void vesacon_write_at(int row, int col, const char *str, uint8_t attr, int rev) +{ + int n = 0; + struct vesa_char *ptr = &__vesacon_text_display[(row+1)*(TEXT_PIXEL_COLS/FONT_WIDTH+2)+(col+1)]; + + while (*str) { + ptr->ch = *str; + ptr->attr = attr; + ptr->sha = rev; + + n++; + str++; + ptr++; + } + + vesacon_update_characters(row, col, 1, n); +} + diff --git a/com32/lib/sys/vesa/initvesa.c b/com32/lib/sys/vesa/initvesa.c index 43b3498..7d29427 100644 --- a/com32/lib/sys/vesa/initvesa.c +++ b/com32/lib/sys/vesa/initvesa.c @@ -35,15 +35,38 @@ #include #include #include +#include +#include +#include #include "vesa.h" #include "video.h" -struct vesa_general_info __vesa_general_info; -struct vesa_mode_info __vesa_mode_info; +struct vesa_info __vesa_info; +struct vesa_char *__vesacon_text_display; + +int __vesacon_font_height; uint8_t __vesacon_graphics_font[FONT_MAX_CHARS][FONT_MAX_HEIGHT]; + uint32_t __vesacon_background[VIDEO_Y_SIZE][VIDEO_X_SIZE]; -uint32_t __vesacon_shadowfb[VIDEO_Y_SIZE][VIDEO_X_SIZE]; + +ssize_t __serial_write(void *fp, const void *buf, size_t count); + +static void debug(const char *str, ...) +{ + va_list va; + char buf[65536]; + size_t len; + + va_start(va, str); + len = vsnprintf(buf, sizeof buf, str, va); + va_end(va); + + if (len >= sizeof buf) + len = sizeof buf - 1; + + __serial_write(NULL, buf, len); +} static void unpack_font(uint8_t *dst, uint8_t *src, int height) { @@ -51,9 +74,9 @@ static void unpack_font(uint8_t *dst, uint8_t *src, int height) for (i = 0; i < FONT_MAX_CHARS; i++) { memcpy(dst, src, height); - memset(dst+height, 0, 32-height); + memset(dst+height, 0, FONT_MAX_HEIGHT-height); - dst += 32; + dst += FONT_MAX_HEIGHT; src += height; } } @@ -70,6 +93,8 @@ static int vesacon_set_mode(void) gi = &((struct vesa_info *)__com32.cs_bounce)->gi; mi = &((struct vesa_info *)__com32.cs_bounce)->mi; + debug("Hello, World!\r\n"); + memset(&rm, 0, sizeof rm); gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */ @@ -87,12 +112,14 @@ static int vesacon_set_mode(void) } /* Search for a 640x480 32-bit linear frame buffer mode */ - mode_ptr = CVT_PTR(gi->video_mode_ptr); + mode_ptr = GET_PTR(gi->video_mode_ptr); for(;;) { if ((mode = *mode_ptr++) == 0xFFFF) return 4; /* No mode found */ + debug("Found mode: 0x%04x\r\n", mode); + rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ rm.ecx.w[0] = mode; rm.edi.w[0] = OFFS(mi); @@ -102,6 +129,11 @@ static int vesacon_set_mode(void) /* Must be a supported mode */ if ( rm.eax.w[0] != 0x004f ) continue; + + debug("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n", + mi->mode_attr, mi->h_res, mi->v_res, mi->bpp, mi->memory_layout, + mi->rpos, mi->gpos, mi->bpos); + /* Must be an LFB color graphics mode supported by the hardware */ if ( (mi->mode_attr & 0x0099) != 0x0099 ) continue; @@ -112,8 +144,8 @@ static int vesacon_set_mode(void) /* 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 != 24 || - mi->gpos != 16 || mi->bpos != 0) ) + (mi->memory_layout != 6 || mi->rpos != 16 || + mi->gpos != 8 || mi->bpos != 0) ) continue; /* Hey, looks like we found something we can live with */ @@ -125,7 +157,8 @@ static int vesacon_set_mode(void) rm.ebx.w[0] = 0x0600; /* Get 8x16 ROM font */ __intcall(0x10, &rm, &rm); rom_font = MK_PTR(rm.es, rm.ebp.w[0]); - unpack_font(graphics_font, rom_font, 16); + __vesacon_font_height = 16; + unpack_font((uint8_t *)__vesacon_graphics_font, rom_font, 16); /* Now set video mode */ rm.eax.w[0] = 0x4F02; /* Set SVGA video mode */ @@ -143,7 +176,110 @@ static int vesacon_set_mode(void) return 0; } + +static int init_text_display(void) +{ + size_t nchars; + struct vesa_char *ptr; + + nchars = (TEXT_PIXEL_ROWS/__vesacon_font_height+2)* + (TEXT_PIXEL_COLS/FONT_WIDTH+2); + + __vesacon_text_display = ptr = malloc(nchars*sizeof(struct vesa_char)); + + if (!ptr) + return -1; + + /* I really which C had a memset() for larger-than-bytes objects... */ + asm volatile("cld; rep; stosl" + : "+D" (ptr), "+c" (nchars) + : "a" (' '+(0x07 << 8)+(SHADOW_NORMAL << 16)) + : "memory"); + + return 0; +} + int __vesacon_init(void) { - return vesacon_set_mode(); + int i, j, r, g, b, n; + const int step = 8; + + /* Fill the background image with a test pattern */ + for (i = 0; i < VIDEO_Y_SIZE; i++) { + r = g = b = n = 0; + + for (j = 0; j < VIDEO_X_SIZE; j++) { + switch (n) { + case 0: + r += step; + if (r >= 255) { + r = 255; + n++; + } + break; + case 1: + g += step; + if (g >= 255) { + g = 255; + n++; + } + break; + case 2: + r -= step; + if (r <= 0) { + r = 0; + n++; + } + break; + case 3: + b += step; + if (b >= 255) { + b = 255; + n++; + } + break; + case 4: + g -= step; + if (g <= 0) { + g = 0; + n++; + } + break; + case 5: + r += step; + if (r >= 255) { + r = 255; + n++; + } + break; + case 6: + g += step; + if (g >= 255) { + g = 255; + n++; + } + break; + case 7: + r -= step; + if (r < 0) { + r = 0; + n = 0; + } + g = b = r; + break; + } + __vesacon_background[i][j] = (r << 16) + (g << 8) + b; + } + } + + vesacon_set_mode(); + + init_text_display(); + + debug("Mode set, now drawing at %#p\n", __vesa_info.mi.lfb_ptr); + + __vesacon_init_background(); + + debug("Ready!\r\n"); + return 0; } diff --git a/com32/lib/sys/vesa/video.h b/com32/lib/sys/vesa/video.h index acbbc10..9237a85 100644 --- a/com32/lib/sys/vesa/video.h +++ b/com32/lib/sys/vesa/video.h @@ -30,10 +30,37 @@ #define FONT_MAX_CHARS 256 #define FONT_MAX_HEIGHT 32 +#define FONT_WIDTH 8 #define VIDEO_X_SIZE 640 #define VIDEO_Y_SIZE 480 -extern uint8_t graphics_font[FONT_MAX_CHARS][FONT_MAX_HEIGHT]; +#define VIDEO_BORDER 8 +#define TEXT_PIXEL_ROWS (VIDEO_Y_SIZE-2*VIDEO_BORDER) +#define TEXT_PIXEL_COLS (VIDEO_X_SIZE-2*VIDEO_BORDER) + +#define SHADOW_NONE 0 +#define SHADOW_ALL 1 +#define SHADOW_NORMAL 2 +#define SHADOW_REVERSE 3 + +struct vesa_char { + uint8_t ch; /* Character */ + uint8_t attr; /* PC-style graphics attribute */ + uint8_t sha; /* Shadow attributes */ + uint8_t pad; /* Currently unused */ +}; + +extern struct vesa_char *__vesacon_text_display; + +extern int __vesacon_font_height; +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]; + +extern unsigned char __vesacon_alpha_tbl[256][4]; + +extern int __vesacon_init_background(void); +int vesacon_load_background(const char *); #endif /* LIB_SYS_VESA_VIDEO_H */ -- 2.7.4