diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-25 17:36:21 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-25 18:28:10 +0100 |
commit | 7a7c08b430da6310ec61138a2c565e27535dbc34 (patch) | |
tree | 4de719630cf0f37c945d33f3d610f237f52743ef | |
parent | bdec377160097ecdd8f6b919a8bcc21867f43616 (diff) |
Use SHM events for synchronisation when possible
-rw-r--r-- | xlib.c | 110 |
1 files changed, 104 insertions, 6 deletions
@@ -5,6 +5,12 @@ #include <stdlib.h> #include <X11/Xutil.h> +#include <X11/Xlibint.h> +#include <X11/Xproto.h> +#include <X11/extensions/XShm.h> +#include <X11/extensions/shmproto.h> +#include <sys/ipc.h> +#include <sys/shm.h> struct xlib_device { struct device base; @@ -16,8 +22,85 @@ struct xlib_device { Window drawable; Pixmap pixmap[2]; GC gc; + + struct { + XShmSegmentInfo shm; + Pixmap pixmap; + int opcode, event; + } shm_sync; }; +static void shm_sync_event (struct xlib_device *device) +{ + XShmCompletionEvent ev; + + ev.type = device->shm_sync.event; + ev.send_event = 1; /* XXX or lie? */ + ev.serial = NextRequest (device->display); + ev.drawable = device->drawable; + ev.major_code = device->shm_sync.opcode; + ev.minor_code = X_ShmPutImage; + ev.shmseg = device->shm_sync.shm.shmid; + ev.offset = device->q; + + XSendEvent (device->display, ev.drawable, False, 0, (XEvent *)&ev); + XFlush (device->display); +} + +static void shm_sync_init (struct xlib_device *device) +{ + Display *dpy = device->display; + int major, minor, has_pixmap; + XExtCodes *codes; + + XShmQueryVersion (dpy, &major, &minor, &has_pixmap); + if (!has_pixmap) + return; + + codes = XInitExtension (dpy, SHMNAME); + if (codes == NULL) + return; + + device->shm_sync.shm.shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0777); + device->shm_sync.shm.shmaddr = (char *) shmat (device->shm_sync.shm.shmid, NULL, 0); + device->shm_sync.shm.readOnly = False; + + if (!XShmAttach (dpy, &device->shm_sync.shm)) + abort (); + + device->shm_sync.opcode = codes ->major_opcode; + device->shm_sync.event = codes->first_event; + + device->shm_sync.pixmap = XShmCreatePixmap (dpy, + device->drawable, + device->shm_sync.shm.shmaddr, + &device->shm_sync.shm, + 1, 1, 24); + + shm_sync_event (device); +} + +static void shm_sync (struct xlib_device *device) +{ + if (!device->shm_sync.pixmap) + return; + + do { + XEvent ev; + XShmCompletionEvent *shm; + + XNextEvent (device->display, &ev); + if (ev.type != device->shm_sync.event) + continue; + + shm = (XShmCompletionEvent *)&ev; + if (shm->shmseg != device->shm_sync.shm.shmid) + continue; + + return; + } while (1); +} + static void destroy (struct framebuffer *fb) { @@ -37,7 +120,9 @@ show (struct framebuffer *fb) 0, 0, device->base.width, device->base.height, 0, 0); - XFlush(device->display); + + XFlush (device->display); + shm_sync(device); } static struct framebuffer * @@ -45,12 +130,23 @@ get_fb (struct device *abstract_device) { struct xlib_device *device = (struct xlib_device *) abstract_device; int q = ++device->q & 1; - XImage *image = XGetImage(device->display, - device->pixmap[q], - 0, 0, 1, 1, - AllPlanes, ZPixmap); - if (image) + if (device->shm_sync.pixmap) { + XCopyArea(device->display, + device->pixmap[q], + device->shm_sync.pixmap, + device->gc, + 0, 0, + 1, 1, + 0, 0); + shm_sync_event (device); + } else { + XImage *image = XGetImage(device->display, + device->pixmap[q], + 0, 0, 1, 1, + AllPlanes, ZPixmap); + if (image) XDestroyImage(image); + } return &device->fb[q]; } @@ -155,5 +251,7 @@ xlib_open (int argc, char **argv) GCGraphicsExposures, &gcv); } + shm_sync_init (device); + return &device->base; } |