Date: Mon, 10 Mar 1997 10:06:27 +0100 (MET)
From: Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
To: Linux/m68k <linux-m68k@phil.uni-sb.de>
Subject: L68K: Experimental console speedup
Sender: owner-linux-m68k@phil.uni-sb.de
Reply-To: linux-m68k@phil.uni-sb.de


This experimental patch speeds up scrolling of parts of the screen. The idea is
that if you want to scroll the whole screen but a few lines, it's faster to
scroll the whole screen using ywrap/ypan and to restore the few lines you
didn't want to scroll. Of course this only works if ywrap/ypan is possible.

Caveats:

  - The scrolling seems to interfere with the cursor, although I do undraw the
    cursor before scrolling. Any clues?

  - Sometimes it looks ugly (the scrolling and restoring of the lines that
    don't need to be scrolled), especially on high depth screens.

What do you think about this?

Of course a 100% working copper console would be better (Jesper: hint, hint :-)


The patch also fixes some small bugs (last 3 chunks) that unnecessarily slowed
down fbcon_bmove() on monochrome, ilbm and planar frame buffers.

--- linux/arch/m68k/console/fbcon.c.orig	Thu Mar  6 21:46:35 1997
+++ linux/arch/m68k/console/fbcon.c	Sun Mar  9 22:43:04 1997
@@ -287,6 +287,13 @@
 static __inline__ u_short dup2w(u_char c);
 static __inline__ int real_y(struct display *p, int y);
 static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
+static __inline__ void updatescrollmode(struct display *p);
+static __inline__ void ywrap_up(int unit, struct display *p, int count);
+static __inline__ void ywrap_down(int unit, struct display *p, int count);
+static __inline__ void ypan_up(int unit, struct vc_data *conp,
+			       struct display *p, int count);
+static __inline__ void ypan_down(int unit, struct vc_data *conp,
+				 struct display *p, int count);
 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
                             int height, int width, u_int y_break);
 
@@ -617,14 +624,7 @@
       printk("fbcon_setup: No support for fontwidth != 8");
       p->fontwidth = 8;
    }
-
-   if (divides(p->ywrapstep, p->fontheight) && divides(p->fontheight, p->var.yres_virtual))
-      p->scrollmode = SCROLL_YWRAP;
-   else if (divides(p->ypanstep, p->fontheight) &&
-            p->var.yres_virtual >= p->var.yres+p->fontheight)
-      p->scrollmode = SCROLL_YPAN;
-   else
-      p->scrollmode = SCROLL_YMOVE;
+   updatescrollmode(p);
 
    nr_cols = p->var.xres/p->fontwidth;
    nr_rows = p->var.yres/p->fontheight;
@@ -1561,6 +1561,75 @@
 }
 
 
