Skip site navigation (1)Skip section navigation (2)
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>