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; }