+static __inline__ void updatescrollmode(struct display *p)
+{
+   if (divides(p->ywrapstep, p->fontheight) &&
+       divides(p->fontheight, p->var.yres_virtual))
+      p->scrollmode = SCROLL_YWRAP;
+   else if (divides(p->ypanstep, p->fontheight) &&
+            p->var.yres_virtual >= p->var.yres+p->fontheight)
+      p->scrollmode = SCROLL_YPAN;
+   else
+      p->scrollmode = SCROLL_YMOVE;
+}
+
+
+static __inline__ void ywrap_up(int unit, struct display *p, int count)
+{
+   p->yscroll += count;
+   if (p->yscroll >= p->vrows)	/* Deal with wrap */
+      p->yscroll -= p->vrows;
+   p->var.xoffset = 0;
+   p->var.yoffset = p->yscroll*p->fontheight;
+   p->var.vmode |= FB_VMODE_YWRAP;
+   fb_info->updatevar(unit);
+}
+
+
+static __inline__ void ywrap_down(int unit, struct display *p, int count)
+{
+   p->yscroll -= count;
+   if (p->yscroll < 0)		/* Deal with wrap */
+      p->yscroll += p->vrows;
+   p->var.xoffset = 0;
+   p->var.yoffset = p->yscroll*p->fontheight;
+   p->var.vmode |= FB_VMODE_YWRAP;
+   fb_info->updatevar(unit);
+}
+
+
+static __inline__ void ypan_up(int unit, struct vc_data *conp,
+			       struct display *p, int count)
+{
+   p->yscroll += count;
+   if (p->yscroll+conp->vc_rows > p->vrows) {
+      p->dispsw->bmove(p, p->yscroll, 0, 0, 0, conp->vc_rows-count,
+		       conp->vc_cols);
+      p->yscroll = 0;
+   }
+   p->var.xoffset = 0;
+   p->var.yoffset = p->yscroll*p->fontheight;
+   p->var.vmode &= ~FB_VMODE_YWRAP;
+   fb_info->updatevar(unit);
+}
+
+
+static __inline__ void ypan_down(int unit, struct vc_data *conp,
+				 struct display *p, int count)
+{
+   p->yscroll -= count;
+   if (p->yscroll < 0) {
+      p->yscroll = p->vrows-conp->vc_rows;
+      p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, conp->vc_rows-count,
+		       conp->vc_cols);
+   }
+   p->var.xoffset = 0;
+   p->var.yoffset = p->yscroll*p->fontheight;
+   p->var.vmode &= ~FB_VMODE_YWRAP;
+   fb_info->updatevar(unit);
+}
+
+
 static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
 {
    int unit = conp->vc_num;
@@ -1577,84 +1646,98 @@
 
    switch (dir) {
       case SM_UP:
-         if (t == 0 && b == conp->vc_rows &&
-             vt_cons[unit]->vc_mode == KD_TEXT) {
-            if (count > conp->vc_rows)             /* Maximum realistic size */
-               count = conp->vc_rows;
-            switch (p->scrollmode) {
-               case SCROLL_YWRAP:
-                  p->yscroll += count;
-                  if (p->yscroll >= p->vrows) /* Deal with wrap */
-                     p->yscroll -= p->vrows;
-                  p->var.xoffset = 0;
-                  p->var.yoffset = p->yscroll*p->fontheight;
-                  p->var.vmode |= FB_VMODE_YWRAP;
-                  fb_info->updatevar(unit);
-                  break;
-
-               case SCROLL_YPAN:
-                  p->yscroll += count;
-                  if (p->yscroll+conp->vc_rows > p->vrows) {
-                     p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count,
-                                      conp->vc_cols);
-                     p->yscroll = 0;
-                  }
-                  p->var.xoffset = 0;
-                  p->var.yoffset = p->yscroll*p->fontheight;
-                  p->var.vmode &= ~FB_VMODE_YWRAP;
-                  fb_info->updatevar(unit);
-                  break;
-
-               case SCROLL_YMOVE:
-                  p->dispsw->bmove(p, count, 0, 0, 0, b-count, conp->vc_cols);
-                  break;
-            }
-         } else
-            fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols);
-         fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
+	 if (count > conp->vc_rows)	/* Maximum realistic size */
+	    count = conp->vc_rows;
+	 if (vt_cons[unit]->vc_mode == KD_TEXT)
+	    switch (p->scrollmode) {
+	       case SCROLL_YWRAP:
+		  if (b-t-count > 3*conp->vc_rows>>2) {
+		     if (t > 0)
+			fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols);
+		     ywrap_up(unit, p, count);
+		     if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b,
+				    conp->vc_cols);
+		  } else
+		     fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
+				 conp->vc_cols);
+		  fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
+		  break;
+
+	       case SCROLL_YPAN:
+		  if (b-t-count > 3*conp->vc_rows>>2) {
+		     if (t > 0)
+			fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols);
+		     ypan_up(unit, conp, p, count);
+		     if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b,
+				    conp->vc_cols);
+		  } else
+		     fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
+				 conp->vc_cols);
+		  fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
+		  break;
+
+	       case SCROLL_YMOVE:
+		  p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
+				   conp->vc_cols);
+		  p->dispsw->clear(conp, p, b-count, 0, count, conp->vc_cols);
+		  break;
+	    }
+	 else {
+	    fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols);
+	    fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
+	 }
          break;
 
       case SM_DOWN:
