Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/wscons Add support for asynchronous drawing in vcons.



details:   https://anonhg.NetBSD.org/src/rev/23c5912c006c
branches:  trunk
changeset: 761373:23c5912c006c
user:      macallan <macallan%NetBSD.org@localhost>
date:      Tue Jan 25 20:28:21 2011 +0000

description:
Add support for asynchronous drawing in vcons.
This is not finished but good enough for others to play with, enable with
options VCONS_DRAW_ASYNC
With this all drawing operations will be posted to a ring buffer instead
of being run directly, and run by a kernel thread. This avoids having to wait
for drawing operations to finish with the kernel lock held ( to a degree at
least ) and scrolling a (slow) framebuffer console should not disrupt other
operations anymore.
Problems:
- we need to switch back to synchronous operations when panicing or entering
  ddb, also re-enable async drawing when leaving ddb
- there are still occasional glitches
tested on an SS20 with cg14 and cg6 for dumb and accelerated cases

diffstat:

 sys/dev/wscons/files.wscons         |    4 +-
 sys/dev/wscons/wsdisplay_vcons.c    |  471 ++++++++++++++++++++++++++++++-----
 sys/dev/wscons/wsdisplay_vconsvar.h |   42 ++-
 3 files changed, 435 insertions(+), 82 deletions(-)

diffs (truncated from 713 to 300 lines):

diff -r d2d94546dfca -r 23c5912c006c sys/dev/wscons/files.wscons
--- a/sys/dev/wscons/files.wscons       Tue Jan 25 19:13:44 2011 +0000
+++ b/sys/dev/wscons/files.wscons       Tue Jan 25 20:28:21 2011 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.wscons,v 1.41 2009/08/20 02:01:08 macallan Exp $
+# $NetBSD: files.wscons,v 1.42 2011/01/25 20:28:21 macallan Exp $
 
 #
 # "Workstation Console" glue; attaches frame buffer to emulator & keyboard,
@@ -75,4 +75,4 @@
 # generic virtual console support on bitmapped framebuffers
 file   dev/wscons/wsdisplay_vcons.c            vcons
 file   dev/wscons/wsdisplay_vcons_util.c       vcons
-defflag        opt_vcons.h             VCONS_SWITCH_ASYNC
+defflag        opt_vcons.h             VCONS_DRAW_ASYNC VCONS_ASYNC_DEBUG
diff -r d2d94546dfca -r 23c5912c006c sys/dev/wscons/wsdisplay_vcons.c
--- a/sys/dev/wscons/wsdisplay_vcons.c  Tue Jan 25 19:13:44 2011 +0000
+++ b/sys/dev/wscons/wsdisplay_vcons.c  Tue Jan 25 20:28:21 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wsdisplay_vcons.c,v 1.18 2010/09/21 03:33:14 macallan Exp $ */
+/*     $NetBSD: wsdisplay_vcons.c,v 1.19 2011/01/25 20:28:21 macallan Exp $ */
 
 /*-
  * Copyright (c) 2005, 2006 Michael Lorenz
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.18 2010/09/21 03:33:14 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.19 2011/01/25 20:28:21 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -42,6 +42,7 @@
 #include <sys/proc.h>
 #include <sys/kthread.h>
 #include <sys/tprintf.h>
+#include <sys/atomic.h>
 
 #include <dev/wscons/wsdisplayvar.h>
 #include <dev/wscons/wsconsio.h>
@@ -78,6 +79,16 @@
 static void vcons_eraserows_buffer(void *, int, int, long);
 static void vcons_putchar_buffer(void *, int, int, u_int, long);
 
+#ifdef VCONS_DRAW_ASYNC
+/* methods that work asynchronously */
+static void vcons_copycols_async(void *, int, int, int, int);
+static void vcons_erasecols_async(void *, int, int, int, long);
+static void vcons_copyrows_async(void *, int, int, int);
+static void vcons_eraserows_async(void *, int, int, long);
+static void vcons_putchar_async(void *, int, int, u_int, long);
+static void vcons_cursor_async(void *, int, int, int);
+#endif
+
 /*
  * actual wrapper methods which call both the _buffer ones above and the
  * driver supplied ones to do the drawing
@@ -103,7 +114,7 @@
 static void vcons_lock(struct vcons_screen *);
 static void vcons_unlock(struct vcons_screen *);
 
-#ifdef VCONS_SWITCH_ASYNC
+#ifdef VCONS_DRAW_ASYNC
 static void vcons_kthread(void *);
 #endif
 
@@ -148,9 +159,9 @@
 #ifdef DIAGNOSTIC
        vd->switch_poll_count = 0;
 #endif
-#ifdef VCONS_SWITCH_ASYNC
+#ifdef VCONS_DRAW_ASYNC
        kthread_create(PRI_NONE, 0, NULL, vcons_kthread, vd,
-           &vd->redraw_thread, "vcons_draw");
+           &vd->drawing_thread, "vcons_draw");
 #endif
        return 0;
 }
@@ -181,9 +192,6 @@
 #ifdef VCONS_PARANOIA
        splx(s);
 #endif
-#ifdef VCONS_SWITCH_ASYNC
-       wakeup(&scr->scr_vd->done_drawing);
-#endif
 }
 
 static void
@@ -223,28 +231,29 @@
         * our wrappers
         */
        vd->eraserows = ri->ri_ops.eraserows;
