Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/wsfb add optional glyph cache for genfb



details:   https://anonhg.NetBSD.org/src/rev/1a8170319360
branches:  trunk
changeset: 950404:1a8170319360
user:      macallan <macallan%NetBSD.org@localhost>
date:      Wed Jan 27 22:42:53 2021 +0000

description:
add optional glyph cache for genfb
enable with options GENFB_GLYPHCACHE=n
with n being the desired size of the cache in MB. Should be enough to cache
at least 900 glyphs in whatever video mode used in order to be effective
in 32bit per pixel that's about 1MB

diffstat:

 sys/dev/wsfb/files.wsfb |    3 +-
 sys/dev/wsfb/genfb.c    |  186 +++++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/wsfb/genfbvar.h |   41 ++++++++++-
 3 files changed, 225 insertions(+), 5 deletions(-)

diffs (truncated from 301 to 300 lines):

diff -r 59dfb266cd39 -r 1a8170319360 sys/dev/wsfb/files.wsfb
--- a/sys/dev/wsfb/files.wsfb   Wed Jan 27 17:39:13 2021 +0000
+++ b/sys/dev/wsfb/files.wsfb   Wed Jan 27 22:42:53 2021 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.wsfb,v 1.11 2019/07/26 10:48:45 rin Exp $
+# $NetBSD: files.wsfb,v 1.12 2021/01/27 22:42:53 macallan Exp $
 
 #
 # wsdisplay framebuffer drivers
@@ -13,3 +13,4 @@
 device genfb: genfb, wsemuldisplaydev, drm, splash
 file   dev/wsfb/genfb.c        genfb   needs-flag
 defflag opt_genfb.h GENFB_DEBUG GENFB_SHADOWFB
