Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 4 Sep 2014 20:18:09 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r271128 - in stable/10/sys: dev/fb dev/vt dev/vt/font dev/vt/hw/efifb dev/vt/hw/fb dev/vt/hw/ofwfb dev/vt/hw/vga powerpc/ps3
Message-ID:  <201409042018.s84KI9Pm028441@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: emaste
Date: Thu Sep  4 20:18:08 2014
New Revision: 271128
URL: http://svnweb.freebsd.org/changeset/base/271128

Log:
  MFC vt(4) improvements / sync with HEAD
  
  These are largely dumbbell@'s changes.  Most significantly they address
  the extreme performance degradation with VGA hardware.
  
  SVN revisions in this MFC:
    269471 270290 270293 270322 270324 270329 270331 270336 270338 270340
    270341 270342 270343 270388 270390 270404 270411 270412 270413 270431
    270446 270448 270485 270587 270589 270613 270618 270620 270667 270702
    270707 270708 270720 270721 270785 270786
  
  Detailed commit list:
  
  r270290: Test if the cursor is shown only once
  
    Later, we just see if the "struct mouse_cursor" pointer is set. This
    avoids the need to mess with all the conditions several times; this
    has been error prone.
  
    While here, rename the variable "m" to a more meaningful "cursor",
    like it's done elsewhere in the code.
  
  r270293: Rename the "mouse_cursor" structure to "vt_mouse_cursor"
  
    At the same time, "w" and "h" members are now called "width" and
    "height". The goal is to have a more "public" structure, because it
    will soon be passed as argument to a new callback, replacing
    vd_bitbltchr_t.
  
  r269471 (ray):
  
    Fix vt_vga driver to draw not-8-bit-aligned fonts correctly.
    Still one bug here: mouse left some gaps on track when moving left.
  
  r270322:
  
    Add new vd_bitblt_text_t callback, and implement it for vt_vga
  
    Compared to the deprecated vd_bitbltchr_t callback, vd_bitblt_text_t
    receives:
      o  the whole text buffer
      o  the dirty area
      o  the mouse cursor (map, position, colors)
  
    This allows the backend to perform optimization on how to draw things.
    The goal is to remove vd_bitbltchr_t and vd_putchar_t, once all driver
    are converted (only vt_vga is included in this commit).
  
    In vt_vga, this allows to draw the text and the cursor in one pass,
    without ever reading from video memory (because it has all the context).
    The main benefit is the speed improvement: no more slideshow during
    boot!
  
    Other bugs fixed in vt_vga are:
      o  left-most characters are drawn properly (the left-most pixels were
         missing with bold characters and some wide letters such as 'm')
      o  no more black square around the cursor
      o  no cursor flickering when the text is scrolling
  
    There are still many problems to fix: the known issues are marked with
    "FIXME" inside the code.
  
  r270411:
  
    vt_fb: Implement vd_bitblt_text_t for vt_fb and derivatives
  
  r270412:
  
    creator_fb: Implement vd_bitblt_text_t
  
  r270413: ofwfb: Implement vd_bitblt_text_t
  
  r270324: vt_vga: Clip the draw area to never draw offscreen
  
    This fixes a bug when two windows use different fonts, but a longer-
    term solution is required. The dirty area should be stored as pixels,
    not character cells, because such coordinates don't have the same
    meaning in all windows, when using different fonts.
  
  r270329: Mark new mouse position as dirty only when it's actually displayed
  
  r270331: Store cursor bitmap & colors in struct vt_device
  
    This removes the need to specify them to each call to vd_bitblt_text_t
    and, therefore, simplifies the API.
  
  r270336: Give the window to vd_bitblt_text_t callback
  
    ... instead of both the buffer and the font. Again, this simplifies
    the API.
  
  r270338: The offset to center the text area is per-window now
  
    The previous global offset, based on the last loaded font, had no
    meaning for other windows. This caused a shifted text area, often
    partly out-of-screen.
  
  r270341:  vt_vga: Remove a "FIXME" comment; the issue was solved in r270338
  
  r270340: Don't run vt_set_border() and vt_flush() concurrently
  
    In the case of vt_vga, the two concurrent calls were writing to the
    same VGA registers, causing incorrect refresh of the screen.
  
  r270342: Use the actual size of the mouse when marking its position as dirty
  
    This fixes a bug where part of the cursor was not erased.
  
  r270343: Remove "FIXME" about multiple locking of vt_buf in vt_flush()
  
    After some testing, it appears that acquiring the lock once and keeping
    it longer is slower than taking it multiple times.
  
    While here, fix a typo in another comment.
  
  r270388: vt_vga: Give only the character part of term_char_t to vga_get_cp437()
  
    This fixes a bug where vga_get_cp437() was called with an invalid
    argument. The screen was then filled with '?' instead of the actual
    character.
  
  r270390: Fix a crash in vt_mark_mouse_position_as_dirty() when in textmode
  
    In textmode, no font is loaded, thus the page fault in
    vt_mark_mouse_position_as_dirty() when it wants the font width/height.
  
    For now, create a fake area for the textmode. This needs to be
    modified if vt_vga gains mouse support in textmode.
  
    While here, fix a build failure when SC_NO_CUTPASTE is defined:
    vt_mark_mouse_position_as_dirty() must not be included in this case.
  
  r270404: Fix cursor handling in vt_flush()
  
    There were situations where the cursor was not erased/redrawn or its
    position was marked as dirty even though it's not displayed. The code
    is now more straightforward.
  
    At the same, add a function to determine if the cursor covers a given
    area. This is used by backends to know if they need to draw the
    cursor.
  
    This new function should be paired with a new state in struct
    vt_device, called vd_mshown, which indicates if the cursor should be
    displayed.  This again simplifies vd_bitblt_text_t callback's API.
  
  r270431: vt(4): Add vd_bitblt_bmp_t callback
  
    The code was already there in all backends, we just expose it. This is
    used to display the splash screen.
  
  r270446: Remove vd_bitbltchr_t
  
    It's replaced by vd_bitblt_text_t, which gives more context to the
    backend and allows it to perform more efficiently when redrawing a
    given area.
  
  r270448: Fix order of arguments (x <-> y) when showing the splash screen
  
  r270485: vt_vga: Fix the display of the splash screen
  
  r270587: Take font offset into account in vt_is_cursor_in_area()
  
    This fixes a "General protection fault" in vt_vga, where
    vt_is_cursor_in_area() erroneously reported that the cursor was over
    the text. This led to negative integers stored in "unsigned int" and
    chaos.
  
  r270589: The cursor coordinates are relative to the drawn area
  
    ... not the whole screen. Don't use font offsets in
    vt_mark_mouse_position_as_dirty().
  
    This fixes a bug where the mouse position wasn't marked as dirty when
    approaching the borders of the drawn area.
  
  r270613: Store a rectangle for the drawable area, not just the top-left corner
  
    This allows backends to verify they do not draw outside of this area.
    This fixes a bug in vt_vga where the text was happily drawn over the
    right and bottom margins, when using the Gallant font.
  
  r270618: Intialize drawable area rectangle each time a font is loaded
  
    This also fixes a problem where early in boot, the area was zero,
    leading to nothing displayed for a few seconds.
  
  r270620: 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.
  
  r270667: When creating a window buffer, fill it entirely
  
    ... not just the visible part.
  
    This fixes a bug where, when switching from eg. vt_vga to vt_fb (ie.
    the resolution goes up), the originally hidden, uninitialized area of
    the buffer is displayed on the screen. This leads to a missing text
    cursor when it's over an unitialized area.
  
    This was also visible when selecting text: the uninitialized area was
    not highlighted.
  
    Internally, this area was zeroed: characters were all 0x00000000,
    meaning the foreground and background color was black. Now, everything
    is filled with a space with a gray foreground color, like the visible
    area.
  
    While here, remove the check for the mute flag and always use
    TERMINAL_NORM_ATTR as the character attribute (ie. gray foreground,
    black background).
  
  r270702: Implement basic support for KDSETMODE ioctl
  
    With the current implementation, this allows an X11 server to tell
    the console it switches a particular window in "graphics mode". This
    information is used by the mouse handling code to ignore sysmouse events
    in the window taken by the X server: only him should receive those
    events.
  
  r270707: Pause the vt_flush() timer when the screen is up-to-date
  
    The timer is restarted whenever a window buffer is marked as dirty or
    the mouse cursor moves.
  
    There's still room for improvement. For instance, we should not mark a
    window buffer as dirty when this window isn't displayed.
  
  r270708: vt(4): Recompute the drawable area when the resolution changes
  
    This was only done when the font changed.
  
  r270720: vt(4): Fix mouse cursor handling in vt_fb/creator_vt/ofwfb
  
    There were two issues:
      1. The area given to vt_is_cursor_in_area() was adding the drawable
         area offset, something already handled by this function.
      2. The cursor was shifted on the screen by the offset of this area
         and thus was misplaced or not erased. Furthermore, when reaching
         the bottom or right borders, the cursor was either totally
         removed or not erased correctly.
  
  r270721: vt(4): If the terminal shrinks, make sure the mouse is inside
     the new area
  
  r270785: vt(4): Change vb_history_size from "int" to "unsigned int"
  
    CID:		1230002, 1230003
  
  r270786: Indicate that KDSETRAD case falls through the next case
  
    CID:		1229953
  
  Relnotes:	Yes

