Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 14 Mar 2018 08:15:26 +0000 (UTC)
From:      Eitan Adler <eadler@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r330920 - stable/11/sys/dev/syscons
Message-ID:  <201803140815.w2E8FQKO087728@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: eadler
Date: Wed Mar 14 08:15:26 2018
New Revision: 330920
URL: https://svnweb.freebsd.org/changeset/base/330920

Log:
  MFC r316636,r316642,r316675,r316733,r316737,r316741,r316827,r316830,r316865,r316878:
  
  Fix removal of the keyboard cursor image in text mode, especially
  in the vga renderer.  Removal used stale attributes and didn't try to
  merge with the current attribute for cut marking, so special rendering
  of cut marking was lost in many cases.  The gfb renderer is too broken
  to support special rendering of cut marking at all, so this change is
  supposed to be just a style fix for it.  Remove all traces of the
  saveunder method which was used to implement this bug.
  
  Fix drawing of the cursor image in text mode, only in the vga
  renderer.  This used a stale attribute from the frame buffer instead
  of from the saveunder, but did merge with the current attribute for
  cut marking so it caused less obvious bugs (subtle misrendering for
  the character under the cursor).
  
  The saveunder method may be good in simpler drivers, but in syscons
  the 'under' is already saved in a better way in the vtb.  Just redraw
  it from there, with visible complications for cut marking and
  invisible complications for mouse cursors.  Almost all drawing
  requests are passed a flag 'flip' which currently means to flip to
  reverse video for characters in the cut marking region, but should
  mean that the the characters are in the cut marking regions so should
  be rendered specially, preferably using something better than reverse
  video.  The gfb renderer always ignores this flag.  The vga renderer
  ignored it for removal of the text cursor -- the saveunder gave the
  stale rendering at the time the cursor was drawn.  Mouse cursors need
  even more complicated methods.  They are handled by drawing them last
  and removing them first.  Removing them usually redraws many other
  characters with the correct cut marking (but transiently loses the
  keyboard cursor, which is redrawn soon).  This tended to hide the
  saveunder bug for forward motions of the keyboard cursor.  But slow
  backward motions of the keyboard cursor always lost the cut marking,
  and fast backwards motions lost in for about 4 in every 5 characters,
  depending on races with the scrn_update() timeout handler.  This is
  because the forward motions are usually into the region redrawn for
  the mouse cursor, while backwards motions rarely are.
  
  Text cursor drawing in the vga renderer used also used a
  possibly-stale copy of the character and its attribute.  The vga
  render has the "optimization" of sometimes reading characters from the
  screen instead of from the vtb (this was not so good even in 1990 when
  main memory was only a few times faster than video RAM).  Due to care
  in update orders, the character is never stale, but its attribute
  might be (just the cut marking part, again due to care in order).
  
  gfb doesn't have the scp->scr pointer used for the "optimization", and
  vga only uses this pointer for text mode.  So most cases have to
  refresh from the vtb, and we can be sure that the ordering of vtb
  updates and drawing is as required for this to work.
  
  ------------------------------------------------------------------------
  r316642 | bde | 2017-04-08 10:00:39 +0000 (Sat, 08 Apr 2017) | 36 lines
  
  Quick fix for removal of the mouse cursor in vga direct graphics modes
  (that is, in all supported 8, 15, 16 and 24-color modes).  Moving the
  mouse cursor while holding down a button (giving cut marking) left a
  trail of garbage from misremoved mouse cursors (usually colored
  rectangles and not cursor shapes).  Cases with a button not held down
  worked better and may even have worked.
  
  No renderer support for removing (software) mouse cursors is needed
  (and many renderers don't have any), since sc_remove_mouse_image()
  marks for update the region containing the image and usually much
  more.  The mouse cursor can be (partially) over as many as 4 character
  cells, and removing it in only the 1-4 cells occupied by it would be
  best for efficiency and for avoiding flicker.  However,
  sc_remove_mouse_image() can only mark a single linear region and
  usually marks a full row of cells and 1 more to be sure to cover the
  4 cells.  It always does this, so using the special rendering method
  just wastes even more time and gives even more flicker.  The special
  methods will be removed soon.
  
  The general method always works.  vga_pxlmouse_direct() appeared to
  defer to it by returning immediately if !on.  However,
  vga_pxlmouse_direct() actually did foot-shooting using a disguised
  saveunder method.  Normal order near a mouse move is:
    (1) remove the mouse cursor in the renderer (optional)
    (2) remove the mouse cursor again and refresh the screen over the
        mouse cursor and much more from the vtb.  When the mouse has
        actually moved and a button is down, many attributes in this
        region are changed to be up to date with the new cut marking
    (3) draw the keyboard cursor again if it was clobbered by the update
    (4) draw the mouse cursor image in its new position.
  The bug was to remove the mouse cursor again in step (4), before the
  drawing it again in (4), using a saveunder that was valid in step (1)
  at best.  The quick fix is to use the saveunder in step (1) and not
  in step (4).  Using it in step (4) also used it before it was
  initialized, initially and after  mode and screen switches.
  
  ------------------------------------------------------------------------
  r316675 | bde | 2017-04-10 06:19:09 +0000 (Mon, 10 Apr 2017) | 29 lines
  
  Special rendering methods for removing mouse cursors cannot be removed
  like I hoped, since they are needed for removing parts over the border.
  Continue fixing bugs in them.
  
  In the vga planar mode renderer, remove removal of the part of the
  image over the text window.  This was hard-coded for nearly 8x16 fonts
  and in practice didn't remove enough for 8x8 fonts.  This used the
  wrong attribute over cutmarked regions.  The caller refreshes with the
  correct attribute later, so the attribute bug only caused flicker.
  The caller uses the same hard-coding, so the refreshes fix up all the
  spots with the wrong attribute, but keep missing the missed spots.
  This still gives trails of bits of cursors for cursor motions in the
  affected configurations (mainly depth 4 modes with 8x8) fonts.  8x14
  fonts barely escape the problem since although the cursor is drawn
  as 16x16, its active part is only 9x13 and the active part fits in
  the hard-coded 2x2 character cell window for 8x14 fonts.  8x8 fonts
  need a 2x3 window.
  
  In the fb non-sparc64 renderer, the buggy image removal was buggier
  and was already avoided by returning before it.  Remove it completely
  and fix nearby style bugs.  It was essentially the same as for the vga
  planar mode renderer (obfuscated by swapping x and y).  This was buggier
  since fb should handle more types of hardware so the hard-coding is
  wronger.
  
  The remaining fb image removal is also buggier.  It never supported
  software cursors drawn into the border, and the hardware cursor is
  probably broken by other bugs to be fixed soon.
  
  ------------------------------------------------------------------------
  r316733 | bde | 2017-04-12 16:21:55 +0000 (Wed, 12 Apr 2017) | 45 lines
  
  Fix clobbering of the default attribute and the screen position in
  scteken_init().  Move the internals of scteken_sync() into a local
  function to help do this.
  
  scteken_init() reset or adjusted the default attribute and screen
  position at least 3 and 5 times, respectively.  Warm init shouldn't
  do any more than reset the "input" state.
    (scterm-sc.c (which still works after minor editing), only resets
    the escape state and the saved cursor position, and then does a
    nearly-null sync of the current color.)
  
  This mainly broke mode changes, and was most noticeable when the
  background color is not teken's default (usually black).  Then the
  screen gets cleared in the wrong color.  vidcontrol restores the
  default normal attribute and tries to restore the default reverse
  attribute.  vidcontrol doesn't clear the screen again after restoring
  the attribute(s), and it is too late to do it there without flicker.
  Now the default normal attribute is restored before the change affects
  the rendering.
  
  When the foreground color is not teken's default, clearing with the
  wrong attributes gave strange cursor colors for some cursor types.
  
  The default reverse attribute is not restored since it is unsupported.
  
  2/3 of the clobbering was from 2 resetting window resizing calls.  The
  second one is needed to restore the size, but must not reset.  Window
  resizing also sanitizes the cursor position, and after the main reset
  resets the window size, the cursor row would often be adjusted from
  24 to 23 if it were not already reset to 0.  scteken_sync() is good
  for restoring the window size and the cursor position in the correct
  order, but was unusable at init time since scp->ts is not always
  initialized then.  Adjust to use its internals.
  
  I didn't notice any problems from the cursor reset.  The cursor should
  be reset, and a previous fix was to reset it consistently a little
  later.
  
  Doing nothing for warm init works almost as well, if not better.  It
  is not very useful to reset the escape state for mode changes, since
  the reset is especially likely to be null then.  The escape state is
  most likely to be non-initial and corrupted by its most normal uses
  -- sloppy non-atomic output where a context switch or just mixing
  stdout with stderr splits up escape sequences.
  
  ------------------------------------------------------------------------
  r316737 | bde | 2017-04-12 18:52:06 +0000 (Wed, 12 Apr 2017) | 23 lines
  
  Fix removal of mouse image by the vga planar renderer in the right border
  in unusual cases.  Optimize and significantly clean up removal in this
  renderer.  Optimize removal in the vga direct renderer.
  
  Removal only needs to be done in the border (the part with pixels) in
  both cases.  The planar renderer used the condition scp->xoff > 0 to
  test whether a right border exists.  This actually tests for a left
  border, and when the total horizontal border is 8 pixels, rounding gives
  only a right border.  This was the unusual broken case.  An example
  is easy to configure using something like "vidcontrol -f 8x16 iso-8x16
  -g 79x25 MODE_27".
  
  Optimize the planar case a little by only removing 9x13 active pixels
  out of 16x16.  Optimize it a lot by not doing anything if there is no
  overlap with the border.  Don't unroll the main loop or hard-code so
  many assumptions about font sizes in it.  On my Haswell system, graphics
  memory and i/o accesses takes about 520 cycles each so optimizations from
  unrolling are in the noise.
  
  Optimize the direct case to not do anything if there is no overlap with
  the border.  Do a sanity check on the saveunder's coordinates.  This
  requires a previous change to pass non-rounded coordinates.
  
  ------------------------------------------------------------------------
  r316741 | bde | 2017-04-12 20:18:38 +0000 (Wed, 12 Apr 2017) | 24 lines
  
  Improve drawing of the vga planar mode mouse image a little.  Unobfuscate
  the method a lot.
  
  Reduce the AND mask to the complement of the cursor's frame, so that area
  inside the frame is not drawn first in black and then in lightwhite.  The
  AND-OR method is only directly suitable for the text mouse image, since
  it doesn't go to the hardware there.  Planar mode Mouse cursor drawing
  takes 10-20 usec on my Haswell system (approx. 100 graphics accesses
  at 130 nsec each), so the transient was not visible.
  
  The method used the fancy read mode 1 and its color compare and color
  don't care registers with value 0 in them so that all colors matched.
  All that this did was make byte reads of frame buffer memory return 0xff,
  so that the x86 case could obfuscate read+write as "and".  The read must
  be done for its side effect on the graphics controller but is not used,
  except it must return 0xff to avoid affecting the write when the write
  is obfuscated as a read-modify-write "and".  Perhaps that was a good
  optimization for 8088 CPUs where each extra instruction byte took as
  long as a byte memory access.
  
  Just use read+write after removing the fancy read mode.  Remove x86
  ifdefs that did the "and".  After removing the "and" in the non-x86
  part of the ifdefs, fix 4 of 6 cases where the shift was wrong.
  
  ------------------------------------------------------------------------
  r316827 | bde | 2017-04-14 12:03:34 +0000 (Fri, 14 Apr 2017) | 19 lines
  
  Further unobfuscate the method of drawing the mouse cursor in vga planar
  mode.
  
  Don't manually unroll the 2 inner loops.  On Haswell, doing so gave a
  speedup of about 0.5% (about 4 cycles per iteration out of 1400), but
  hard-coded a limit of width 9 and made better better optimizations
  harder to see.  gcc-4.2.1 -O does the unrolling anyway, unless tricked
  with a volatile hack.  gcc's unrolling is not very good and gives a
  a speedup of about half as much (about 2 cycles per iteration).  (All
  timing on i386.)
  
  Manual unrolling was only feasible because the inner loop only iterates
  once or twice.  Usually twice, but a dynamic check is needed to decide,
  and was not moved from the second-innermost loop manually or by gcc.
  This commit basically adds another dynamic check in the inner loop.
  
  Cursor widths of 10-17 require 3 iterations in the inner loop and this
  is not so easy to unroll -- even gcc stops at 2.
  
  ------------------------------------------------------------------------
  r316830 | bde | 2017-04-14 14:00:13 +0000 (Fri, 14 Apr 2017) | 13 lines
  
  Optimize drawing of the mouse cursor in vga planar mode almost as
  much as possible, by avoiding null ANDs and ORs to the frame buffer.
  
  Mouse cursors are fairly sparse, especially for their frame.  Pixels
  are written in groups of 8 in planar mode and the per-group sparseness
  is not as large, but it still averages about 40% with the current
  9x13 mouse cursor.  The average drawing time is reduced by about this
  amount (from 22 usec constant to 12.5 usec average on Haswell).
  
  This optimization is relatively larger with larger cursors.  Width 10
  requires 6 frame buffer accesses per line instead of 4 if not done
  sparsely, but rarely more than 4 if done sparsely.
  
  ------------------------------------------------------------------------
  r316865 | bde | 2017-04-14 17:02:24 +0000 (Fri, 14 Apr 2017) | 10 lines
  
  Adjust shifting so that cursor widths up to 17 (was 9) work in vga planar
  mode.
  
  Direct mode always supported widths up to 32, except for its hard-coded
  16s matching the pixmap size.  Text mode is still limited to 9 its 2x2
  character cell method and missing adjustments for the gap between
  characters, if any.
  
  Cursor heights can be almost anything in graphics modes.

Modified:
  stable/11/sys/dev/syscons/scgfbrndr.c
  stable/11/sys/dev/syscons/scterm-teken.c
  stable/11/sys/dev/syscons/scvgarndr.c
  stable/11/sys/dev/syscons/syscons.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/syscons/scgfbrndr.c
==============================================================================
--- stable/11/sys/dev/syscons/scgfbrndr.c	Wed Mar 14 07:58:11 2018	(r330919)
+++ stable/11/sys/dev/syscons/scgfbrndr.c	Wed Mar 14 08:15:26 2018	(r330920)
@@ -273,13 +273,11 @@ gfb_cursor(scr_stat *scp, int at, int blink, int on, i
 			c = sc_vtb_getc(&scp->vtb, at);
 			vidd_putc(scp->sc->adp, at, c,
 			    (a >> 4) | ((a & 0xf) << 4));
-			scp->cursor_saveunder_attr = a;
-			scp->cursor_saveunder_char = c;
 		} else {
 			if (scp->status & VR_CURSOR_ON)
 				vidd_putc(scp->sc->adp, at,
-				    scp->cursor_saveunder_char,
-				    scp->cursor_saveunder_attr);
+				    sc_vtb_getc(&scp->vtb, at),
+				    sc_vtb_geta(&scp->vtb, at) >> 8);
 			scp->status &= ~VR_CURSOR_ON;
 		}
 	}