+defparam opt_genfb.h GENFB_GLYPHCACHE=0        # glyphcache size in MB
diff -r 59dfb266cd39 -r 1a8170319360 sys/dev/wsfb/genfb.c
--- a/sys/dev/wsfb/genfb.c      Wed Jan 27 17:39:13 2021 +0000
+++ b/sys/dev/wsfb/genfb.c      Wed Jan 27 22:42:53 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: genfb.c,v 1.80 2021/01/26 18:08:33 macallan Exp $ */
+/*     $NetBSD: genfb.c,v 1.81 2021/01/27 22:42:53 macallan Exp $ */
 
 /*-
  * Copyright (c) 2007 Michael Lorenz
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.80 2021/01/26 18:08:33 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.81 2021/01/27 22:42:53 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -92,6 +92,11 @@
 static void    genfb_brightness_up(device_t);
 static void    genfb_brightness_down(device_t);
 
+#if GENFB_GLYPHCACHE > 0
+static int     genfb_setup_glyphcache(struct genfb_softc *, long);
+static void    genfb_putchar(void *, int, int, u_int, long);
+#endif
+
 extern const u_char rasops_cmap[768];
 
 static int genfb_cnattach_called = 0;
@@ -288,6 +293,10 @@
            &defattr);
        sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
 
+#if GENFB_GLYPHCACHE > 0
+       genfb_setup_glyphcache(sc, defattr);
+#endif
+
 #ifdef SPLASHSCREEN
 /*
  * If system isn't going to go multiuser, or user has requested to see
@@ -632,7 +641,10 @@
                    sc->sc_width / ri->ri_font->fontwidth);
 
        ri->ri_hw = scr;
-
+#if GENFB_GLYPHCACHE > 0
+       sc->sc_putchar = ri->ri_ops.putchar;
+       ri->ri_ops.putchar = genfb_putchar;
+#endif
 #ifdef GENFB_DISABLE_TEXT
        if (scr == &sc->sc_console_screen && !DISABLESPLASH)
                SCREEN_DISABLE_DRAWING(&sc->sc_console_screen);
@@ -890,3 +902,171 @@
                vcons_disable_polling(&sc->vd);
        }
 }
+
+#if GENFB_GLYPHCACHE > 0
+#define GLYPHCACHESIZE ((GENFB_GLYPHCACHE) * 1024 * 1024)
+
+static inline int
+attr2idx(long attr)
+{
+       if ((attr & 0xf0f00ff8) != 0)
+               return -1;
+       
+       return (((attr >> 16) & 0x0f) | ((attr >> 20) & 0xf0));
+}
+
+static int
+genfb_setup_glyphcache(struct genfb_softc *sc, long defattr)
+{
+       struct rasops_info *ri = &sc->sc_console_screen.scr_ri,
+                         *cri = &sc->sc_cache_ri;
+       gc_bucket *b;
+       int i, usedcells = 0, idx, j;
+
+       sc->sc_cache = kmem_alloc(GLYPHCACHESIZE, KM_SLEEP);
+
+       /*
+        * now we build a mutant rasops_info for the cache - same pixel type
+        * and such as the real fb, but only one character per line for 
+        * simplicity and locality
+        */
+       memcpy(cri, ri, sizeof(struct rasops_info));
+       cri->ri_ops.putchar = sc->sc_putchar;
+       cri->ri_width = ri->ri_font->fontwidth;
+       cri->ri_stride = ri->ri_xscale;
+       cri->ri_bits = sc->sc_cache;
+       cri->ri_hwbits = NULL;
+       cri->ri_origbits = sc->sc_cache;
+       cri->ri_cols = 1;
+       cri->ri_rows = GLYPHCACHESIZE / 
+           (cri->ri_stride * cri->ri_font->fontheight);
+       cri->ri_xorigin = 0;
+       cri->ri_yorigin = 0;
+       cri->ri_xscale = ri->ri_xscale;
+       cri->ri_yscale = ri->ri_font->fontheight * ri->ri_xscale;
+       
+       printf("size %d %d %d\n", GLYPHCACHESIZE, ri->ri_width, ri->ri_stride);
+       printf("cells: %d\n", cri->ri_rows);
+       sc->sc_nbuckets = uimin(256, cri->ri_rows / 223);
+       sc->sc_buckets = kmem_alloc(sizeof(gc_bucket) * sc->sc_nbuckets, KM_SLEEP);
+       printf("buckets: %d\n", sc->sc_nbuckets);
+       for (i = 0; i < sc->sc_nbuckets; i++) {
+               b = &sc->sc_buckets[i];
+               b->gb_firstcell = usedcells;
+               b->gb_numcells = uimin(223, cri->ri_rows - usedcells);
+               usedcells += 223;
+               b->gb_usedcells = 0;
+               b->gb_index = -1;
+               for (j = 0; j < 223; j++) b->gb_map[j] = -1;
+       }
+
+       /* initialize the attribute map... */
+       for (i = 0; i < 256; i++) {
+               sc->sc_attrmap[i] = -1;
+       }
+
+       /* first bucket goes to default attr */
+       idx = attr2idx(defattr);
+       printf("defattr %08lx idx %x\n", defattr, idx);
+       
+       if (idx >= 0) {
+               sc->sc_attrmap[idx] = 0;
+               sc->sc_buckets[0].gb_index = idx;
+       }
+       
+       return 0;
+}
+
+static void
+genfb_putchar(void *cookie, int row, int col, u_int c, long attr)
+{
+       struct rasops_info *ri = cookie;
+       struct vcons_screen *scr = ri->ri_hw;
+       struct genfb_softc *sc = scr->scr_cookie;
+       uint8_t *src, *dst;
+       gc_bucket *b;
+       int i, idx, bi, cell;
+
+       attr &= ~WSATTR_USERMASK;
+
+       idx = attr2idx(attr);
+       if (c < 33 || c > 255 || idx < 0) goto nope;
+
+       /* look for a bucket with the right attribute */
+       bi = sc->sc_attrmap[idx];
+       if (bi == -1) {
+               /* nope, see if there's an empty one left */
+               bi = 1;
+               while ((bi < sc->sc_nbuckets) && 
+                      (sc->sc_buckets[bi].gb_index != -1)) {
+                       bi++;
+               }
+               if (bi < sc->sc_nbuckets) {
+                       /* found one -> grab it */
+                       sc->sc_attrmap[idx] = bi;
+                       b = &sc->sc_buckets[bi];
+                       b->gb_index = idx;
+                       b->gb_usedcells = 0;
+                       /* make sure this doesn't get evicted right away */
+                       b->gb_lastread = time_uptime;
+               } else {
+                       /*
+                        * still nothing
+                        * steal the least recently read bucket
+                        */
+                       time_t moo = time_uptime;
+                       int oldest = 1;
+
+                       for (i = 1; i < sc->sc_nbuckets; i++) {
+                               if (sc->sc_buckets[i].gb_lastread < moo) {
+                                       oldest = i;
+                                       moo = sc->sc_buckets[i].gb_lastread;
+                               }
+                       }
+
+                       /* if we end up here all buckets must be in use */
+                       b = &sc->sc_buckets[oldest];
+                       sc->sc_attrmap[b->gb_index] = -1;
+                       b->gb_index = idx;
+                       b->gb_usedcells = 0;
+                       sc->sc_attrmap[idx] = oldest;
+                       /* now scrub it */
+                       for (i = 0; i < 223; i++)
+                               b->gb_map[i] = -1;
+                       /* and set the time stamp */
+                       b->gb_lastread = time_uptime;
+               }
+       } else {
+               /* found one */
+               b = &sc->sc_buckets[bi];
+       }
+
+       /* see if there's room in the bucket */
+       if (b->gb_usedcells >= b->gb_numcells) goto nope;
+
+       cell = b->gb_map[c - 33];
+       if (cell == -1) {
+               if (b->gb_usedcells >= b->gb_numcells)
+                       goto nope;
+               cell = atomic_add_int_nv(&b->gb_usedcells, 1) - 1;
+               b->gb_map[c - 33] = cell;
+               cell += b->gb_firstcell;
+               sc->sc_putchar(&sc->sc_cache_ri, cell, 0, c, attr);
+               
+       } else
+               cell += b->gb_firstcell;
+
+       src = sc->sc_cache + cell * sc->sc_cache_ri.ri_yscale;
+       dst = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
+       for (i = 0; i < ri->ri_font->fontheight; i++) {
+               memcpy(dst, src, ri->ri_xscale);
+               src += ri->ri_xscale;
+               dst += ri->ri_stride;
+       }
+       b->gb_lastread = time_uptime;
+       return;
+nope:
+       sc->sc_putchar(cookie, row, col, c, attr);
+}
+
+#endif
diff -r 59dfb266cd39 -r 1a8170319360 sys/dev/wsfb/genfbvar.h
--- a/sys/dev/wsfb/genfbvar.h   Wed Jan 27 17:39:13 2021 +0000
+++ b/sys/dev/wsfb/genfbvar.h   Wed Jan 27 22:42:53 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: genfbvar.h,v 1.25 2017/02/25 01:11:55 nonaka Exp $ */
+/*     $NetBSD: genfbvar.h,v 1.26 2021/01/27 22:42:53 macallan Exp $ */
 
 /*-
  * Copyright (c) 2007 Michael Lorenz
@@ -54,6 +54,10 @@
 #include <dev/splash/splash.h>
 #endif
 
+#if GENFB_GLYPHCACHE > 0
+#include <dev/wscons/wsdisplay_glyphcachevar.h>
+#endif
+
 struct genfb_softc;
 
 struct genfb_ops {
@@ -125,6 +129,41 @@
        struct splash_info sc_splash;
 #endif
        struct wsdisplay_accessops sc_accessops;
+#if GENFB_GLYPHCACHE > 0
+       /*
+        * The generic glyphcache code makes a bunch of assumptions that are
+        * true for most graphics hardware with a directly supported blitter.
+        * For example it assume that
+        * - VRAM access from the host is expensive
+        * - copying data around in VRAM is cheap and can happen in parallel
+        *   to the host CPU
+        * -> therefore we draw glyphs normally if we have to, so the ( assumed
+        *    to be hardware assisted ) driver supplied putchar() method doesn't
+        *    need to be glyphcache aware, then copy them away for later use
+        * for genfb things are a bit different. On most hardware:
+        * - VRAM access from the host is still expensive
+        * - copying data around in VRAM is also expensive since we don't have
+        *   a blitter and VRAM is mapped uncached
+        * - VRAM reads are usually slower than writes ( write combining and
+        *   such help writes but not reads, and VRAM might be behind an
+        *   asymmetric bus like AGP ) and must be avoided, both are much
+        *   slower than main memory
+        * -> therefore we cache glyphs in main memory, no reason to map it
+        *    uncached, we draw into the cache first and then copy the glyph
+        *    into video memory to avoid framebuffer reads and to allow more
+        *    efficient write accesses than putchar() would offer
+        * Because of this we can't use the generic code but we can recycle a
+        * few data structures.
+        */
+       uint8_t *sc_cache;
+       struct rasops_info sc_cache_ri;
+       void (*sc_putchar)(void *, int, int, u_int, long);
+       int sc_cache_cells;
+       int sc_nbuckets;        /* buckets allocated */
+       gc_bucket *sc_buckets;  /* we allocate as many as we can get into ram */
+       int sc_attrmap[256];    /* mapping a colour attribute to a bucket */
+#endif
+
 };
 



Home | Main Index | Thread Index | Old Index