From fd71f80efd4c5b3b706ccde7024a9c0c54d1c490 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 27 Jul 2013 13:36:45 +0100 Subject: [PATCH 1/2] xlib: Add support for automatic probing of XShm support Standard code for testing whether the display connections offers the MIT-SHM extension and then verifies that it works (in order to detect and disable SHM over ssh X-tunneling). --- src/xlib.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/xlib.c b/src/xlib.c index 9e1a167..a8a164a 100644 --- a/src/xlib.c +++ b/src/xlib.c @@ -173,6 +173,62 @@ static int xquit(Display *d){ return 0; } +static int _x_error_occurred; + +static int +_check_error_handler(Display *display, + XErrorEvent *event) +{ + _x_error_occurred = 1; + return False; /* ignored */ +} + +static int +can_use_shm(Display *dpy) +{ + XShmSegmentInfo info; + int (*old_handler)(Display *display, XErrorEvent *event); + Status success; + int major, minor, has_pixmap; + + if (!XShmQueryExtension(dpy)) + return 0; + + XShmQueryVersion(dpy, &major, &minor, &has_pixmap); + + info.shmid = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600); + if (info.shmid == -1) + return 0; + + info.readOnly = 0; + info.shmaddr = shmat(info.shmid, NULL, 0); + if (info.shmaddr == (char *) -1) { + shmctl(info.shmid, IPC_RMID, NULL); + return 0; + } + + XLockDisplay (dpy); + XSync(dpy, False); + old_handler = XSetErrorHandler (_check_error_handler); + + _x_error_occurred = 0; + success = XShmAttach(dpy, &info); + if (success) + XShmDetach(dpy, &info); + + XSync(dpy, False); + XSetErrorHandler(old_handler); + XUnlockDisplay(dpy); + + shmctl(info.shmid, IPC_RMID, NULL); + shmdt(info.shmaddr); + + if (!success || _x_error_occurred) + return 0; + + return !!has_pixmap << 1 | 1; +} + void backend_init(){ display = XOpenDisplay (NULL); xfd = ConnectionNumber(display); @@ -188,6 +244,8 @@ void backend_init(){ XFlush(display); XSetIOErrorHandler(xquit); XFlush(display); + + xshm = can_use_shm(display); } void handlekeypress(XEvent *event){ From 6db10a1683546b696beb85a2a8b12a9294a8c382 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 27 Jul 2013 13:39:38 +0100 Subject: [PATCH 2/2] xlib: Support ShmPixmap transport A few drivers offer to create Pixmaps out of shared memory as it reduces the overhead associated with ShmPutImage and allows the driver to optimize storage of the pixmap within video memory. Here this means that any redrawing we require is then a simple blit from within video memory, rather than requiring a fresh transfer every time. This is only useful if we redraw of course, but there should be negative consequences from enabling the pixmap path where supported! --- src/xlib.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/xlib.c b/src/xlib.c index a8a164a..3b7b24a 100644 --- a/src/xlib.c +++ b/src/xlib.c @@ -17,6 +17,7 @@ struct data_t{ XImage *ximg; XShmSegmentInfo *shminfo; + Pixmap shmpix; }; /* Globals */ @@ -64,6 +65,12 @@ static void ximage(struct data_t *data, struct image *img, unsigned int width, u fprintf(stderr, "XShm problems, falling back to to XImage\n"); xshm = 0; } + if(xshm & (1 << 1)){ + data->shmpix = + XShmCreatePixmap(display, window, + ximg->data, shminfo, + width, height, depth); + } }else{ ximg = XCreateImage(display, CopyFromParent, depth, @@ -100,10 +107,11 @@ void backend_prepare(struct image *img, unsigned int width, unsigned int height, } void backend_draw(struct image *img, unsigned int width, unsigned int height){ - assert(((struct data_t *)img->backend)); - assert(((struct data_t *)img->backend)->ximg); + struct data_t *data = img->backend; + assert(data); + assert(data->ximg); - XImage *ximg = ((struct data_t *)img->backend)->ximg; + XImage *ximg = data->ximg; XRectangle rects[2]; int yoffset, xoffset; @@ -126,7 +134,12 @@ void backend_draw(struct image *img, unsigned int width, unsigned int height){ } XFillRectangles(display, window, gc, rects, 2); } - if(xshm){ + if(data->shmpix){ + XCopyArea(display, data->shmpix, window, gc, + 0, 0, + ximg->width, ximg->height, + xoffset, yoffset); + } else if(xshm){ XShmPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height, False); }else{ XPutImage(display, window, gc, ximg, 0, 0, xoffset, yoffset, ximg->width, ximg->height); @@ -139,6 +152,8 @@ void backend_free(struct image *img){ if(img->backend){ struct data_t *data = (struct data_t *)img->backend; XImage *ximg = data->ximg; + if (data->shmpix) + XFreePixmap(display, data->shmpix); if(ximg){ if(xshm && data->shminfo){ XShmDetach(display, data->shminfo); @@ -230,6 +245,8 @@ can_use_shm(Display *dpy) } void backend_init(){ + XGCValues gcv; + display = XOpenDisplay (NULL); xfd = ConnectionNumber(display); assert(display); @@ -237,7 +254,9 @@ void backend_init(){ window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 640, 480, 0, DefaultDepth(display, screen), InputOutput, CopyFromParent, 0, NULL); backend_setaspect(1, 1); - gc = XCreateGC(display, window, 0, NULL); + + gcv.graphics_exposures = False; + gc = XCreateGC(display, window, GCGraphicsExposures, &gcv); XMapRaised(display, window); XSelectInput(display, window, StructureNotifyMask | ExposureMask | KeyPressMask);