summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-08-25 17:36:21 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2013-08-25 18:28:10 +0100
commit7a7c08b430da6310ec61138a2c565e27535dbc34 (patch)
tree4de719630cf0f37c945d33f3d610f237f52743ef
parentbdec377160097ecdd8f6b919a8bcc21867f43616 (diff)
Use SHM events for synchronisation when possible
-rw-r--r--xlib.c110
1 files changed, 104 insertions, 6 deletions
diff --git a/xlib.c b/xlib.c
index 6ca665d..b98735b 100644
--- a/xlib.c
+++ b/xlib.c
@@ -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;
}