doug@wbcs.UUCP (Doug Kratky) (10/16/89)
Could someone give me hints, code fragments, or examples on "double-buffering" with X? -- Doug Kratky Boeing Computer Services ...!scubed!ncr-sd!ncrwic!wbcs!doug PO Box 7730, MS K79-32 ...!bellcore!fenix!ncrlnk!ncrwic!wbcs!doug Wichita, KS 67277-7730 ...!hplabs!hp-sdd!ncr-sd!ncrwic!wbcs!doug
rick@hanauma.stanford.edu (Richard Ottolini) (10/17/89)
In article <181@wbcs.UUCP> doug@wbcs.UUCP (Doug Kratky) writes: >Could someone give me hints, code fragments, or examples >on "double-buffering" with X? Draw into an offscreen pixmap, then copy it onto screen. This works well on a fast X-server such as a DEC 3100 and not so well on a slow server such as any Sun. (Not all drawing operations that work on screens work on pixmaps such as erase.)
klee@chico.pa.dec.com (Ken Lee) (10/17/89)
In article <181@wbcs.UUCP>, doug@wbcs.UUCP (Doug Kratky) writes: > Could someone give me hints, code fragments, or examples > on "double-buffering" with X? Check out ico (-dbl option) in the demos directory of the X11R3 tape. Ken Lee DEC Western Software Laboratory, Palo Alto, Calif. Internet: klee@decwrl.dec.com uucp: uunet!decwrl!klee
klee@chico.pa.dec.com (Ken Lee) (10/17/89)
In article <170@med.Stanford.EDU>, rick@hanauma.stanford.edu (Richard Ottolini) writes: > In article <181@wbcs.UUCP> doug@wbcs.UUCP (Doug Kratky) writes: > >Could someone give me hints, code fragments, or examples > >on "double-buffering" with X? > > Draw into an offscreen pixmap, then copy it onto screen. This isn't really "double buffering". Double buffering avoids the copy by writing to 2 different planes (or groups of planes) of a multi-plane display, then fiddling with the colormap to determine which planes show. The advantage of this approach is that, on most systems, changing the colormap is much faster than copying pixmaps. As I mentioned earlier, some of the X11R3 demo programs, such as ico, implement double buffering. Ken Lee DEC Western Software Laboratory, Palo Alto, Calif. Internet: klee@decwrl.dec.com uucp: uunet!decwrl!klee
markc@Solbourne.COM (Mark Connell) (10/17/89)
In article <181@wbcs.UUCP>, doug@wbcs.UUCP (Doug Kratky) writes: > > Could someone give me hints, code fragments, or examples > on "double-buffering" with X? > -- > Doug Kratky True double-buffering is not supported under X. ico has an option (-dbl) that will use colormap double-buffering. See the source for your example. You can also implement your own double-buffering by using 2 pixmaps for your buffers and using CopyArea to display the appropriate buffers. Mark A. Connell Solbourne Computer, Inc. 1900 Pike Road Longmont, Co 80501 (303) 772-3400 markc@Solbourne.COM ...!uunet!stan!markc
bobtl@toolbox.WV.TEK.COM (10/17/89)
In article <1929@bacchus.dec.com> klee@decwrl.dec.com writes: >In article <170@med.Stanford.EDU>, rick@hanauma.stanford.edu (Richard >Ottolini) writes: >The advantage of this approach is that, on most systems, >changing the colormap is much faster than copying pixmaps. Unless the window manager gets in the way. Is the mechanism in ICCCM fast enough for this? I am asking because I have never seen this done in a truly compliant application with a truly compliant window manager. Whatever truly compliant means. >Ken Lee >DEC Western Software Laboratory, Palo Alto, Calif. >Internet: klee@decwrl.dec.com >uucp: uunet!decwrl!klee Bob Toole
rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (10/17/89)
changing the colormap is much faster than copying pixmaps. Unless the window manager gets in the way. Is the mechanism in ICCCM fast enough for this? Independent of ICCCM. We're talking about changing RGB values in a writable colormap, not installing a new colormap. The WM does't get involved at all. Note that there is a proposed double-buffering extension to X, which was out for public review this summer. We have a (very) sample implementation which is expected to be in R4.
madd@bu-cs.BU.EDU (Jim Frost) (10/17/89)
In article <170@med.Stanford.EDU> rick@hanauma.UUCP (Richard Ottolini) writes: |In article <181@wbcs.UUCP> doug@wbcs.UUCP (Doug Kratky) writes: |>Could someone give me hints, code fragments, or examples |>on "double-buffering" with X? | |Draw into an offscreen pixmap, then copy it onto screen. |This works well on a fast X-server such as a DEC 3100 and not so well |on a slow server such as any Sun. Actually it works pretty well even on the 386i server (the SLOOOW server), especially if compiled with gcc. When working for my previous employer we used this method to make graphics changes seem atomic to the user; the copies were fast enough to be generally unnoticable, especially if the copy is limited to the changed area. We were using a fullscreen window for our display and it still worked well. On fast servers it works extremely well, although you're not going to get real-time animation out of it as you can with true double-buffering (our application worked much better under SGI GL with or without double buffering than under X, imagine that :-). |(Not all drawing operations that work on screens work on pixmaps such |as erase.) True, but it's simple enough to fill a rectangle to take care of this case. jim frost software tool & die madd@std.com
stroyan@hpfcdq.HP.COM (Mike Stroyan) (10/18/89)
> Could someone give me hints, code fragments, or examples > on "double-buffering" with X? > Doug Kratky Below is a set of utility functions for double buffering in X. The functions use colormap manipulation; they therefore require a dynamic visual such as GrayScale, PseudoColor or DirectColor. The example program will fail if the default visual is not dynamic or has less than 16 free colors. There is also a more subtle requirement of grouping by planes, so the program may fail even though 16 colors are free. A program could avoid many of these hurdles by creating a window with an appropriate visual and a private colormap. You then have to handle the colormap focus issues. Mike Stroyan, stroyan@hpfcla.hp.com # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Mike Stroyan <stroyan@hpstryn> on Tue Oct 17 16:48:15 1989 # # This archive contains: # Makefile dbuf.c double_buf.c double_buf.h # LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH echo x - Makefile cat >Makefile <<'@EOF' CFLAGS= -O LDFLAGS= -lX11 -lm dbuf: dbuf.c double_buf.o $(CC) $(CFLAGS) -o dbuf dbuf.c double_buf.o -lX11 -lm @EOF chmod 664 Makefile echo x - dbuf.c cat >dbuf.c <<'@EOF' /* dbuf.c - a demonstration of double buffering under X windows */ #include <X11/Xlib.h> #include <X11/Xutil.h> #include <malloc.h> #include <math.h> #include <stdio.h> #include <time.h> #include "double_buf.h" #define POINTS 6 main(argc, argv) int argc; char *argv[]; { Display *display; Window w1, w2; GC gc1, gc2; XGCValues gcvalues; XColor colors[4]; XPoint data[POINTS]; double_buffer_state *dbuf_state; double start_angle, angle; register int i; struct timeval timeout; XEvent event; static XSizeHints xsh = { /* Size hints for window manager */ (PPosition | PSize | PMinSize), /* flags */ 400, /* height */ 400, /* width */ 200, /* minimum height */ 200, /* minimum width */ 300, /* x coordinate */ 200 /* y coordinate */ }; static XWMHints xwmh = { /* More hints for window manager */ (InputHint | StateHint), /* flags */ False, /* input */ NormalState, /* initial_state */ 0, /* icon pixmap */ 0, /* icon window */ 0, 0, /* icon location */ 0, /* icon mask */ 0, /* Window group */ }; static XClassHint xch = { /* Class hints for window manager */ "Dbuf", /* name */ "Dbuf" /* class */ }; timeout.tv_sec = 0; timeout.tv_usec = 50000; if ((display = XOpenDisplay(NULL)) == NULL) { fprintf(stderr, "Can't open %s\n", XDisplayName(NULL)); exit(1); } /* * Create two windows. * Window w1 will be double buffered. * Window w2 won't be. */ w1 = XCreateSimpleWindow(display, DefaultRootWindow(display), xsh.x, xsh.y, xsh.width, xsh.height, 2, WhitePixel(display, DefaultScreen(display)), BlackPixel(display, DefaultScreen(display))); if (!w1) { fprintf (stderr, "XCreateSimpleWindow failed\n"); exit(1); } gc1 = XCreateGC(display, w1, 0, &gcvalues); XSetStandardProperties(display, w1, "double buffered", "double buffered", None, argv, argc, &xsh); XSetWMHints(display, w1, &xwmh); XSetClassHint(display, w1, &xch); XSelectInput(display, w1, StructureNotifyMask | ButtonPressMask); XMapWindow(display, w1); XFlush(display); do { XNextEvent(display, &event); } while (event.type != MapNotify || event.xmap.window != w1); xsh.x = 600; w2 = XCreateSimpleWindow(display, DefaultRootWindow(display), xsh.x, xsh.y, xsh.width, xsh.height, 2, WhitePixel(display, DefaultScreen(display)), BlackPixel(display, DefaultScreen(display))); if (!w2) { fprintf (stderr, "XCreateSimpleWindow failed\n"); exit(1); } gc2 = XCreateGC(display, w2, 0, gcvalues); XSetStandardProperties(display, w2, "single buffered", "single buffered", None, argv, argc, &xsh); XSetWMHints(display, w2, &xwmh); XSetClassHint(display, w2, &xch); XSelectInput(display, w2, StructureNotifyMask | ButtonPressMask); XMapWindow(display, w2); XFlush(display); do { XNextEvent(display, &event); } while (event.type != MapNotify || event.xmap.window != w2); /* black */ colors[0].red = 0; colors[0].green = 0; colors[0].blue = 0; /* white */ colors[1].red = 65535; colors[1].green = 65535; colors[1].blue = 65535; /* green */ colors[2].red = 0; colors[2].green = 40000; colors[2].blue = 0; /* yellow */ colors[3].red = 65535; colors[3].green = 65535; colors[3].blue = 0; dbuf_state = start_double_buffer(display, DefaultColormap(display, DefaultScreen(display)), 2, colors); if (dbuf_state == NULL) { fprintf(stderr, "Couldn't allocate resources for double buffering\n"); exit(1); } XSetPlaneMask(display, gc1, dbuf_state->drawing_planes); start_angle = 0.0; while (XPending(display) == 0) { start_angle += M_PI / 50.0; angle = start_angle; for (i=0; i<POINTS; i++) { data[i].x = 100.0 + 80.0 * cos(angle); data[i].y = 100.0 + 80.0 * sin(angle); angle += 4.0 * M_PI / ((double) (POINTS-1)); } XSetForeground(display, gc1, colors[0].pixel); XSetForeground(display, gc2, colors[0].pixel); XFillRectangle(display, w1, gc1, 0, 0, xsh.width, xsh.height); XFillRectangle(display, w2, gc2, 0, 0, xsh.width, xsh.height); XSetForeground(display, gc1, colors[2].pixel); XSetForeground(display, gc2, colors[2].pixel); XFillPolygon(display, w1, gc1, data, POINTS, Complex, CoordModeOrigin); XFillPolygon(display, w2, gc2, data, POINTS, Complex, CoordModeOrigin); XSetForeground(display, gc1, colors[1].pixel); XSetForeground(display, gc2, colors[1].pixel); XDrawLines(display, w1, gc1, data, POINTS, CoordModeOrigin); XDrawLines(display, w2, gc2, data, POINTS, CoordModeOrigin); double_buffer_switch(dbuf_state); XSetPlaneMask(display, gc1, dbuf_state->drawing_planes); XFlush(display); select(0, 0, 0, 0, &timeout); } end_double_buffer(dbuf_state); XCloseDisplay(display); exit(0); } @EOF chmod 666 dbuf.c echo x - double_buf.c cat >double_buf.c <<'@EOF' /* * double_buf.c - an Xlib double buffering utility. */ #include <X11/Xlib.h> #include <malloc.h> #include <stdio.h> #include "double_buf.h" static void release(state) register double_buffer_state *state; /* * Release a possibly partially allocated double buffer state record. */ { if (state != NULL) { if (state->colormaps[0] != NULL) free(state->colormaps[0]); if (state->colormaps[1] != NULL) free(state->colormaps[1]); if (state->planes != NULL) free(state->planes); free(state); } } static long color(state, simple_color) register double_buffer_state *state; register long simple_color; /* * Map the supplied color into the equivalent color * using the double buffered planes. */ { register long i, plane, computed_color; computed_color = state->pixel; for (plane = 1, i = 0; simple_color != 0; plane <<= 1, i++) { if (plane & simple_color) { computed_color |= state->planes[i]; simple_color &= ~plane; } } return(computed_color); } double_buffer_state *start_double_buffer(display, cmap, planes, colors) Display *display; Colormap cmap; long planes; /* how many planes for each buffer */ XColor *colors; /* color settings for buffers */ /* * Start double buffering in given number of planes per buffer. * If resources can be allocated, then set color pixels in colors parameter * and return the address of a double_buffer_state record. * Otherwise, return NULL. */ { register double_buffer_state *state; register long i, high_mask, low_mask; /* Allocate memory. */ state = (double_buffer_state *) malloc(sizeof(double_buffer_state)); if (state == NULL) return (NULL); state->map_size = 1 << (2 * planes); state->colormaps[0] = (XColor *) malloc(state->map_size * sizeof(XColor)); state->colormaps[1] = (XColor *) malloc(state->map_size * sizeof(XColor)); state->planes = (long *) malloc((2 * planes) * sizeof(long)); if (state->colormaps[1] == NULL || state->colormaps[0] == NULL || state->planes == NULL) { release(state); return(NULL); } state->display = display; state->cmap = cmap; /* Get colors to double buffer with. */ if (XAllocColorCells(state->display, state->cmap, False, state->planes, 2*planes, &state->pixel, 1) == 0) { release(state); return(NULL); } /* Prepare the write enable masks. */ state->masks[0] = AllPlanes; state->masks[1] = AllPlanes; /* Mask 0 won't write in the "low" planes. */ /* Mask 1 won't write in the "high" planes. */ for (i = 0; i < planes; i++) { state->masks[0] &= ~state->planes[i]; state->masks[1] &= ~state->planes[planes + i]; } /* Prepare the flags and pixel values for each color. */ for (i = 0; i < (1 << planes); i++) { colors[i].pixel = color(state, i | (i << planes)); colors[i].flags = DoRed | DoGreen | DoBlue; } /* Prepare the two color map settings. */ /* Colormap 0 displays the "low" planes. */ /* Colormap 1 displays the "high" planes. */ low_mask = (1 << planes) - 1; high_mask = low_mask << planes; for (i = state->map_size - 1; i >= 0; i--) { state->colormaps[0][i] = colors[i & low_mask]; state->colormaps[0][i].pixel = color(state, i); state->colormaps[1][i] = colors[(i & high_mask) >> planes]; state->colormaps[1][i].pixel = color(state, i); } /* Set up initial color map and write_enable. */ state->buffer = 0; state->drawing_planes = state->masks[state->buffer]; XStoreColors(state->display, state->cmap, state->colormaps[state->buffer], state->map_size); return(state); } void double_buffer_switch(state) register double_buffer_state *state; /* * Change double buffering buffer. * Return the new planes mask for double buffering. */ { /* Toggle the buffers. */ state->buffer ^= 1; /* Adjust the color map and write enable mask. */ XStoreColors(state->display, state->cmap, state->colormaps[state->buffer], state->map_size); state->drawing_planes = state->masks[state->buffer]; } void end_double_buffer(state) register double_buffer_state *state; { XFreeColors(state->display, state->cmap, &state->pixel, 1, ~(state->masks[0] & state->masks[1])); release(state); } @EOF chmod 664 double_buf.c echo x - double_buf.h cat >double_buf.h <<'@EOF' /* * double_buf.h - declarations for an Xlib double buffering utility. */ /* double buffering state record */ typedef struct { Display *display; Colormap cmap; long drawing_planes; /* planes currently drawn to */ int buffer; /* which buffer to show, even or odd */ XColor *colormaps[2]; /* color maps for even and odd buffers */ int map_size; /* number of entries in color maps */ long masks[2]; /* write_enable masks for odd and even */ long *planes; /* individual planes */ long pixel; /* pixel base value of double buffering */ } double_buffer_state; /* double buffering procedures */ extern double_buffer_state *start_double_buffer(); extern void double_buffer_switch(); extern void end_double_buffer(); @EOF chmod 664 double_buf.h exit 0
kent@gnomee.pa.dec.com (Christopher A. Kent) (10/20/89)
The alternative is to grab an array of pixels in the default colormap and repeatedly do StoreColors there. That's how clover works. Changing colormaps is pretty slow with a compliant window manager. Chris Kent Western Software Laboratory Digital Equipment Corporation kent@decwrl.dec.com decwrl!kent (415) 853-6639
jimmc@sci.UUCP (Jim McBeath) (10/27/89)
The standard distribution of the 'ico' program (in core.src/demos) does double buffering. It's actually not very difficult to do. Take a look at the functions initDBufs, setBufColname, setBufColor, setDrawBuf, and setDisplayBuf. I find that approach pretty straightforward, but then I might be a little bit biased, since I wrote the double buffering for ico. Jim McBeath sci!jimmc@decwrl.dec.com Silicon Compilers Systems Corporation (408)371-2900 2045 Hamilton Avenue, San Jose CA 95125