-       vd->copyrows  = ri->ri_ops.copyrows;
        vd->erasecols = ri->ri_ops.erasecols;
-       vd->copycols  = ri->ri_ops.copycols;
        vd->putchar   = ri->ri_ops.putchar;
        vd->cursor    = ri->ri_ops.cursor;
 
+       if (scr->scr_flags & VCONS_NO_COPYCOLS) {
+               vd->copycols  = vcons_copycols_noread;
+       } else {
+               vd->copycols = ri->ri_ops.copycols;
+       }
+
+       if (scr->scr_flags & VCONS_NO_COPYROWS) {
+               vd->copyrows  = vcons_copyrows_noread;
+       } else {
+               vd->copyrows = ri->ri_ops.copyrows;
+       }
+
        ri->ri_ops.eraserows = vcons_eraserows; 
        ri->ri_ops.erasecols = vcons_erasecols; 
        ri->ri_ops.putchar   = vcons_putchar;
        ri->ri_ops.cursor    = vcons_cursor;
+       ri->ri_ops.copycols  = vcons_copycols;
+       ri->ri_ops.copyrows  = vcons_copyrows;
 
-       if (scr->scr_flags & VCONS_NO_COPYCOLS) {
-               ri->ri_ops.copycols  = vcons_copycols_noread;
-       } else {
-               ri->ri_ops.copycols  = vcons_copycols;
-       }
-
-       if (scr->scr_flags & VCONS_NO_COPYROWS) {
-               ri->ri_ops.copyrows  = vcons_copyrows_noread;
-       } else {
-               ri->ri_ops.copyrows  = vcons_copyrows;
-       }
 
        ri->ri_hw = scr;
 
@@ -520,10 +529,6 @@
        vd->wanted = scr;
        vd->switch_cb = cb;
        vd->switch_cb_arg = cb_arg;
-#ifdef VCONS_SWITCH_ASYNC
-       wakeup(&vd->start_drawing);
-       return EAGAIN;
-#else
        if (cb) {
                callout_schedule(&vd->switch_callout, 0);
                return EAGAIN;
@@ -531,7 +536,6 @@
 
        vcons_do_switch(vd);
        return 0;
-#endif
 }
 
 /* wrappers for rasops_info methods */
@@ -570,7 +574,13 @@
 
        vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
-               scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols);
+#ifdef VCONS_DRAW_ASYNC
+               struct vcons_data *vd = scr->scr_vd;
+               if (vd->use_async) {
+                       vcons_copycols_async(cookie, row, srccol, dstcol, ncols);
+               } else
+#endif
+                       scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols);
        }
        vcons_unlock(scr);
 }