-         if (t == 0 && b == conp->vc_rows &&
-             vt_cons[unit]->vc_mode == KD_TEXT) {
-            if (count > conp->vc_rows)             /* Maximum realistic size */
-               count = conp->vc_rows;
-            switch (p->scrollmode) {
-               case SCROLL_YWRAP:
-                  p->yscroll -= count;
-                  if (p->yscroll < 0)              /* Deal with wrap */
-                     p->yscroll += p->vrows;
-                  p->var.xoffset = 0;
-                  p->var.yoffset = p->yscroll*p->fontheight;
-                  p->var.vmode |= FB_VMODE_YWRAP;
-                  fb_info->updatevar(unit);
-                  break;
-
-               case SCROLL_YPAN:
-                  p->yscroll -= count;
-                  if (p->yscroll < 0) {
-                     p->yscroll = p->vrows-conp->vc_rows;
-                     p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count,
-                                      conp->vc_cols);
-                  }
-                  p->var.xoffset = 0;
-                  p->var.yoffset = p->yscroll*p->fontheight;
-                  p->var.vmode &= ~FB_VMODE_YWRAP;
-                  fb_info->updatevar(unit);
-                  break;
-
-               case SCROLL_YMOVE:
-                  p->dispsw->bmove(p, 0, 0, count, 0, b-count, conp->vc_cols);
-                  break;
-            }
-         } else
-            fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
-
-         /* Fixed bmove() should end Arno's frustration with copying?
-          * Confucius says:
-          *    Man who copies in wrong direction, end up with trashed data
-          */
-         fbcon_clear(conp, t, 0, count, conp->vc_cols);
+	 if (count > conp->vc_rows)	/* Maximum realistic size */
+	    count = conp->vc_rows;
+	 if (vt_cons[unit]->vc_mode == KD_TEXT)
+	    switch (p->scrollmode) {
+	       case SCROLL_YWRAP:
+		  if (b-t-count > 3*conp->vc_rows>>2) {
+		     if (t > 0)
+			fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b,
+				    conp->vc_cols);
+		     ywrap_down(unit, p, count);
+		     if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols);
+		  } else
+		     fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
+				 conp->vc_cols);
+		  fbcon_clear(conp, t, 0, count, conp->vc_cols);
+		  break;
+
+	       case SCROLL_YPAN:
+		  if (b-t-count > 3*conp->vc_rows>>2) {
+		     if (t > 0)
+			fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b,
+				    conp->vc_cols);
+		     ypan_down(unit, conp, p, count);
+		     if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols);
+		  } else
+		     fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
+				 conp->vc_cols);
+		  fbcon_clear(conp, t, 0, count, conp->vc_cols);
+		  break;
+
+	       case SCROLL_YMOVE:
+		  p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count,
+				   conp->vc_cols);
+		  p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols);
+		  break;
+	    }
+	 else {
+	    /*
+	     * Fixed bmove() should end Arno's frustration with copying?
+	     * Confucius says:
+	     *    Man who copies in wrong direction, end up with trashed data
+	     */
+	    fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
+	    fbcon_clear(conp, t, 0, count, conp->vc_cols);
+	 }
          break;
 
       case SM_LEFT:
@@ -1873,14 +1956,7 @@
 		/* Adjust the virtual screen-size to fontheight*rows */
 		p->var.yres_virtual = (p->var.yres/h)*h;
 		p->vrows = p->var.yres_virtual/h;
-		if (divides(p->ywrapstep, p->fontheight))
-			p->scrollmode = SCROLL_YWRAP;
-		else if (divides(p->ypanstep, p->fontheight) &&
-				 p->var.yres_virtual >= p->var.yres+p->fontheight)
-			p->scrollmode = SCROLL_YPAN;
-		else
-			p->scrollmode = SCROLL_YMOVE;
-
+		updatescrollmode(p);
 		vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
 	}
 	else if (unit == fg_console)
@@ -1955,8 +2031,8 @@
    u_char *src, *dest;
    u_int rows;
 
-   if (sx == 0 && sy == 0 && width == p->next_line) {
-      src = p->screen_base;
+   if (sx == 0 && dx == 0 && width == p->next_line) {
+      src = p->screen_base+sy*p->fontheight*width;
       dest = p->screen_base+dy*p->fontheight*width;
       mymemmove(dest, src, height*p->fontheight*width);
    } else if (dy <= sy) {
@@ -2090,8 +2166,9 @@
 static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
                        int height, int width)
 {
-   if (sx == 0 && sy == 0 && width == p->next_plane)
-      mymemmove(p->screen_base+dy*p->fontheight*p->next_line, p->screen_base,
+   if (sx == 0 && dx == 0 && width == p->next_plane)
+      mymemmove(p->screen_base+dy*p->fontheight*p->next_line,
+		p->screen_base+sy*p->fontheight*p->next_line,
                 height*p->fontheight*p->next_line);
    else {
       u_char *src, *dest;
@@ -2312,8 +2389,8 @@
    u_char *src, *dest, *src0, *dest0;
    u_int i, rows;
 
-   if (sx == 0 && sy == 0 && width == p->next_line) {
-      src = p->screen_base;
+   if (sx == 0 && dx == 0 && width == p->next_line) {
+      src = p->screen_base+sy*p->fontheight*width;
       dest = p->screen_base+dy*p->fontheight*width;
       for (i = p->var.bits_per_pixel; i--;) {
          mymemmove(dest, src, height*p->fontheight*width);

Greetings,

						Geert

--
Geert Uytterhoeven                     Geert.Uytterhoeven@cs.kuleuven.ac.be
Wavelets, Linux/m68k on Amiga          http://www.cs.kuleuven.ac.be/~geert/
Department of Computer Science -- Katholieke Universiteit Leuven -- Belgium

