summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon TURNEY <jon.turney@dronecode.org.uk>2013-06-30 11:58:54 +0100
committerJon TURNEY <jon.turney@dronecode.org.uk>2013-07-26 18:00:15 +0100
commit05f3ae2e4ea9baee072d6a1471988053d8267228 (patch)
tree88a4cf26f633854e1eab90398f7498981bcaa844
parent4a6b65ede25174200a3ef8a19da905650b7a704c (diff)
Get window image using SHM, if possible
If MIT-SHM extension is available, maintain a SHM segment appropriately sized to hold the window image (i.e. with the same lifetime as the composite pixmap) Try to get window image by copying it to a SHM image, before falling back to copying it to a normal image (for which the image data must be read over the socket from the server)
-rw-r--r--configure.ac2
-rw-r--r--src/libxcwm/context.c3
-rw-r--r--src/libxcwm/event_loop.c58
-rw-r--r--src/libxcwm/image.c59
-rw-r--r--src/libxcwm/window.c3
-rw-r--r--src/libxcwm/xcwm_internal.h3
6 files changed, 113 insertions, 15 deletions
diff --git a/configure.ac b/configure.ac
index b848f5b..e20af3d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@ AC_PROG_OBJC
AC_PROG_INSTALL
# Checks for libraries.
-NEEDED="xcb-damage xcb-composite xcb-event xcb-xtest xcb-image xcb-keysyms xcb-icccm >= 0.3.9 xcb-atom xcb-ewmh"
+NEEDED="xcb-damage xcb-composite xcb-event xcb-xtest xcb-image xcb-keysyms xcb-icccm >= 0.3.9 xcb-atom xcb-ewmh xcb-shm"
PKG_CHECK_MODULES(XCB, $NEEDED)
AC_SUBST(NEEDED)
diff --git a/src/libxcwm/context.c b/src/libxcwm/context.c
index e092fab..57b3460 100644
--- a/src/libxcwm/context.c
+++ b/src/libxcwm/context.c
@@ -119,6 +119,9 @@ xcwm_context_open(char *display)
if (!_xcwm_init_extension(conn, "XKEYBOARD"))
goto fail;
+ context->has_shm = (_xcwm_init_extension(conn, "MIT-SHM") != NULL);
+ context->depth = xcb_aux_get_depth(conn, root_screen);
+
_xcwm_atoms_init(context);
/* Select for XFIXES cursor notify events */
diff --git a/src/libxcwm/event_loop.c b/src/libxcwm/event_loop.c
index 702d6ae..b6769fe 100644
--- a/src/libxcwm/event_loop.c
+++ b/src/libxcwm/event_loop.c
@@ -28,6 +28,8 @@
#endif
#include <pthread.h>
+#include <sys/shm.h>
+
#include <xcwm/xcwm.h>
#include <xcb/composite.h>
#include "xcwm_internal.h"
@@ -105,19 +107,65 @@ _xcwm_event_stop_loop(void)
static void
_xcwm_window_composite_pixmap_release(xcwm_window_t *window)
{
- if (window->composite_pixmap_id)
- {
+ /* Release composite pixmap */
+ if (window->composite_pixmap_id) {
xcb_free_pixmap(window->context->conn, window->composite_pixmap_id);
window->composite_pixmap_id = 0;
}
+
+ /* Release SHM resources */
+ if (window->context->has_shm) {
+ if (window->shminfo.shmseg) {
+ xcb_shm_detach(window->context->conn, window->shminfo.shmseg);
+ window->shminfo.shmseg = 0;
+ }
+
+ if (window->shminfo.shmaddr != (void *)-1) {
+ shmdt(window->shminfo.shmaddr);
+ window->shminfo.shmaddr = (void *)-1;
+ }
+
+ if (window->shminfo.shmid != -1) {
+ shmctl(window->shminfo.shmid, IPC_RMID, 0);
+ window->shminfo.shmid = -1;
+ }
+ }
}
static void
_xcwm_window_composite_pixmap_update(xcwm_window_t *window)
{
- _xcwm_window_composite_pixmap_release(window);
- window->composite_pixmap_id = xcb_generate_id(window->context->conn);
- xcb_composite_name_window_pixmap(window->context->conn, window->window_id, window->composite_pixmap_id);
+ _xcwm_window_composite_pixmap_release(window);
+
+ /* Assign a pixmap XID to the composite pixmap */
+ window->composite_pixmap_id = xcb_generate_id(window->context->conn);
+ xcb_composite_name_window_pixmap(window->context->conn, window->window_id, window->composite_pixmap_id);
+
+ if (window->context->has_shm)
+ {
+ /* Pre-compute the size of image data needed for this window */
+ xcb_image_t *image = xcb_image_create_native(window->context->conn,
+ window->bounds.width,
+ window->bounds.height,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ window->context->depth,
+ NULL, ~0, NULL);
+ size_t image_size = image->size;
+ xcb_image_destroy(image);
+ printf("window 0x%08x requires %d bytes of SHM\n", window->window_id, image_size);
+
+ /* Allocate SHM resources */
+ window->shminfo.shmid = shmget(IPC_PRIVATE, image_size, IPC_CREAT | 0777);
+ if (window->shminfo.shmid < 0)
+ fprintf(stderr, "shmget failed\n");
+
+ window->shminfo.shmaddr = shmat(window->shminfo.shmid, 0, 0);
+ if (window->shminfo.shmaddr < 0)
+ fprintf(stderr, "shmget failed\n");
+
+ window->shminfo.shmseg = xcb_generate_id(window->context->conn);
+ xcb_shm_attach(window->context->conn, window->shminfo.shmseg, window->shminfo.shmid, 0);
+ }
}
/*
diff --git a/src/libxcwm/image.c b/src/libxcwm/image.c
index cb5ca26..34069d4 100644
--- a/src/libxcwm/image.c
+++ b/src/libxcwm/image.c
@@ -36,7 +36,7 @@
xcwm_image_t *
xcwm_image_copy_partial(xcwm_window_t *window, xcwm_rect_t *area)
{
- xcb_image_t *image;
+ xcb_image_t *image = NULL;
/* Return null if image is 0 by 0 */
if (area->width == 0 || area->height == 0) {
@@ -44,14 +44,55 @@ xcwm_image_copy_partial(xcwm_window_t *window, xcwm_rect_t *area)
}
/* Get the image of the specified area of the window */
- image = xcb_image_get(window->context->conn,
- window->composite_pixmap_id,
- area->x,
- area->y,
- area->width,
- area->height,
- (unsigned int)~0L,
- XCB_IMAGE_FORMAT_Z_PIXMAP);
+
+ if (window->context->has_shm && window->shminfo.shmaddr) {
+ /*
+ A composite pixmap cannot be a shm pixmap, so we must use
+ xcb_image_shm_get to copy the image from the window's composite
+ pixmap to a shm image.
+
+ Rather than creating it every-time, we keep a shared memory
+ segment around which is of the right size for the window image.
+ */
+
+ /* Create an xcb_image_t for which we manage the data */
+ image = xcb_image_create_native(window->context->conn,
+ area->width,
+ area->height,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ window->context->depth,
+ NULL, ~0, NULL);
+ if (image) {
+ /* data is the shared memory */
+ image->data = window->shminfo.shmaddr;
+
+ /* Read image data from the composite pixmap into the shm image */
+ if (!xcb_image_shm_get(window->context->conn,
+ window->composite_pixmap_id,
+ image,
+ window->shminfo,
+ area->x,
+ area->y,
+ (unsigned int)~0L)) {
+ xcb_image_destroy(image);
+ image = NULL;
+ }
+ }
+ }
+
+ if (!image && window->context->has_shm)
+ printf("has_shm, but falling back to socket image\n");
+
+ /* If shm not available, or failed, use xcb_image_get() */
+ if (!image)
+ image = xcb_image_get(window->context->conn,
+ window->composite_pixmap_id,
+ area->x,
+ area->y,
+ area->width,
+ area->height,
+ (unsigned int)~0L,
+ XCB_IMAGE_FORMAT_Z_PIXMAP);
/* Failed to get a valid image, return null */
if (!image) {
diff --git a/src/libxcwm/window.c b/src/libxcwm/window.c
index 0b227de..eafda92 100644
--- a/src/libxcwm/window.c
+++ b/src/libxcwm/window.c
@@ -120,6 +120,9 @@ _xcwm_window_create(xcwm_context_t *context, xcb_window_t new_window,
window->notified_bounds = window->bounds;
window->opacity = ~0;
window->composite_pixmap_id = 0;
+ window->shminfo.shmseg = 0;
+ window->shminfo.shmaddr = (void *)-1;
+ window->shminfo.shmid = -1;
window->local_data = 0;
window->shape = 0;
diff --git a/src/libxcwm/xcwm_internal.h b/src/libxcwm/xcwm_internal.h
index 9e3b993..99c6e00 100644
--- a/src/libxcwm/xcwm_internal.h
+++ b/src/libxcwm/xcwm_internal.h
@@ -69,6 +69,8 @@ struct xcwm_context_t {
int fixes_event_base;
xcb_window_t wm_cm_window;
xcwm_wm_atoms_t atoms;
+ int has_shm;
+ int depth;
};
/**
@@ -92,6 +94,7 @@ struct xcwm_window_t {
void *local_data; /* Area for data client cares about */
unsigned int opacity;
xcb_pixmap_t composite_pixmap_id;
+ xcb_shm_segment_info_t shminfo;
xcb_shape_get_rectangles_reply_t *shape;
};