@@ -581,9 +591,6 @@
        struct rasops_info *ri = cookie;
        struct vcons_screen *scr = ri->ri_hw;
 
-       vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols);
-
-       vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
                int pos, c, offset;
 
@@ -599,7 +606,6 @@
                        pos++;
                }
        }
-       vcons_unlock(scr);
 }
 
 static void
@@ -636,8 +642,15 @@
 
        vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
-               scr->scr_vd->erasecols(cookie, row, startcol, ncols, 
-                   fillattr);
+#ifdef VCONS_DRAW_ASYNC
+               struct vcons_data *vd = scr->scr_vd;
+               if (vd->use_async) {
+                       vcons_erasecols_async(cookie, row, startcol, ncols, 
+                           fillattr);
+               } else
+#endif
+                       scr->scr_vd->erasecols(cookie, row, startcol, ncols, 
+                           fillattr);
        }
        vcons_unlock(scr);
 }
@@ -688,7 +701,13 @@
 
        vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
-               scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows);
+#ifdef VCONS_DRAW_ASYNC
+               struct vcons_data *vd = scr->scr_vd;
+               if (vd->use_async) {
+                       vcons_copyrows_async(cookie, srcrow, dstrow, nrows);
+               } else
+#endif
+                       scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows);
        }
        vcons_unlock(scr);
 }
@@ -699,9 +718,6 @@
        struct rasops_info *ri = cookie;
        struct vcons_screen *scr = ri->ri_hw;
 
-       vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows);
-
-       vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
                int pos, l, c, offset;
 
@@ -719,7 +735,6 @@
                        }
                }
        }
-       vcons_unlock(scr);
 }
 
 static void
@@ -756,7 +771,13 @@
 
        vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
-               scr->scr_vd->eraserows(cookie, row, nrows, fillattr);
+#ifdef VCONS_DRAW_ASYNC
+               struct vcons_data *vd = scr->scr_vd;
+               if (vd->use_async) {
+                       vcons_eraserows_async(cookie, row, nrows, fillattr);
+               } else
+#endif
+                       scr->scr_vd->eraserows(cookie, row, nrows, fillattr);
        }
        vcons_unlock(scr);
 }
@@ -798,7 +819,13 @@
        
        vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
-               scr->scr_vd->putchar(cookie, row, col, c, attr);
+#ifdef VCONS_DRAW_ASYNC
+               struct vcons_data *vd = scr->scr_vd;
+               if (vd->use_async) {
+                       vcons_putchar_async(cookie, row, col, c, attr);
+               } else
+#endif
+                       scr->scr_vd->putchar(cookie, row, col, c, attr);
        }
        vcons_unlock(scr);
 }
@@ -811,7 +838,13 @@
 
        vcons_lock(scr);
        if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
-               scr->scr_vd->cursor(cookie, on, row, col);
+#ifdef VCONS_DRAW_ASYNC
+               struct vcons_data *vd = scr->scr_vd;
+               if (vd->use_async) {
+                       vcons_cursor_async(cookie, on, row, col);
+               } else
+#endif
+                       scr->scr_vd->cursor(cookie, on, row, col);
        } else {
                scr->scr_ri.ri_crow = row;
                scr->scr_ri.ri_ccol = col;
@@ -967,46 +1000,334 @@
 
 /* async drawing using a kernel thread */
 
-#ifdef VCONS_SWITCH_ASYNC
+#ifdef VCONS_DRAW_ASYNC
+
+static inline uint32_t
+vcons_words_in_buffer(struct vcons_data *vd)
+{
+       int len = vd->rb_write - vd->rb_read;
+
+       if (len < 0) len += VCONS_RING_BUFFER_LENGTH;
+       if (len < 0) vd->use_async = 0;
+       if (len >= VCONS_RING_BUFFER_LENGTH) vd->use_async = 0;
+       return (uint32_t)len;
+}
+
+static inline int
+vcons_wait_buffer(struct vcons_data *vd, uint32_t words)



Home | Main Index | Thread Index | Old Index