svn commit: r270620 - head/sys/dev/vt/hw/vga
Jean-Sebastien Pedron
dumbbell at FreeBSD.org
Mon Aug 25 20:15:20 UTC 2014
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
More information about the svn-src-head
mailing list