changeset 691:05a453e07d01

X_supp.c uses XSHM to avoid overhead of transmission
author Thinker K.F. Li <thinker@branda.to>
date Mon, 09 Aug 2010 09:01:19 +0800
parents 86c6ebf1de25
children 201cc86720a3
files src/X_supp.c
diffstat 1 files changed, 117 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/X_supp.c	Sat Aug 07 23:00:16 2010 +0800
+++ b/src/X_supp.c	Mon Aug 09 09:01:19 2010 +0800
@@ -8,6 +8,15 @@
 #include "mb_timer.h"
 #include "mb_X_supp.h"
 
+#define XSHM 1
+
+#ifdef XSHM
+/* \sa http://www.xfree86.org/current/mit-shm.html */
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#endif
+
 #define ERR -1
 #define OK 0
 
@@ -52,6 +61,11 @@
     /* States */
     shape_t *last;
 #endif
+
+#ifdef XSHM
+    XImage *ximage;
+    XShmSegmentInfo shminfo;
+#endif
 };
 
 /*! \defgroup xkb X Keyboard Handling
@@ -453,6 +467,94 @@
     return OK;
 }
 
+#ifdef XSHM
+static void
+xshm_destroy(X_MB_runtime_t *xmb_rt) {
+    XShmSegmentInfo *shminfo;
+
+    shminfo = &xmb_rt->shminfo;
+    
+    if(xmb_rt->shminfo.shmaddr) {
+	XShmDetach(xmb_rt->display, shminfo);
+    }
+    
+    if(xmb_rt->ximage) {
+	XDestroyImage(xmb_rt->ximage);
+	xmb_rt->ximage = NULL;
+    }
+    
+    if(shminfo->shmaddr) {
+	shmdt(shminfo->shmaddr);
+	shminfo->shmaddr = NULL;
+    }
+    
+    if(shminfo->shmid) {
+	shmctl(shminfo->shmid, IPC_RMID, 0);
+	shminfo->shmid = 0;
+    }
+}
+
+static void
+xshm_init(X_MB_runtime_t *xmb_rt) {
+    Display *display;
+    Visual *visual;
+    XImage *ximage;
+    int screen;
+    int depth;
+    int support_shm;
+    int mem_sz;
+    XShmSegmentInfo *shminfo;
+    int surf_fmt;
+
+    display = xmb_rt->display;
+    visual = xmb_rt->visual;
+    shminfo = &xmb_rt->shminfo;
+    
+    support_shm = XShmQueryExtension(display);
+    if(!support_shm)
+	return;
+    
+    screen = DefaultScreen(display);
+    depth = DefaultDepth(display, screen);
+    
+    if(depth != 24 && depth != 32)
+	return;
+    
+    xmb_rt->ximage = XShmCreateImage(display, visual, depth,
+				     ZPixmap, NULL, shminfo,
+				     xmb_rt->w, xmb_rt->h);
+    ximage = xmb_rt->ximage;
+    
+    mem_sz = ximage->bytes_per_line * ximage->height;
+    shminfo->shmid = shmget(IPC_PRIVATE, mem_sz, IPC_CREAT | 0777);
+    if(shminfo->shmid == -1) {
+	xshm_destroy(xmb_rt);
+	return;
+    }
+
+    shminfo->shmaddr = shmat(shminfo->shmid, 0, 0);
+    ximage->data = shminfo->shmaddr;
+    
+    shminfo->readOnly = 0;
+
+    XShmAttach(display, shminfo);
+
+    switch(depth) {
+    case 24: surf_fmt = CAIRO_FORMAT_RGB24; break;
+    case 32: surf_fmt = CAIRO_FORMAT_ARGB32; break;
+    }
+
+    xmb_rt->backend_surface =
+	cairo_image_surface_create_for_data(ximage->data,
+					    surf_fmt,
+					    xmb_rt->w,
+					    xmb_rt->h,
+					    ximage->bytes_per_line);
+    if(xmb_rt->backend_surface == NULL)
+	xshm_destroy(xmb_rt);
+}
+#endif /* XSHM */
+
 /*! \brief Initialize a MadButterfy runtime for Xlib.
  *
  * It setups a runtime environment to run MadButterfly with Xlib.
@@ -461,13 +563,20 @@
 static int X_MB_init(const char *display_name,
 	      int w, int h, X_MB_runtime_t *xmb_rt) {
     mb_img_ldr_t *img_ldr;
+    int r;
     
     memset(xmb_rt, 0, sizeof(X_MB_runtime_t));
 
     xmb_rt->w = w;
     xmb_rt->h = h;
-    X_init_connection(display_name, w, h, &xmb_rt->display,
-		      &xmb_rt->visual, &xmb_rt->win);
+    r = X_init_connection(display_name, w, h, &xmb_rt->display,
+			  &xmb_rt->visual, &xmb_rt->win);
+    if(r != OK)
+	return ERR;
+
+#ifdef XSHM
+    xshm_init(xmb_rt);
+#endif
 
     xmb_rt->surface =
 	mbe_image_surface_create(MB_IFMT_ARGB32, w, h);
@@ -475,11 +584,12 @@
     xmb_rt->surface_ptn =
 	mbe_pattern_create_for_surface(xmb_rt->surface);
     
-    xmb_rt->backend_surface =
-	mbe_xlib_surface_create(xmb_rt->display,
-				  xmb_rt->win,
-				  xmb_rt->visual,
-				  w, h);
+    if(xmb_rt->backend_surface != NULL) /* xshm_init() may create one */
+	xmb_rt->backend_surface =
+	    mbe_xlib_surface_create(xmb_rt->display,
+				    xmb_rt->win,
+				    xmb_rt->visual,
+				    w, h);
 
     xmb_rt->cr = mbe_create(xmb_rt->surface);
     xmb_rt->backend_cr = mbe_create(xmb_rt->backend_surface);