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 */

Reply via email to