Re: [dev] st: improved double-buffering with Xdbe

From: Brandon Invergo <brandon_AT_invergo.net>
Date: Sat, 28 Jul 2012 14:39:21 +0200

FYI I've applied this patch to st's default branch (commit #245)

Enjoy,
-brandon

Brandon Invergo <brandon_AT_invergo.net> writes:

> Hi,
> As some background, I've been using st on an Arm device (Genesi Efika
> MX) which has relatively low specs compared to your average x86/amd64
> computer. st should be ideal because of how small it is compared to
> xterm or rxvt but the reality is that its rendering is quite a bit
> slower. Under heavy processor load, such as building a package, I can
> literally watch the terminal window refreshing (ie I can see a line
> traveling down the window, above which the window is refreshed and below
> which the window is dirty...."tearing").
>
> I've changed the code to use the X Double Buffer Extension (Xdbe).
> Instead of rendering to a Pixbuf and then copying that Pixbuf to the
> window, which is a relatively slow operation, it now renders to an
> XdbeBackBuffer and then simply swaps buffers with the window. The result
> is tear-free and apparently faster rendering even on an 800mhz Arm cpu.
>
> A side effect is that the code is a bit shorter as a result too. For
> example, xresize() does almost nothing now, since the XdbeBackBuffer is
> automatically resized with the window (see the DBE manpage), so several
> Xlib calls can be removed from that function.
>
> The provided diff is against the default branch, however I also got it
> working for the xft branch. I can provide a diff for that too if you
> want but the only extra difference is that any Xft draw-related calls
> should work on xw.buf rather than xw.win (including the one in
> xresize()).
>
> LIBS in config.mk should have -lXext appended. I forgot to include that
> in the patch.
>
> A few caveats: 1) my C skills are a bit rusty, 2) I'm unfamiliar with
> Mercurial, 3) I'm completely new to Xlib. So, while it Works For Me
> (tm), you might want to test it a bit and let me know if I messed up
> something.
>
> I'm going to keep hacking on it to try to improve further the speed if I
> can.
>
> Cheers,
> Brandon Invergo
> diff -r e1414acbe547 st.c
> --- a/st.c Mon Feb 27 12:48:13 2012 +0100
> +++ b/st.c Fri Apr 20 09:10:28 2012 +0200
> _AT_@ -24,6 +24,7 @@
> #include <X11/Xutil.h>
> #include <X11/cursorfont.h>
> #include <X11/keysym.h>
> +#include <X11/extensions/Xdbe.h>
>
> #if defined(__linux)
> #include <pty.h>
> _AT_@ -178,7 +179,7 @@
> Display* dpy;
> Colormap cmap;
> Window win;
> - Pixmap buf;
> + XdbeBackBuffer buf;
> Atom xembed;
> XIM xim;
> XIC xic;
> _AT_@ -270,7 +271,7 @@
> static void xdraws(char *, Glyph, int, int, int, int);
> static void xhints(void);
> static void xclear(int, int, int, int);
> -static void xcopy(int, int, int, int);
> +static void xcopy();
> static void xdrawcursor(void);
> static void xinit(void);
> static void xloadcols(void);
> _AT_@ -1620,32 +1621,8 @@
>
> void
> xresize(int col, int row) {
> - Pixmap newbuf;
> - int oldw, oldh;
> -
> - oldw = xw.bufw;
> - oldh = xw.bufh;
> xw.bufw = MAX(1, col * xw.cw);
> xw.bufh = MAX(1, row * xw.ch);
> - newbuf = XCreatePixmap(xw.dpy, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dpy, xw.scr));
> - XCopyArea(xw.dpy, xw.buf, newbuf, dc.gc, 0, 0, xw.bufw, xw.bufh, 0, 0);
> - XFreePixmap(xw.dpy, xw.buf);
> - XSetForeground(xw.dpy, dc.gc, dc.col[DefaultBG]);
> - if(xw.bufw > oldw)
> - XFillRectangle(xw.dpy, newbuf, dc.gc, oldw, 0,
> - xw.bufw-oldw, MIN(xw.bufh, oldh));
> - else if(xw.bufw < oldw && (BORDER > 0 || xw.w > xw.bufw))
> - XClearArea(xw.dpy, xw.win, BORDER+xw.bufw, BORDER,
> - xw.w-xw.bufh-BORDER, BORDER+MIN(xw.bufh, oldh),
> - False);
> - if(xw.bufh > oldh)
> - XFillRectangle(xw.dpy, newbuf, dc.gc, 0, oldh,
> - xw.bufw, xw.bufh-oldh);
> - else if(xw.bufh < oldh && (BORDER > 0 || xw.h > xw.bufh))
> - XClearArea(xw.dpy, xw.win, BORDER, BORDER+xw.bufh,
> - xw.w-2*BORDER, xw.h-xw.bufh-BORDER,
> - False);
> - xw.buf = newbuf;
> }
>
> void
> _AT_@ -1801,7 +1778,7 @@
> CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
> | CWColormap,
> &attrs);
> - xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dpy, xw.scr));
> + xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
>
>
> /* input methods */
> _AT_@ -1871,10 +1848,10 @@
>
> /* copy buffer pixmap to screen pixmap */
> void
> -xcopy(int x, int y, int cols, int rows) {
> - int src_x = x*xw.cw, src_y = y*xw.ch, src_w = cols*xw.cw, src_h = rows*xw.ch;
> - int dst_x = BORDER+src_x, dst_y = BORDER+src_y;
> - XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, src_x, src_y, src_w, src_h, dst_x, dst_y);
> +xcopy() {
> + XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
> + XdbeSwapBuffers(xw.dpy, swpinfo, 1);
> +
> }
>
> void
> _AT_@ -1918,6 +1895,7 @@
> void
> draw() {
> drawregion(0, 0, term.col, term.row);
> + xcopy();
> gettimeofday(&xw.lastdraw, NULL);
> }
>
> _AT_@ -1959,7 +1937,6 @@
> }
> if(ib > 0)
> xdraws(buf, base, ox, y, ic, ib);
> - xcopy(0, y, term.col, 1);
> }
> xdrawcursor();
> }
> _AT_@ -1968,13 +1945,10 @@
> expose(XEvent *ev) {
> XExposeEvent *e = &ev->xexpose;
> if(xw.state & WIN_REDRAW) {
> - if(!e->count) {
> + if(!e->count)
> xw.state &= ~WIN_REDRAW;
> - xcopy(0, 0, term.col, term.row);
> - }
> - } else
> - XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER,
> - e->width, e->height, e->x, e->y);
> + }
> + xcopy();
> }
>
> void
Received on Sat Jul 28 2012 - 14:39:21 CEST

This archive was generated by hypermail 2.3.0 : Sat Jul 28 2012 - 14:48:04 CEST