Date: Mon, 25 Aug 2014 20:15:19 +0000 (UTC) From: Jean-Sebastien Pedron <dumbbell@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r270620 - head/sys/dev/vt/hw/vga Message-ID: <201408252015.s7PKFJn6011068@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: dumbbell Date: Mon Aug 25 20:15:19 2014 New Revision: 270620 URL: http://svnweb.freebsd.org/changeset/base/270620 Log: vt_vga: Use Write Mode 0 to draw group of 8 pixels using 3 or more colors This replaces the method based on Write Mode 3, which required reads from the video memory to load the latches. MFC after: 1 week Modified: head/sys/dev/vt/hw/vga/vt_vga.c Modified: head/sys/dev/vt/hw/vga/vt_vga.c ============================================================================== --- head/sys/dev/vt/hw/vga/vt_vga.c Mon Aug 25 20:06:57 2014 (r270619) +++ head/sys/dev/vt/hw/vga/vt_vga.c Mon Aug 25 20:15:19 2014 (r270620) @@ -54,6 +54,7 @@ struct vga_softc { bus_space_handle_t vga_fb_handle; bus_space_tag_t vga_reg_tag; bus_space_handle_t vga_reg_handle; + int vga_wmode; term_color_t vga_curfg, vga_curbg; }; @@ -115,46 +116,74 @@ static struct vga_softc vga_conssoftc; VT_DRIVER_DECLARE(vt_vga, vt_vga_driver); static inline void -vga_setfg(struct vt_device *vd, term_color_t color) +vga_setwmode(struct vt_device *vd, int wmode) { struct vga_softc *sc = vd->vd_softc; - if (sc->vga_curfg != color) { - REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET); - REG_WRITE1(sc, VGA_GC_DATA, color); - sc->vga_curfg = color; + if (sc->vga_wmode == wmode) + return; + + REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE); + REG_WRITE1(sc, VGA_GC_DATA, wmode); + sc->vga_wmode = wmode; + + switch (wmode) { + case 3: + /* Re-enable all plans. */ + REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MAP_MASK); + REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_MM_EM3 | VGA_SEQ_MM_EM2 | + VGA_SEQ_MM_EM1 | VGA_SEQ_MM_EM0); + break; } } static inline void +vga_setfg(struct vt_device *vd, term_color_t color) +{ + struct vga_softc *sc = vd->vd_softc; + + vga_setwmode(vd, 3); + + if (sc->vga_curfg == color) + return; + + REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET); + REG_WRITE1(sc, VGA_GC_DATA, color); + sc->vga_curfg = color; +} + +static inline void vga_setbg(struct vt_device *vd, term_color_t color) { struct vga_softc *sc = vd->vd_softc; - if (sc->vga_curbg != color) { - REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET); - REG_WRITE1(sc, VGA_GC_DATA, color); + vga_setwmode(vd, 3); - /* - * Write 8 pixels using the background color to an - * off-screen byte in the video memory. - */ - MEM_WRITE1(sc, VT_VGA_BGCOLOR_OFFSET, 0xff); + if (sc->vga_curbg == color) + return; - /* - * Read those 8 pixels back to load the background color - * in the latches register. - */ - MEM_READ1(sc, VT_VGA_BGCOLOR_OFFSET); + REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET); + REG_WRITE1(sc, VGA_GC_DATA, color); - sc->vga_curbg = color; + /* + * Write 8 pixels using the background color to an off-screen + * byte in the video memory. + */ + MEM_WRITE1(sc, VT_VGA_BGCOLOR_OFFSET, 0xff); - /* - * The Set/Reset register doesn't contain the fg color - * anymore, store an invalid color. - */ - sc->vga_curfg = 0xff; - } + /* + * Read those 8 pixels back to load the background color in the + * latches register. + */ + MEM_READ1(sc, VT_VGA_BGCOLOR_OFFSET); + + sc->vga_curbg = color; + + /* + * The Set/Reset register doesn't contain the fg color anymore, + * store an invalid color. + */ + sc->vga_curfg = 0xff; } /* @@ -486,40 +515,75 @@ static void vga_bitblt_pixels_block_ncolors(struct vt_device *vd, const uint8_t *masks, unsigned int x, unsigned int y, unsigned int height) { - unsigned int i, j, offset; + unsigned int i, j, plan, color, offset; struct vga_softc *sc; - uint8_t mask; + uint8_t mask, plans[height * 4]; sc = vd->vd_softc; + memset(plans, 0, sizeof(plans)); + + /* + * To write a group of pixels using 3 or more colors, we select + * Write Mode 0 and write one byte to each plan separately. + */ + /* - * To draw a pixels block with N colors (N > 2), we write each - * color one by one: - * 1. Use the color as the foreground color - * 2. Read the pixels block into the latches - * 3. Draw the calculated mask - * 4. Go back to #1 for subsequent colors. + * We first compute each byte: each plan contains one bit of the + * color code for each of the 8 pixels. + * + * For example, if the 8 pixels are like this: + * GBBBBBBY + * where: + * G (gray) = 0b0111 + * B (black) = 0b0000 + * Y (yellow) = 0b0011 * - * FIXME: Use Write Mode 0 to remove the need to read from video - * memory. + * The corresponding for bytes are: + * GBBBBBBY + * Plan 0: 10000001 = 0x81 + * Plan 1: 10000001 = 0x81 + * Plan 2: 10000000 = 0x80 + * Plan 3: 00000000 = 0x00 + * | | | + * | | +-> 0b0011 (Y) + * | +-----> 0b0000 (B) + * +--------> 0b0111 (G) */ for (i = 0; i < height; ++i) { - for (j = 0; j < 16; ++j) { - mask = masks[i * 16 + j]; - if (mask == 0) + for (color = 0; color < 16; ++color) { + mask = masks[i * 16 + color]; + if (mask == 0x00) continue; - vga_setfg(vd, j); + for (j = 0; j < 8; ++j) { + if (!((mask >> (7 - j)) & 0x1)) + continue; + + /* The pixel "j" uses color "color". */ + for (plan = 0; plan < 4; ++plan) + plans[i * 4 + plan] |= + ((color >> plan) & 0x1) << (7 - j); + } + } + } + + /* + * The bytes are ready: we now switch to Write Mode 0 and write + * all bytes, one plan at a time. + */ + vga_setwmode(vd, 0); - offset = (VT_VGA_WIDTH * (y + i) + x) / 8; - if (mask != 0xff) { - MEM_READ1(sc, offset); + REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MAP_MASK); + for (plan = 0; plan < 4; ++plan) { + /* Select plan. */ + REG_WRITE1(sc, VGA_SEQ_DATA, 1 << plan); - /* The bg color was trashed by the reads. */ - sc->vga_curbg = 0xff; - } - MEM_WRITE1(sc, offset, mask); + /* Write all bytes for this plan, from Y to Y+height. */ + for (i = 0; i < height; ++i) { + offset = (VT_VGA_WIDTH * (y + i) + x) / 8; + MEM_WRITE1(sc, offset, plans[i * 4 + plan]); } } } @@ -1102,8 +1166,16 @@ vga_initialize(struct vt_device *vd, int /* Switch to write mode 3, because we'll mainly do bitblt. */ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE); REG_WRITE1(sc, VGA_GC_DATA, 3); + sc->vga_wmode = 3; + + /* + * In Write Mode 3, Enable Set/Reset is ignored, but we + * use Write Mode 0 to write a group of 8 pixels using + * 3 or more colors. In this case, we want to disable + * Set/Reset: set Enable Set/Reset to 0. + */ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_ENABLE_SET_RESET); - REG_WRITE1(sc, VGA_GC_DATA, 0x0f); + REG_WRITE1(sc, VGA_GC_DATA, 0x00); /* * Clear the colors we think are loaded into Set/Reset or
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408252015.s7PKFJn6011068>