This causes the write-only framebuffer console to only redraw the
chars that differ between the start and end positions.

'time ls -R /usr/src/sys' is 3x faster with this, because most of
the characters stay the same after a scroll.

If this looks good, I can do the same thing for clear rows and copy/
clear columns, although I will need to make a test case for them.

It would probably be a good idea to change the rasops interface to
have generic block copy and clear oeprations, versus the current
full-column / full-row interface, so tmux and friends could get the
full acceleration.

Index: rasops.c
===================================================================
RCS file: /cvs/src/sys/dev/rasops/rasops.c,v
retrieving revision 1.61
diff -u -p -r1.61 rasops.c
--- rasops.c    25 May 2020 09:55:49 -0000      1.61
+++ rasops.c    26 Jun 2020 04:14:13 -0000
@@ -1627,28 +1627,42 @@ rasops_vcons_copyrows(void *cookie, int 
        struct rasops_info *ri = scr->rs_ri;
        int cols = ri->ri_cols;
        int row, col, rc;
+       int srcofs;
+       int move;
 
+       /* update the scrollback buffer if the entire screen is moving */
        if (dst == 0 && (src + num == ri->ri_rows) && scr->rs_sbscreens > 0)
                memmove(&scr->rs_bs[dst], &scr->rs_bs[src * cols],
-                   ((ri->ri_rows * (scr->rs_sbscreens + 1) * cols) -
-                   (src * cols)) * sizeof(struct wsdisplay_charcell));
-       else
+                   ri->ri_rows * scr->rs_sbscreens * cols
+                   * sizeof(struct wsdisplay_charcell));
+
+       /* copy everything */
+       if ((ri->ri_flg & RI_WRONLY) == 0 || !scr->rs_visible) {
                memmove(&scr->rs_bs[dst * cols + scr->rs_dispoffset],
-                   &scr->rs_bs[src * cols + scr->rs_dispoffset],
-                   num * cols * sizeof(struct wsdisplay_charcell));
+                       &scr->rs_bs[src * cols + scr->rs_dispoffset],
+                       num * cols * sizeof(struct wsdisplay_charcell));
 
-       if (!scr->rs_visible)
-               return 0;
+               if (!scr->rs_visible)
+                       return 0;
 
-       if ((ri->ri_flg & RI_WRONLY) == 0)
                return ri->ri_copyrows(ri, src, dst, num);
+       }
 
-       for (row = dst; row < dst + num; row++) {
+       /* smart update, only redraw characters that are different */
+       srcofs = (src - dst) * cols;
+
+       for (move = 0 ; move < num ; move++) {
+               row = srcofs > 0 ? dst + move : dst + num - 1 - move;
                for (col = 0; col < cols; col++) {
                        int off = row * cols + col + scr->rs_dispoffset;
-
-                       rc = ri->ri_putchar(ri, row, col,
-                           scr->rs_bs[off].uc, scr->rs_bs[off].attr);
+                       int newc = scr->rs_bs[off+srcofs].uc;
+                       int newa = scr->rs_bs[off+srcofs].attr;
+                       if ( scr->rs_bs[off].uc == newc 
+                               && scr->rs_bs[off].attr == newa )
+                               continue;
+                       scr->rs_bs[off].uc = newc;
+                       scr->rs_bs[off].attr = newa;
+                       rc = ri->ri_putchar(ri, row, col, newc, newa);
                        if (rc != 0)
                                return rc;
                }


Reply via email to