@@ -339,28 +337,14 @@ static void 
 gfb_mouse(scr_stat *scp, int x, int y, int on)
 {
 #ifdef __sparc64__
-		vidd_putm(scp->sc->adp, x, y, mouse_pointer,
-		    on ? 0xffffffff : 0x0, 22, 12);
+	vidd_putm(scp->sc->adp, x, y, mouse_pointer,
+	    on ? 0xffffffff : 0x0, 22, 12);
 #else
-	int i, pos;
-
 	if (on) {
-
-		/* Display the mouse pointer image... */
 		vidd_putm(scp->sc->adp, x, y, mouse_pointer,
 		    0xffffffff, 16, 8);
 	} else {
-
-		/*
-		   Erase the mouse cursor image by redrawing the text
-		   underneath it...
-		*/
-		return;
-		pos = x*scp->xsize + y;
-		i = (y < scp->xsize - 1) ? 2 : 1;
-		(*scp->rndr->draw)(scp, pos, i, FALSE);
-		if (x < scp->ysize - 1)
-			(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
+		/* XXX: removal is incomplete for h/w cursors and borders. */
 	}
 #endif
 }

Modified: stable/11/sys/dev/syscons/scterm-teken.c
==============================================================================
--- stable/11/sys/dev/syscons/scterm-teken.c	Wed Mar 14 07:58:11 2018	(r330919)
+++ stable/11/sys/dev/syscons/scterm-teken.c	Wed Mar 14 08:15:26 2018	(r330920)
@@ -74,6 +74,8 @@ typedef struct {
 
 static teken_stat	reserved_teken_stat;
 
+static void scteken_sync_internal(scr_stat *, teken_stat *);
+
 static sc_term_sw_t sc_term_scteken = {
 	{ NULL, NULL },
 	"scteken",			/* emulator name */
@@ -118,7 +120,7 @@ static int
 scteken_init(scr_stat *scp, void **softc, int code)
 {
 	teken_stat *ts;
-	teken_pos_t tp;
+	teken_attr_t ta;
 
 	if (*softc == NULL) {
 		if (reserved_teken_stat.ts_busy)
@@ -133,17 +135,16 @@ scteken_init(scr_stat *scp, void **softc, int code)
 		ts->ts_busy = 1;
 		/* FALLTHROUGH */
 	case SC_TE_WARM_INIT:
+		ta = *teken_get_defattr(&ts->ts_teken);
 		teken_init(&ts->ts_teken, &scteken_funcs, scp);
+		teken_set_defattr(&ts->ts_teken, &ta);
 #ifndef TEKEN_UTF8
 		teken_set_8bit(&ts->ts_teken);
 #endif /* !TEKEN_UTF8 */
 #ifdef TEKEN_CONS25
 		teken_set_cons25(&ts->ts_teken);
 #endif /* TEKEN_CONS25 */
-
-		tp.tp_row = scp->ysize;
-		tp.tp_col = scp->xsize;
-		teken_set_winsize(&ts->ts_teken, &tp);
+		scteken_sync_internal(scp, ts);
 		break;
 	}
 
@@ -221,7 +222,7 @@ scteken_clear(scr_stat *scp)
 	teken_stat *ts = scp->ts;
 
 	sc_move_cursor(scp, 0, 0);
-	scteken_sync(scp);
+	scteken_sync_internal(scp, ts);
 	sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20],
 		     scteken_te_to_sc_attr(teken_get_curattr(&ts->ts_teken))
 		     << 8);
@@ -286,9 +287,8 @@ scteken_fkeystr(scr_stat *scp, int c)
 }
 
 static void
-scteken_sync(scr_stat *scp)
+scteken_sync_internal(scr_stat *scp, teken_stat *ts)
 {
-	teken_stat *ts = scp->ts;
 	teken_pos_t tp;
 
 	tp.tp_col = scp->xsize;
@@ -297,6 +297,12 @@ scteken_sync(scr_stat *scp)
 	tp.tp_col = scp->xpos;
 	tp.tp_row = scp->ypos;
 	teken_set_cursor(&ts->ts_teken, &tp);
+}
+
+static void
+scteken_sync(scr_stat *scp)
+{
+	scteken_sync_internal(scp, scp->ts);
 }
 
 static void

Modified: stable/11/sys/dev/syscons/scvgarndr.c
==============================================================================
--- stable/11/sys/dev/syscons/scvgarndr.c	Wed Mar 14 07:58:11 2018	(r330919)
+++ stable/11/sys/dev/syscons/scvgarndr.c	Wed Mar 14 08:15:26 2018	(r330920)
@@ -161,6 +161,8 @@ RENDERER_MODULE(vga, vga_set);
 
 #ifndef SC_NO_CUTPASTE
 #if !defined(SC_ALT_MOUSE_IMAGE) || defined(SC_PIXEL_MODE)
+#define	MOUSE_IMAGE_HEIGHT	13
+#define	MOUSE_IMAGE_WIDTH	9
 static u_short mouse_and_mask[16] = {
 	0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
 	0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
@@ -296,8 +298,6 @@ draw_txtcharcursor(scr_stat *scp, int at, u_short c, u
 	sc_softc_t *sc;
 
 	sc = scp->sc;
-	scp->cursor_saveunder_char = c;
-	scp->cursor_saveunder_attr = a;
 
 #ifndef SC_NO_FONT_LOADING
 	if (scp->curs_attr.flags & CONS_CHAR_CURSOR) {
@@ -374,18 +374,18 @@ vga_txtcursor(scr_stat *scp, int at, int blink, int on
 		if (on) {
 			scp->status |= VR_CURSOR_ON;
 			draw_txtcharcursor(scp, at,
-					   sc_vtb_getc(&scp->scr, at),
-					   sc_vtb_geta(&scp->scr, at),
+					   sc_vtb_getc(&scp->vtb, at),
+					   sc_vtb_geta(&scp->vtb, at),
 					   flip);
 		} else {
-			cursor_attr = scp->cursor_saveunder_attr;
+			cursor_attr = sc_vtb_geta(&scp->vtb, at);
 			if (flip)
 				cursor_attr = (cursor_attr & 0x8800)
 					| ((cursor_attr & 0x7000) >> 4)
 					| ((cursor_attr & 0x0700) << 4);
 			if (scp->status & VR_CURSOR_ON)
 				sc_vtb_putc(&scp->scr, at,
-					    scp->cursor_saveunder_char,
+					    sc_vtb_getc(&scp->vtb, at),
 					    cursor_attr);
 			scp->status &= ~VR_CURSOR_ON;
 		}
@@ -1032,71 +1032,44 @@ draw_pxlmouse_planar(scr_stat *scp, int x, int y)
 	int line_width;
 	int xoff, yoff;
 	int ymax;
-	u_short m;
-	int i, j;
+	uint32_t m;
+	int i, j, k;
+	uint8_t m1;
 
 	line_width = scp->sc->adp->va_line_width;
 	xoff = (x - scp->xoff*8)%8;
 	yoff = y - rounddown(y, line_width);
 	ymax = imin(y + 16, scp->ypixel);
 
-	outw(GDCIDX, 0x0805);		/* read mode 1, write mode 0 */
+	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
 	outw(GDCIDX, 0x0001);		/* set/reset enable */
-	outw(GDCIDX, 0x0002);		/* color compare */
-	outw(GDCIDX, 0x0007);		/* color don't care */
 	outw(GDCIDX, 0xff08);		/* bit mask */
 	outw(GDCIDX, 0x0803);		/* data rotate/function select (and) */
 	p = scp->sc->adp->va_window + line_width*y + x/8;
-	if (x < scp->xpixel - 8) {
-		for (i = y, j = 0; i < ymax; ++i, ++j) {
-			m = ~(mouse_and_mask[j] >> xoff);
-#if defined(__i386__) || defined(__amd64__)
-			*(u_char *)p &= m >> 8;
-			*(u_char *)(p + 1) &= m;
-#else
-			writeb(p, readb(p) & (m >> 8));
-			writeb(p + 1, readb(p + 1) & (m >> 8));
-#endif
-			p += line_width;
+	for (i = y, j = 0; i < ymax; ++i, ++j) {
+		m = ~((mouse_and_mask[j] & ~mouse_or_mask[j]) << 8 >> xoff);
+		for (k = 0; k < 3; ++k) {
+			m1 = m >> (8 * (2 - k));
+			if (m1 != 0xff && x + 8 * k < scp->xpixel) {
+				readb(p + k);
+				writeb(p + k, m1);
+ 			}
 		}
-	} else {
-		xoff += 8;
-		for (i = y, j = 0; i < ymax; ++i, ++j) {
-			m = ~(mouse_and_mask[j] >> xoff);
-#if defined(__i386__) || defined(__amd64__)
-			*(u_char *)p &= m;
-#else
-			writeb(p, readb(p) & (m >> 8));
-#endif
-			p += line_width;
-		}
+		p += line_width;
 	}
 	outw(GDCIDX, 0x1003);		/* data rotate/function select (or) */
 	p = scp->sc->adp->va_window + line_width*y + x/8;
-	if (x < scp->xpixel - 8) {
-		for (i = y, j = 0; i < ymax; ++i, ++j) {
-			m = mouse_or_mask[j] >> xoff;
-#if defined(__i386__) || defined(__amd64__)
-			*(u_char *)p &= m >> 8;
-			*(u_char *)(p + 1) &= m;
-#else
-			writeb(p, readb(p) & (m >> 8));
-			writeb(p + 1, readb(p + 1) & (m >> 8));
-#endif
-			p += line_width;
+	for (i = y, j = 0; i < ymax; ++i, ++j) {
+		m = mouse_or_mask[j] << 8 >> xoff;
+		for (k = 0; k < 3; ++k) {
+			m1 = m >> (8 * (2 - k));
+			if (m1 != 0 && x + 8 * k < scp->xpixel) {
+				readb(p + k);
+				writeb(p + k, m1);
+			}
 		}
-	} else {
-		for (i = y, j = 0; i < ymax; ++i, ++j) {
-			m = mouse_or_mask[j] >> xoff;
-#if defined(__i386__) || defined(__amd64__)
-			*(u_char *)p &= m;
-#else
-			writeb(p, readb(p) & (m >> 8));
-#endif
-			p += line_width;
-		}
+		p += line_width;
 	}
-	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
 }
 
@@ -1104,54 +1077,31 @@ static void
 remove_pxlmouse_planar(scr_stat *scp, int x, int y)
 {
 	vm_offset_t p;
-	int col, row;
-	int pos;
-	int line_width;
-	int ymax;
-	int i;
+	int bx, by, i, line_width, xend, xoff, yend, yoff;
 
-	/* erase the mouse cursor image */
-	col = x/8 - scp->xoff;
-	row = y/scp->font_size - scp->yoff;
-	pos = row*scp->xsize + col;
-	i = (col < scp->xsize - 1) ? 2 : 1;
-	(*scp->rndr->draw)(scp, pos, i, FALSE);
-	if (row < scp->ysize - 1)
-		(*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
+	/*
+	 * It is only necessary to remove the mouse image where it overlaps
+	 * the border.  Determine the overlap, and do nothing if it is empty.
+	 */
+	bx = (scp->xoff + scp->xsize) * 8;
+	by = (scp->yoff + scp->ysize) * scp->font_size;
+	xend = imin(x + MOUSE_IMAGE_WIDTH, scp->xpixel);
+	yend = imin(y + MOUSE_IMAGE_HEIGHT, scp->ypixel);
+	if (xend <= bx && yend <= by)
+		return;
 
-	/* paint border if necessary */
+	/* Repaint the non-empty overlap. */
 	line_width = scp->sc->adp->va_line_width;
 	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
 	outw(GDCIDX, 0x0003);		/* data rotate/function select */
 	outw(GDCIDX, 0x0f01);		/* set/reset enable */
 	outw(GDCIDX, 0xff08);		/* bit mask */
 	outw(GDCIDX, (scp->border << 8) | 0x00);	/* set/reset */
-	if (row == scp->ysize - 1) {
-		i = (scp->ysize + scp->yoff)*scp->font_size;
-		ymax = imin(i + scp->font_size, scp->ypixel);
-		p = scp->sc->adp->va_window + i*line_width + scp->xoff + col;
-		if (col < scp->xsize - 1) {
-			for (; i < ymax; ++i) {
-				writeb(p, 0);
-				writeb(p + 1, 0);
-				p += line_width;
-			}
-		} else {
-			for (; i < ymax; ++i) {
-				writeb(p, 0);
-				p += line_width;
-			}
-		}
-	}
-	if ((col == scp->xsize - 1) && (scp->xoff > 0)) {
-		i = (row + scp->yoff)*scp->font_size;
-		ymax = imin(i + scp->font_size*2, scp->ypixel);
-		p = scp->sc->adp->va_window + i*line_width
-			+ scp->xoff + scp->xsize;
-		for (; i < ymax; ++i) {
+	for (i = x / 8, xoff = i * 8; xoff < xend; ++i, xoff += 8) {
+		yoff = (xoff >= bx) ? y : by;
+		p = scp->sc->adp->va_window + yoff * line_width + i;
+		for (; yoff < yend; ++yoff, p += line_width)
 			writeb(p, 0);
-			p += line_width;
-		}
 	}
 	outw(GDCIDX, 0x0000);		/* set/reset */
 	outw(GDCIDX, 0x0001);		/* set/reset enable */
@@ -1171,7 +1121,14 @@ vga_pxlmouse_direct(scr_stat *scp, int x, int y, int o
 	uint8_t  *u8;
 	int bpp;
 
-	if (!on)
+	/*
+	 * Determine overlap with the border and then if removing, do nothing
+	 * if the overlap is empty.
+	 */
+	xend = imin(x + 16, scp->xpixel);
+	yend = imin(y + 16, scp->ypixel);
+	if (!on && xend <= (scp->xoff + scp->xsize) * 8 &&
+	    yend <= (scp->yoff + scp->ysize) * scp->font_size)
 		return;
 
 	bpp = scp->sc->adp->va_info.vi_depth;
@@ -1182,9 +1139,18 @@ vga_pxlmouse_direct(scr_stat *scp, int x, int y, int o
 	line_width = scp->sc->adp->va_line_width;
 	pixel_size = scp->sc->adp->va_info.vi_pixel_size;
 
-	xend = imin(x + 16, scp->xpixel);
-	yend = imin(y + 16, scp->ypixel);
+	if (on)
+		goto do_on;
 
+	/*
+	 * Repaint overlap with the border and nearby.  Unlike in the planar
+	 * case, we kept track of everything under the cursor so can restore
+	 * it all, but we don't completely trust the saved state to be still
+	 * relevant, so do nothing if it is obviously stale.
+	 */
+	if (x != x_old || y != y_old || xend != xend_old || yend != yend_old)
+		return;
+
 	p = scp->sc->adp->va_window + y_old * line_width + x_old * pixel_size;
 
 	for (i = 0; i < (yend_old - y_old); i++) {
@@ -1209,7 +1175,9 @@ vga_pxlmouse_direct(scr_stat *scp, int x, int y, int o
 
 		p += line_width;
 	}
+	return;
 
+do_on:
 	p = scp->sc->adp->va_window + y * line_width + x * pixel_size;
 
 	for (i = 0; i < (yend - y); i++) {

Modified: stable/11/sys/dev/syscons/syscons.h
==============================================================================
--- stable/11/sys/dev/syscons/syscons.h	Wed Mar 14 07:58:11 2018	(r330919)
+++ stable/11/sys/dev/syscons/syscons.h	Wed Mar 14 08:15:26 2018	(r330920)
@@ -322,8 +322,6 @@ typedef struct scr_stat {
 
 	int		cursor_pos;		/* cursor buffer position */
 	int		cursor_oldpos;		/* cursor old buffer position */
-	u_short		cursor_saveunder_char;	/* saved char under cursor */
-	u_short		cursor_saveunder_attr;	/* saved attr under cursor */
 	struct cursor_attr dflt_curs_attr;
 	struct cursor_attr curr_curs_attr;
 	struct cursor_attr curs_attr;



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