Modified:
  stable/10/sys/dev/fb/creator_vt.c
  stable/10/sys/dev/vt/font/vt_mouse_cursor.c
  stable/10/sys/dev/vt/hw/efifb/efifb.c
  stable/10/sys/dev/vt/hw/fb/vt_early_fb.c
  stable/10/sys/dev/vt/hw/fb/vt_fb.c
  stable/10/sys/dev/vt/hw/fb/vt_fb.h
  stable/10/sys/dev/vt/hw/ofwfb/ofwfb.c
  stable/10/sys/dev/vt/hw/vga/vt_vga.c
  stable/10/sys/dev/vt/vt.h
  stable/10/sys/dev/vt/vt_buf.c
  stable/10/sys/dev/vt/vt_core.c
  stable/10/sys/powerpc/ps3/ps3_syscons.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/fb/creator_vt.c
==============================================================================
--- stable/10/sys/dev/fb/creator_vt.c	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/fb/creator_vt.c	Thu Sep  4 20:18:08 2014	(r271128)
@@ -45,14 +45,16 @@ __FBSDID("$FreeBSD$");
 static vd_probe_t	creatorfb_probe;
 static vd_init_t	creatorfb_init;
 static vd_blank_t	creatorfb_blank;
-static vd_bitbltchr_t	creatorfb_bitbltchr;
+static vd_bitblt_text_t	creatorfb_bitblt_text;
+static vd_bitblt_bmp_t	creatorfb_bitblt_bitmap;
 
 static const struct vt_driver vt_creatorfb_driver = {
 	.vd_name	= "creatorfb",
 	.vd_probe	= creatorfb_probe,
 	.vd_init	= creatorfb_init,
 	.vd_blank	= creatorfb_blank,
-	.vd_bitbltchr	= creatorfb_bitbltchr,
+	.vd_bitblt_text	= creatorfb_bitblt_text,
+	.vd_bitblt_bmp	= creatorfb_bitblt_bitmap,
 	.vd_fb_ioctl	= vt_fb_ioctl,
 	.vd_fb_mmap	= vt_fb_mmap,
 	.vd_priority	= VD_PRIORITY_SPECIFIC
@@ -176,30 +178,30 @@ creatorfb_blank(struct vt_device *vd, te
 }
 
 static void
-creatorfb_bitbltchr(struct vt_device *vd, const uint8_t *src,
-    const uint8_t *mask, int bpl, vt_axis_t top, vt_axis_t left,
-    unsigned int width, unsigned int height, term_color_t fg, term_color_t bg)
+creatorfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
+    const uint8_t *pattern, const uint8_t *mask,
+    unsigned int width, unsigned int height,
+    unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
 {
 	struct creatorfb_softc *sc = vd->vd_softc;
 	u_long line;
 	uint32_t fgc, bgc;
-	int c;
+	int c, l;
 	uint8_t b, m;
 
 	fgc = sc->fb.fb_cmap[fg];
 	bgc = sc->fb.fb_cmap[bg];
 	b = m = 0;
 
-	/* Don't try to put off screen pixels */
-	if (((left + width) > vd->vd_width) || ((top + height) >
-	    vd->vd_height))
-		return;
-
-	line = (sc->fb.fb_stride * top) + 4*left;
-	for (; height > 0; height--) {
-		for (c = 0; c < width; c++) {
+	line = (sc->fb.fb_stride * y) + 4*x;
+	for (l = 0;
+	    l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
+	    l++) {
+		for (c = 0;
+		    c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
+		    c++) {
 			if (c % 8 == 0)
-				b = *src++;
+				b = *pattern++;
 			else
 				b <<= 1;
 			if (mask != NULL) {
@@ -218,3 +220,55 @@ creatorfb_bitbltchr(struct vt_device *vd
 	}
 }
 
+void
+creatorfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
+    const term_rect_t *area)
+{
+	unsigned int col, row, x, y;
+	struct vt_font *vf;
+	term_char_t c;
+	term_color_t fg, bg;
+	const uint8_t *pattern;
+
+	vf = vw->vw_font;
+
+	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
+		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
+		    ++col) {
+			x = col * vf->vf_width +
+			    vw->vw_draw_area.tr_begin.tp_col;
+			y = row * vf->vf_height +
+			    vw->vw_draw_area.tr_begin.tp_row;
+
+			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
+			pattern = vtfont_lookup(vf, c);
+			vt_determine_colors(c,
+			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
+
+			creatorfb_bitblt_bitmap(vd, vw,
+			    pattern, NULL, vf->vf_width, vf->vf_height,
+			    x, y, fg, bg);
+		}
+	}
+
+#ifndef SC_NO_CUTPASTE
+	if (!vd->vd_mshown)
+		return;
+
+	term_rect_t drawn_area;
+
+	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
+	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
+	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
+	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
+
+	if (vt_is_cursor_in_area(vd, &drawn_area)) {
+		creatorfb_bitblt_bitmap(vd, vw,
+		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
+		    vd->vd_mcursor->width, vd->vd_mcursor->height,
+		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
+		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
+		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
+	}
+#endif
+}

Modified: stable/10/sys/dev/vt/font/vt_mouse_cursor.c
==============================================================================
--- stable/10/sys/dev/vt/font/vt_mouse_cursor.c	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/vt/font/vt_mouse_cursor.c	Thu Sep  4 20:18:08 2014	(r271128)
@@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/vt/vt.h>
 
 #ifndef SC_NO_CUTPASTE
-struct mouse_cursor vt_default_mouse_pointer = {
+struct vt_mouse_cursor vt_default_mouse_pointer = {
 	.map = {
 		0x00, /* "__      " */
 		0x40, /* "_*_     " */
@@ -64,7 +64,7 @@ struct mouse_cursor vt_default_mouse_poi
 		0x0f, /* "    ____" */
 		0x0f, /* "    ____" */
 	},
-	.w = 8,
-	.h = 13,
+	.width = 8,
+	.height = 13,
 };
 #endif

Modified: stable/10/sys/dev/vt/hw/efifb/efifb.c
==============================================================================
--- stable/10/sys/dev/vt/hw/efifb/efifb.c	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/vt/hw/efifb/efifb.c	Thu Sep  4 20:18:08 2014	(r271128)
@@ -60,7 +60,8 @@ static struct vt_driver vt_efifb_driver 
 	.vd_probe = vt_efifb_probe,
 	.vd_init = vt_efifb_init,
 	.vd_blank = vt_fb_blank,
-	.vd_bitbltchr = vt_fb_bitbltchr,
+	.vd_bitblt_text = vt_fb_bitblt_text,
+	.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
 	.vd_fb_ioctl = vt_fb_ioctl,
 	.vd_fb_mmap = vt_fb_mmap,
 	/* Better than VGA, but still generic driver. */

Modified: stable/10/sys/dev/vt/hw/fb/vt_early_fb.c
==============================================================================
--- stable/10/sys/dev/vt/hw/fb/vt_early_fb.c	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/vt/hw/fb/vt_early_fb.c	Thu Sep  4 20:18:08 2014	(r271128)
@@ -59,7 +59,8 @@ static struct vt_driver vt_fb_early_driv
 	.vd_probe = vt_efb_probe,
 	.vd_init = vt_efb_init,
 	.vd_blank = vt_fb_blank,
-	.vd_bitbltchr = vt_fb_bitbltchr,
+	.vd_bitblt_text = vt_fb_bitblt_text,
+	.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
 	.vd_priority = VD_PRIORITY_GENERIC,
 };
 

Modified: stable/10/sys/dev/vt/hw/fb/vt_fb.c
==============================================================================
--- stable/10/sys/dev/vt/hw/fb/vt_fb.c	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/vt/hw/fb/vt_fb.c	Thu Sep  4 20:18:08 2014	(r271128)
@@ -41,15 +41,15 @@ __FBSDID("$FreeBSD$");
 #include <dev/vt/hw/fb/vt_fb.h>
 #include <dev/vt/colors/vt_termcolors.h>
 
-void vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2,
-    int fill, term_color_t color);
-void vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color);
+static vd_drawrect_t	vt_fb_drawrect;
+static vd_setpixel_t	vt_fb_setpixel;
 
 static struct vt_driver vt_fb_driver = {
 	.vd_name = "fb",
 	.vd_init = vt_fb_init,
 	.vd_blank = vt_fb_blank,
-	.vd_bitbltchr = vt_fb_bitbltchr,
+	.vd_bitblt_text = vt_fb_bitblt_text,
+	.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
 	.vd_drawrect = vt_fb_drawrect,
 	.vd_setpixel = vt_fb_setpixel,
 	.vd_postswitch = vt_fb_postswitch,
@@ -146,7 +146,7 @@ vt_fb_mmap(struct vt_device *vd, vm_ooff
 	return (EINVAL);
 }
 
-void
+static void
 vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
 {
 	struct fb_info *info;
@@ -181,7 +181,7 @@ vt_fb_setpixel(struct vt_device *vd, int
 
 }
 
-void
+static void
 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
     term_color_t color)
 {
@@ -244,13 +244,14 @@ vt_fb_blank(struct vt_device *vd, term_c
 }
 
 void
-vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
-    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
-    unsigned int height, term_color_t fg, term_color_t bg)
+vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
+    const uint8_t *pattern, const uint8_t *mask,
+    unsigned int width, unsigned int height,
+    unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
 {
 	struct fb_info *info;
 	uint32_t fgc, bgc, cc, o;
-	int c, l, bpp;
+	int c, l, bpp, bpl;
 	u_long line;
 	uint8_t b, m;
 	const uint8_t *ch;
@@ -260,20 +261,18 @@ vt_fb_bitbltchr(struct vt_device *vd, co
 	fgc = info->fb_cmap[fg];
 	bgc = info->fb_cmap[bg];
 	b = m = 0;
-	if (bpl == 0)
-		bpl = (width + 7) >> 3; /* Bytes per sorce line. */
-
-	/* Don't try to put off screen pixels */
-	if (((left + width) > info->fb_width) || ((top + height) >
-	    info->fb_height))
-		return;
+	bpl = (width + 7) >> 3; /* Bytes per source line. */
 
 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
 
-	line = (info->fb_stride * top) + (left * bpp);
-	for (l = 0; l < height; l++) {
-		ch = src;
-		for (c = 0; c < width; c++) {
+	line = (info->fb_stride * y) + (x * bpp);
+	for (l = 0;
+	    l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
+	    l++) {
+		ch = pattern;
+		for (c = 0;
+		    c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
+		    c++) {
 			if (c % 8 == 0)
 				b = *ch++;
 			else
@@ -312,8 +311,61 @@ vt_fb_bitbltchr(struct vt_device *vd, co
 			}
 		}
 		line += info->fb_stride;
-		src += bpl;
+		pattern += bpl;
+	}
+}
+
+void
+vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
+    const term_rect_t *area)
+{
+	unsigned int col, row, x, y;
+	struct vt_font *vf;
+	term_char_t c;
+	term_color_t fg, bg;
+	const uint8_t *pattern;
+
+	vf = vw->vw_font;
+
+	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
+		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
+		    ++col) {
+			x = col * vf->vf_width +
+			    vw->vw_draw_area.tr_begin.tp_col;
+			y = row * vf->vf_height +
+			    vw->vw_draw_area.tr_begin.tp_row;
+
+			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
+			pattern = vtfont_lookup(vf, c);
+			vt_determine_colors(c,
+			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
+
+			vt_fb_bitblt_bitmap(vd, vw,
+			    pattern, NULL, vf->vf_width, vf->vf_height,
+			    x, y, fg, bg);
+		}
+	}
+
+#ifndef SC_NO_CUTPASTE
+	if (!vd->vd_mshown)
+		return;
+
+	term_rect_t drawn_area;
+
+	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
+	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
+	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
+	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
+
+	if (vt_is_cursor_in_area(vd, &drawn_area)) {
+		vt_fb_bitblt_bitmap(vd, vw,
+		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
+		    vd->vd_mcursor->width, vd->vd_mcursor->height,
+		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
+		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
+		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
 	}
+#endif
 }
 
 void

Modified: stable/10/sys/dev/vt/hw/fb/vt_fb.h
==============================================================================
--- stable/10/sys/dev/vt/hw/fb/vt_fb.h	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/vt/hw/fb/vt_fb.h	Thu Sep  4 20:18:08 2014	(r271128)
@@ -36,11 +36,12 @@ int vt_fb_attach(struct fb_info *info);
 void vt_fb_resume(void);
 void vt_fb_suspend(void);
 
-vd_init_t	vt_fb_init;
-vd_blank_t	vt_fb_blank;
-vd_bitbltchr_t	vt_fb_bitbltchr;
-vd_postswitch_t	vt_fb_postswitch;
-vd_fb_ioctl_t	vt_fb_ioctl;
-vd_fb_mmap_t	vt_fb_mmap;
+vd_init_t		vt_fb_init;
+vd_blank_t		vt_fb_blank;
+vd_bitblt_text_t	vt_fb_bitblt_text;
+vd_bitblt_bmp_t		vt_fb_bitblt_bitmap;
+vd_postswitch_t		vt_fb_postswitch;
+vd_fb_ioctl_t		vt_fb_ioctl;
+vd_fb_mmap_t		vt_fb_mmap;
 
 #endif /* _DEV_VT_HW_FB_VT_FB_H_ */

Modified: stable/10/sys/dev/vt/hw/ofwfb/ofwfb.c
==============================================================================
--- stable/10/sys/dev/vt/hw/ofwfb/ofwfb.c	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/vt/hw/ofwfb/ofwfb.c	Thu Sep  4 20:18:08 2014	(r271128)
@@ -58,14 +58,16 @@ struct ofwfb_softc {
 
 static vd_probe_t	ofwfb_probe;
 static vd_init_t	ofwfb_init;
-static vd_bitbltchr_t	ofwfb_bitbltchr;
+static vd_bitblt_text_t	ofwfb_bitblt_text;
+static vd_bitblt_bmp_t	ofwfb_bitblt_bitmap;
 
 static const struct vt_driver vt_ofwfb_driver = {
 	.vd_name	= "ofwfb",
 	.vd_probe	= ofwfb_probe,
 	.vd_init	= ofwfb_init,
 	.vd_blank	= vt_fb_blank,
-	.vd_bitbltchr	= ofwfb_bitbltchr,
+	.vd_bitblt_text	= ofwfb_bitblt_text,
+	.vd_bitblt_bmp	= ofwfb_bitblt_bitmap,
 	.vd_fb_ioctl	= vt_fb_ioctl,
 	.vd_fb_mmap	= vt_fb_mmap,
 	.vd_priority	= VD_PRIORITY_GENERIC+1,
@@ -100,14 +102,15 @@ ofwfb_probe(struct vt_device *vd)
 }
 
 static void
-ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
-    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
-    unsigned int height, term_color_t fg, term_color_t bg)
+ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
+    const uint8_t *pattern, const uint8_t *mask,
+    unsigned int width, unsigned int height,
+    unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
 {
 	struct fb_info *sc = vd->vd_softc;
 	u_long line;
 	uint32_t fgc, bgc;
-	int c;
+	int c, l;
 	uint8_t b, m;
 	union {
 		uint32_t l;
@@ -118,16 +121,16 @@ ofwfb_bitbltchr(struct vt_device *vd, co
 	bgc = sc->fb_cmap[bg];
 	b = m = 0;
 
-	/* Don't try to put off screen pixels */
-	if (((left + width) > vd->vd_width) || ((top + height) >
-	    vd->vd_height))
-		return;
-
-	line = (sc->fb_stride * top) + left * sc->fb_bpp/8;
+	line = (sc->fb_stride * y) + x * sc->fb_bpp/8;
 	if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) {
+		/* Don't try to put off screen pixels */
+		if (((x + width) > vd->vd_width) || ((y + height) >
+		    vd->vd_height))
+			return;
+
 		for (; height > 0; height--) {
 			for (c = 0; c < width; c += 8) {
-				b = *src++;
+				b = *pattern++;
 
 				/*
 				 * Assume that there is more background than
@@ -157,10 +160,14 @@ ofwfb_bitbltchr(struct vt_device *vd, co
 			line += sc->fb_stride;
 		}
 	} else {
-		for (; height > 0; height--) {
-			for (c = 0; c < width; c++) {
+		for (l = 0;
+		    l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
+		    l++) {
+			for (c = 0;
+			    c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
+			    c++) {
 				if (c % 8 == 0)
-					b = *src++;
+					b = *pattern++;
 				else
 					b <<= 1;
 				if (mask != NULL) {
@@ -191,6 +198,59 @@ ofwfb_bitbltchr(struct vt_device *vd, co
 	}
 }
 
+void
+ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
+    const term_rect_t *area)
+{
+	unsigned int col, row, x, y;
+	struct vt_font *vf;
+	term_char_t c;
+	term_color_t fg, bg;
+	const uint8_t *pattern;
+
+	vf = vw->vw_font;
+
+	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
+		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
+		    ++col) {
+			x = col * vf->vf_width +
+			    vw->vw_draw_area.tr_begin.tp_col;
+			y = row * vf->vf_height +
+			    vw->vw_draw_area.tr_begin.tp_row;
+
+			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
+			pattern = vtfont_lookup(vf, c);
+			vt_determine_colors(c,
+			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
+
+			ofwfb_bitblt_bitmap(vd, vw,
+			    pattern, NULL, vf->vf_width, vf->vf_height,
+			    x, y, fg, bg);
+		}
+	}
+
+#ifndef SC_NO_CUTPASTE
+	if (!vd->vd_mshown)
+		return;
+
+	term_rect_t drawn_area;
+
+	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
+	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
+	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
+	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
+
+	if (vt_is_cursor_in_area(vd, &drawn_area)) {
+		ofwfb_bitblt_bitmap(vd, vw,
+		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
+		    vd->vd_mcursor->width, vd->vd_mcursor->height,
+		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
+		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
+		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
+	}
+#endif
+}
+
 static void
 ofwfb_initialize(struct vt_device *vd)
 {

Modified: stable/10/sys/dev/vt/hw/vga/vt_vga.c
==============================================================================
--- stable/10/sys/dev/vt/hw/vga/vt_vga.c	Thu Sep  4 20:12:36 2014	(r271127)
+++ stable/10/sys/dev/vt/hw/vga/vt_vga.c	Thu Sep  4 20:18:08 2014	(r271128)
@@ -54,7 +54,8 @@ 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_curcolor;
+	int			 vga_wmode;
+	term_color_t		 vga_curfg, vga_curbg;
 };
 
 /* Convenience macros. */
@@ -71,13 +72,27 @@ struct vga_softc {
 #define	VT_VGA_HEIGHT	480
 #define	VT_VGA_MEMSIZE	(VT_VGA_WIDTH * VT_VGA_HEIGHT / 8)
 
+/*
+ * VGA is designed to handle 8 pixels at a time (8 pixels in one byte of
+ * memory).
+ */
+#define	VT_VGA_PIXELS_BLOCK	8
+
+/*
+ * We use an off-screen addresses to:
+ *     o  store the background color;
+ *     o  store pixels pattern.
+ * Those addresses are then loaded in the latches once.
+ */
+#define	VT_VGA_BGCOLOR_OFFSET	VT_VGA_MEMSIZE
+
 static vd_probe_t	vga_probe;
 static vd_init_t	vga_init;
 static vd_blank_t	vga_blank;
-static vd_bitbltchr_t	vga_bitbltchr;
+static vd_bitblt_text_t	vga_bitblt_text;
+static vd_bitblt_bmp_t	vga_bitblt_bitmap;
 static vd_drawrect_t	vga_drawrect;
 static vd_setpixel_t	vga_setpixel;
-static vd_putchar_t	vga_putchar;
 static vd_postswitch_t	vga_postswitch;
 
 static const struct vt_driver vt_vga_driver = {
@@ -85,10 +100,10 @@ static const struct vt_driver vt_vga_dri
 	.vd_probe	= vga_probe,
 	.vd_init	= vga_init,
 	.vd_blank	= vga_blank,
-	.vd_bitbltchr	= vga_bitbltchr,
+	.vd_bitblt_text	= vga_bitblt_text,
+	.vd_bitblt_bmp	= vga_bitblt_bitmap,
 	.vd_drawrect	= vga_drawrect,
 	.vd_setpixel	= vga_setpixel,
-	.vd_putchar	= vga_putchar,
 	.vd_postswitch	= vga_postswitch,
 	.vd_priority	= VD_PRIORITY_GENERIC,
 };
@@ -101,158 +116,74 @@ static struct vga_softc vga_conssoftc;
 VT_DRIVER_DECLARE(vt_vga, vt_vga_driver);
 
 static inline void
-vga_setcolor(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_curcolor != color) {
-		REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET);
-		REG_WRITE1(sc, VGA_GC_DATA, color);
-		sc->vga_curcolor = color;
-	}
-}
+	if (sc->vga_wmode == wmode)
+		return;
 
-static void
-vga_blank(struct vt_device *vd, term_color_t color)
-{
-	struct vga_softc *sc = vd->vd_softc;
-	u_int ofs;
+	REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE);
+	REG_WRITE1(sc, VGA_GC_DATA, wmode);
+	sc->vga_wmode = wmode;
 
-	vga_setcolor(vd, color);
-	for (ofs = 0; ofs < VT_VGA_MEMSIZE; ofs++)
-		MEM_WRITE1(sc, ofs, 0xff);
+	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_bitblt_put(struct vt_device *vd, u_long dst, term_color_t color,
-    uint8_t v)
+vga_setfg(struct vt_device *vd, term_color_t color)
 {
 	struct vga_softc *sc = vd->vd_softc;
 
-	/* Skip empty writes, in order to avoid palette changes. */
-	if (v != 0x00) {
-		vga_setcolor(vd, color);
-		/*
-		 * When this MEM_READ1() gets disabled, all sorts of
-		 * artifacts occur.  This is because this read loads the
-		 * set of 8 pixels that are about to be changed.  There
-		 * is one scenario where we can avoid the read, namely
-		 * if all pixels are about to be overwritten anyway.
-		 */
-		if (v != 0xff)
-			MEM_READ1(sc, dst);
-		MEM_WRITE1(sc, dst, v);
-	}
-}
-
-static void
-vga_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
-{
-
-	vga_bitblt_put(vd, (y * VT_VGA_WIDTH / 8) + (x / 8), color,
-	    0x80 >> (x % 8));
-}
+	vga_setwmode(vd, 3);
 
-static void
-vga_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
-    term_color_t color)
-{
-	int x, y;
+	if (sc->vga_curfg == color)
+		return;
 
-	for (y = y1; y <= y2; y++) {
-		if (fill || (y == y1) || (y == y2)) {
-			for (x = x1; x <= x2; x++)
-				vga_setpixel(vd, x, y, color);
-		} else {
-			vga_setpixel(vd, x1, y, color);
-			vga_setpixel(vd, x2, y, color);
-		}
-	}
+	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_bitblt_draw(struct vt_device *vd, const uint8_t *src,
-    u_long ldst, uint8_t shift, unsigned int width, unsigned int height,
-    term_color_t color, int negate)
-{
-	u_long dst;
-	int w;
-	uint8_t b, r, out;
-
-	for (; height > 0; height--) {
-		dst = ldst;
-		ldst += VT_VGA_WIDTH / 8;
-		r = 0;
-		for (w = width; w > 0; w -= 8) {
-			b = *src++;
-			if (negate) {
-				b = ~b;
-				/* Don't go too far. */
-				if (w < 8)
-					b &= 0xff << (8 - w);
-			}
-			/* Reintroduce bits from previous column. */
-			out = (b >> shift) | r;
-			r = b << (8 - shift);
-			vga_bitblt_put(vd, dst++, color, out);
-		}
-		/* Print the remainder. */
-		vga_bitblt_put(vd, dst, color, r);
-	}
-}
-
-static void
-vga_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
-    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
-    unsigned int height, term_color_t fg, term_color_t bg)
+vga_setbg(struct vt_device *vd, term_color_t color)
 {
-	u_long dst, ldst;
-	int w;
+	struct vga_softc *sc = vd->vd_softc;
 
-	/* Don't try to put off screen pixels */
-	if (((left + width) > VT_VGA_WIDTH) || ((top + height) >
-	    VT_VGA_HEIGHT))
-		return;
+	vga_setwmode(vd, 3);
 
-	dst = (VT_VGA_WIDTH * top + left) / 8;
+	if (sc->vga_curbg == color)
+		return;
 
-	for (; height > 0; height--) {
-		ldst = dst;
-		for (w = width; w > 0; w -= 8) {
-			vga_bitblt_put(vd, ldst, fg, *src);
-			vga_bitblt_put(vd, ldst, bg, ~*src);
-			ldst++;
-			src++;
-		}
-		dst += VT_VGA_WIDTH / 8;
-	}
-}
+	REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET);
+	REG_WRITE1(sc, VGA_GC_DATA, color);
 
-/* Bitblt with mask support. Slow. */
-static void
-vga_maskbitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
-    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
-    unsigned int height, term_color_t fg, term_color_t bg)
-{
-	struct vga_softc *sc = vd->vd_softc;
-	u_long dst;
-	uint8_t shift;
+	/*
+	 * Write 8 pixels using the background color to an off-screen
+	 * byte in the video memory.
+	 */
+	MEM_WRITE1(sc, VT_VGA_BGCOLOR_OFFSET, 0xff);
 
-	dst = (VT_VGA_WIDTH * top + left) / 8;
-	shift = left % 8;
+	/*
+	 * Read those 8 pixels back to load the background color in the
+	 * latches register.
+	 */
+	MEM_READ1(sc, VT_VGA_BGCOLOR_OFFSET);
 
-	/* Don't try to put off screen pixels */
-	if (((left + width) > VT_VGA_WIDTH) || ((top + height) >
-	    VT_VGA_HEIGHT))
-		return;
+	sc->vga_curbg = color;
 
-	if (sc->vga_curcolor == fg) {
-		vga_bitblt_draw(vd, src, dst, shift, width, height, fg, 0);
-		vga_bitblt_draw(vd, src, dst, shift, width, height, bg, 1);
-	} else {
-		vga_bitblt_draw(vd, src, dst, shift, width, height, bg, 1);
-		vga_bitblt_draw(vd, src, dst, shift, width, height, fg, 0);
-	}
+	/*
+         * The Set/Reset register doesn't contain the fg color anymore,
+         * store an invalid color.
+	 */
+	sc->vga_curfg = 0xff;
 }
 
 /*
@@ -381,25 +312,635 @@ vga_get_cp437(term_char_t c)
 }
 
 static void
-vga_putchar(struct vt_device *vd, term_char_t c,
-    vt_axis_t top, vt_axis_t left, term_color_t fg, term_color_t bg)
+vga_blank(struct vt_device *vd, term_color_t color)
 {
 	struct vga_softc *sc = vd->vd_softc;
-	uint8_t ch, attr;
+	u_int ofs;
+
+	vga_setfg(vd, color);
+	for (ofs = 0; ofs < VT_VGA_MEMSIZE; ofs++)
+		MEM_WRITE1(sc, ofs, 0xff);
+}
+
+static inline void
+vga_bitblt_put(struct vt_device *vd, u_long dst, term_color_t color,
+    uint8_t v)
+{
+	struct vga_softc *sc = vd->vd_softc;
+
+	/* Skip empty writes, in order to avoid palette changes. */
+	if (v != 0x00) {
+		vga_setfg(vd, color);
+		/*
+		 * When this MEM_READ1() gets disabled, all sorts of
+		 * artifacts occur.  This is because this read loads the
+		 * set of 8 pixels that are about to be changed.  There
+		 * is one scenario where we can avoid the read, namely
+		 * if all pixels are about to be overwritten anyway.
+		 */
+		if (v != 0xff) {
+			MEM_READ1(sc, dst);
+
+			/* The bg color was trashed by the reads. */
+			sc->vga_curbg = 0xff;
+		}
+		MEM_WRITE1(sc, dst, v);
+	}
+}
+
+static void
+vga_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
+{
+
+	vga_bitblt_put(vd, (y * VT_VGA_WIDTH / 8) + (x / 8), color,
+	    0x80 >> (x % 8));
+}
+
+static void
+vga_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
+    term_color_t color)
+{
+	int x, y;
+
+	for (y = y1; y <= y2; y++) {
+		if (fill || (y == y1) || (y == y2)) {
+			for (x = x1; x <= x2; x++)
+				vga_setpixel(vd, x, y, color);
+		} else {
+			vga_setpixel(vd, x1, y, color);
+			vga_setpixel(vd, x2, y, color);
+		}
+	}
+}
+
+static void
+vga_compute_shifted_pattern(const uint8_t *src, unsigned int bytes,
+    unsigned int src_x, unsigned int x_count, unsigned int dst_x,
+    uint8_t *pattern, uint8_t *mask)
+{
+	unsigned int n;
+
+	n = src_x / 8;
+
+	/*
+	 * This mask has bits set, where a pixel (ether 0 or 1)
+	 * comes from the source bitmap.
+	 */
+	if (mask != NULL) {
+		*mask = (0xff
+		    >> (8 - x_count))
+		    << (8 - x_count - dst_x);
+	}
+
+	if (n == (src_x + x_count - 1) / 8) {
+		/* All the pixels we want are in the same byte. */
+		*pattern = src[n];
+		if (dst_x >= src_x)
+			*pattern >>= (dst_x - src_x % 8);
+		else
+			*pattern <<= (src_x % 8 - dst_x);
+	} else {
+		/* The pixels we want are split into two bytes. */
+		if (dst_x >= src_x % 8) {
+			*pattern =
+			    src[n] << (8 - dst_x - src_x % 8) |
+			    src[n + 1] >> (dst_x - src_x % 8);
+		} else {
+			*pattern =
+			    src[n] << (src_x % 8 - dst_x) |
+			    src[n + 1] >> (8 - src_x % 8 - dst_x);
+		}
+	}
+}
+
+static void
+vga_copy_bitmap_portion(uint8_t *pattern_2colors, uint8_t *pattern_ncolors,
+    const uint8_t *src, const uint8_t *src_mask, unsigned int src_width,
+    unsigned int src_x, unsigned int dst_x, unsigned int x_count,
+    unsigned int src_y, unsigned int dst_y, unsigned int y_count,
+    term_color_t fg, term_color_t bg, int overwrite)
+{
+	unsigned int i, bytes;
+	uint8_t pattern, relevant_bits, mask;
+
+	bytes = (src_width + 7) / 8;
+
+	for (i = 0; i < y_count; ++i) {
+		vga_compute_shifted_pattern(src + (src_y + i) * bytes,
+		    bytes, src_x, x_count, dst_x, &pattern, &relevant_bits);
+
+		if (src_mask == NULL) {
+			/*
+			 * No src mask. Consider that all wanted bits
+			 * from the source are "authoritative".
+			 */
+			mask = relevant_bits;
+		} else {
+			/*
+			 * There's an src mask. We shift it the same way
+			 * we shifted the source pattern.
+			 */
+			vga_compute_shifted_pattern(
+			    src_mask + (src_y + i) * bytes,
+			    bytes, src_x, x_count, dst_x,
+			    &mask, NULL);
+
+			/* Now, only keep the wanted bits among them. */
+			mask &= relevant_bits;
+		}
+
+		/*
+		 * Clear bits from the pattern which must be
+		 * transparent, according to the source mask.
+		 */
+		pattern &= mask;
+
+		/* Set the bits in the 2-colors array. */
+		if (overwrite)
+			pattern_2colors[dst_y + i] &= ~mask;
+		pattern_2colors[dst_y + i] |= pattern;
+
+		if (pattern_ncolors == NULL)
+			continue;
+
+		/*
+		 * Set the same bits in the n-colors array. This one
+		 * supports transparency, when a given bit is cleared in
+		 * all colors.
+		 */
+		if (overwrite) {
+			/*
+			 * Ensure that the pixels used by this bitmap are
+			 * cleared in other colors.
+			 */
+			for (int j = 0; j < 16; ++j)
+				pattern_ncolors[(dst_y + i) * 16 + j] &=
+				    ~mask;
+		}
+		pattern_ncolors[(dst_y + i) * 16 + fg] |= pattern;
+		pattern_ncolors[(dst_y + i) * 16 + bg] |= (~pattern & mask);
+	}
+}
+
+static void
+vga_bitblt_pixels_block_2colors(struct vt_device *vd, const uint8_t *masks,
+    term_color_t fg, term_color_t bg,
+    unsigned int x, unsigned int y, unsigned int height)
+{
+	unsigned int i, offset;
+	struct vga_softc *sc;
+
+	/*
+	 * The great advantage of Write Mode 3 is that we just need
+	 * to load the foreground in the Set/Reset register, load the
+	 * background color in the latches register (this is done
+	 * through a write in offscreen memory followed by a read of
+	 * that data), then write the pattern to video memory. This
+	 * pattern indicates if the pixel should use the foreground
+	 * color (bit set) or the background color (bit cleared).
+	 */
+
+	vga_setbg(vd, bg);
+	vga_setfg(vd, fg);
+
+	sc = vd->vd_softc;
+	offset = (VT_VGA_WIDTH * y + x) / 8;
+
+	for (i = 0; i < height; ++i, offset += VT_VGA_WIDTH / 8) {
+		MEM_WRITE1(sc, offset, masks[i]);
+	}
+}
+
+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, plan, color, offset;
+	struct vga_softc *sc;
+	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.
+	 */
+
+	/*
+	 * 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
+	 *
+	 * 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 (color = 0; color < 16; ++color) {
+			mask = masks[i * 16 + color];
+			if (mask == 0x00)
+				continue;
+
+			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);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409042018.s84KI9Pm028441>