On most modern hardware reading from a framebuffer is much slower than writing to it. This is why when I added code to the rasops code to remember the characters written and simply redraw them when we scroll the console. That code only works when RI_VCONS was specified, because that code already had the backing store for the characters to support switching between multiple screens.
Unfortunately the RI_VCONS code doesn't work early on in the boot process. We need to allocate memory for the screen and the backing store and that isn't going to work if we haven't initialized uvm yet. Enter the diff below. This makes it possible for the early console initialization code to pass a buffer for storing the all characters on the framebuffer, and set the RI_WRONLY flag. This makes efifb(4) on my laptop quite a bit faster. And it will be even faster when we make the framebuffer write-combining. There is a bit of code duplication between the rasops_vcons_* and rasops_wronly_* functions. I probably should refactor things a bit to remove the code duplication for at least the *_copycols() and *_compyrows() functions. I can do that now or later. ok? Index: arch/amd64/amd64/efifb.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/efifb.c,v retrieving revision 1.4 diff -u -p -r1.4 efifb.c --- arch/amd64/amd64/efifb.c 5 Sep 2015 08:21:27 -0000 1.4 +++ arch/amd64/amd64/efifb.c 5 Sep 2015 22:31:56 -0000 @@ -121,7 +121,7 @@ efifb_attach(struct device *parent, stru efifb_rasops_preinit(fb); ri->ri_flg &= ~RI_CLEAR; - ri->ri_flg |= RI_VCONS; + ri->ri_flg |= RI_VCONS | RI_WRONLY; rasops_init(ri, efifb_std_descr.nrows, efifb_std_descr.ncols); } @@ -264,6 +264,8 @@ efifb_list_font(void *v, struct wsdispla return (rasops_list_font(ri, font)); } +struct wsdisplay_charcell efifb_bs[EFIFB_HEIGHT * EFIFB_WIDTH]; + int efifb_cnattach(void) { @@ -289,7 +291,8 @@ efifb_cnattach(void) efifb_rasops_preinit(fb); - ri->ri_flg = RI_CLEAR | RI_CENTER; + ri->ri_bs = efifb_bs; + ri->ri_flg = RI_CLEAR | RI_CENTER | RI_WRONLY; rasops_init(ri, EFIFB_HEIGHT, EFIFB_WIDTH); efifb_std_descr.ncols = ri->ri_cols; efifb_std_descr.nrows = ri->ri_rows; Index: dev/rasops/rasops.c =================================================================== RCS file: /cvs/src/sys/dev/rasops/rasops.c,v retrieving revision 1.41 diff -u -p -r1.41 rasops.c --- dev/rasops/rasops.c 1 Sep 2015 01:54:04 -0000 1.41 +++ dev/rasops/rasops.c 5 Sep 2015 22:31:56 -0000 @@ -174,6 +174,12 @@ int rasops_vcons_eraserows(void *, int, int rasops_vcons_alloc_attr(void *, int, int, int, long *); void rasops_vcons_unpack_attr(void *, long, int *, int *, int *); +int rasops_wronly_putchar(void *, int, int, u_int, long); +int rasops_wronly_copycols(void *, int, int, int, int); +int rasops_wronly_erasecols(void *, int, int, int, long); +int rasops_wronly_copyrows(void *, int, int, int); +int rasops_wronly_eraserows(void *, int, int, long); + int rasops_add_font(struct rasops_info *, struct wsdisplay_font *); int rasops_use_font(struct rasops_info *, struct wsdisplay_font *); int rasops_list_font_cb(void *, struct wsdisplay_font *); @@ -271,6 +277,21 @@ rasops_init(struct rasops_info *ri, int ri->ri_ops.eraserows = rasops_vcons_eraserows; ri->ri_ops.alloc_attr = rasops_vcons_alloc_attr; ri->ri_ops.unpack_attr = rasops_vcons_unpack_attr; + } else if ((ri->ri_flg & RI_WRONLY) && ri->ri_bs != NULL) { + long attr; + int i; + + ri->ri_ops.putchar = rasops_wronly_putchar; + ri->ri_ops.copycols = rasops_wronly_copycols; + ri->ri_ops.erasecols = rasops_wronly_erasecols; + ri->ri_ops.copyrows = rasops_wronly_copyrows; + ri->ri_ops.eraserows = rasops_wronly_eraserows; + + ri->ri_alloc_attr(ri, 0, 0, 0, &attr); + for (i = 0; i < ri->ri_rows * ri->ri_cols; i++) { + ri->ri_bs[i].uc = ' '; + ri->ri_bs[i].attr = attr; + } } task_set(&ri->ri_switchtask, rasops_doswitch, ri); @@ -1368,7 +1389,6 @@ rasops_alloc_screen(void *v, void **cook { struct rasops_info *ri = v; struct rasops_screen *scr; - size_t size; int i; scr = malloc(sizeof(*scr), M_DEVBUF, M_NOWAIT); @@ -1382,7 +1402,6 @@ rasops_alloc_screen(void *v, void **cook free(scr, M_DEVBUF, sizeof(*scr)); return (ENOMEM); } - size = ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell); *cookiep = scr; *curxp = 0; @@ -1394,9 +1413,14 @@ rasops_alloc_screen(void *v, void **cook scr->rs_crow = -1; scr->rs_ccol = -1; - for (i = 0; i < ri->ri_rows * ri->ri_cols; i++) { - scr->rs_bs[i].uc = ' '; - scr->rs_bs[i].attr = *attrp; + if (ri->ri_bs) { + memcpy(scr->rs_bs, ri->ri_bs, ri->ri_rows * ri->ri_cols * + sizeof(struct wsdisplay_charcell)); + } else { + for (i = 0; i < ri->ri_rows * ri->ri_cols; i++) { + scr->rs_bs[i].uc = ' '; + scr->rs_bs[i].attr = *attrp; + } } LIST_INSERT_HEAD(&ri->ri_screens, scr, rs_next); @@ -1628,6 +1652,95 @@ rasops_vcons_unpack_attr(void *cookie, l rasops_unpack_attr(scr->rs_ri, attr, fg, bg, underline); } + +int +rasops_wronly_putchar(void *cookie, int row, int col, u_int uc, long attr) +{ + struct rasops_info *ri = cookie; + int off = row * ri->ri_cols + col; + + ri->ri_bs[off].uc = uc; + ri->ri_bs[off].attr = attr; + + return ri->ri_putchar(ri, row, col, uc, attr); +} + +int +rasops_wronly_copycols(void *cookie, int row, int src, int dst, int num) +{ + struct rasops_info *ri = cookie; + int cols = ri->ri_cols; + int col, rc; + + memmove(&ri->ri_bs[row * cols + dst], &ri->ri_bs[row * cols + src], + num * sizeof(struct wsdisplay_charcell)); + + for (col = dst; col < dst + num; col++) { + int off = row * cols + col; + + rc = ri->ri_putchar(ri, row, col, + ri->ri_bs[off].uc, ri->ri_bs[off].attr); + if (rc != 0) + return rc; + } + + return 0; +} + +int +rasops_wronly_erasecols(void *cookie, int row, int col, int num, long attr) +{ + struct rasops_info *ri = cookie; + int cols = ri->ri_cols; + int i; + + for (i = 0; i < num; i++) { + ri->ri_bs[row * cols + col + i].uc = ' '; + ri->ri_bs[row * cols + col + i].attr = attr; + } + + return ri->ri_erasecols(ri, row, col, num, attr); +} + +int +rasops_wronly_copyrows(void *cookie, int src, int dst, int num) +{ + struct rasops_info *ri = cookie; + int cols = ri->ri_cols; + int row, col, rc; + + memmove(&ri->ri_bs[dst * cols], &ri->ri_bs[src * cols], + num * cols * sizeof(struct wsdisplay_charcell)); + + for (row = dst; row < dst + num; row++) { + for (col = 0; col < cols; col++) { + int off = row * cols + col; + + rc = ri->ri_putchar(ri, row, col, + ri->ri_bs[off].uc, ri->ri_bs[off].attr); + if (rc != 0) + return rc; + } + } + + return 0; +} + +int +rasops_wronly_eraserows(void *cookie, int row, int num, long attr) +{ + struct rasops_info *ri = cookie; + int cols = ri->ri_cols; + int i; + + for (i = 0; i < num * cols; i++) { + ri->ri_bs[row * cols + i].uc = ' '; + ri->ri_bs[row * cols + i].attr = attr; + } + + return ri->ri_eraserows(ri, row, num, attr); +} + /* * Font management. Index: dev/rasops/rasops.h =================================================================== RCS file: /cvs/src/sys/dev/rasops/rasops.h,v retrieving revision 1.16 diff -u -p -r1.16 rasops.h --- dev/rasops/rasops.h 22 Dec 2014 20:08:05 -0000 1.16 +++ dev/rasops/rasops.h 5 Sep 2015 22:31:56 -0000 @@ -74,6 +74,7 @@ struct rasops_info { struct wsdisplay_font *ri_font; int ri_wsfcookie; /* wsfont cookie */ void *ri_hw; /* driver private data; ignored by rasops */ + struct wsdisplay_charcell *ri_bs; /* character backing store */ int ri_crow; /* cursor row */ int ri_ccol; /* cursor column */ int ri_flg; /* various operational flags */