[PATCH] [xshm] Basic infrastructure.
Chris Wilson
chris at chris-wilson.co.uk
Thu Aug 14 11:26:49 PDT 2008
Introduce detection of the X Shared Memory extension for a display and a
buddy allocator for shared memory pools.
Having acquired some shared memory, we put it to use in
_get_image_surface() and _draw_image_surface() when possible.
The missing features are how to enable efficient uploading of unknown image
surfaces (i.e. clone_similar() support) which require image->data to be
created within a shared memory segment, and the ability to directly
modify the pixels representing the surface.
---
configure.in | 25 ++
src/cairo-xlib-display.c | 734 ++++++++++++++++++++++++++++++++++++++
src/cairo-xlib-private.h | 38 ++
src/cairo-xlib-surface-private.h | 3 +
src/cairo-xlib-surface.c | 332 ++++++++++++++++-
5 files changed, 1115 insertions(+), 17 deletions(-)
diff --git a/configure.in b/configure.in
index d0e8bb6..a74c938 100644
--- a/configure.in
+++ b/configure.in
@@ -342,6 +342,30 @@ CAIRO_BACKEND_ENABLE(xlib, Xlib, xlib, XLIB_SURFACE, auto, [
fi])
])
+#FIXME: Not strictly a backend, but a handy feature test macro
+CAIRO_BACKEND_ENABLE(xlib_xshm, X Shared Memory, xlib-xshm, XLIB_XSHM, auto, [
+ if test "x$use_xlib" != "xyes"; then
+ use_xlib_xshm="no (requires --enable-xlib)"
+ else
+ dnl Check for XShm header files if the XShm package is not installed:
+ xlib_xshm_BASE=cairo-xlib
+ xlib_xshm_REQUIRES="xext"
+ PKG_CHECK_MODULES(xlib_xshm, $xlib_xshm_REQUIRES, ,
+ [AC_MSG_RESULT(no)
+ xlib_xshm_REQUIRES=""
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $xlib_CFLAGS $xlib_NONPKGCONFIG_CFLAGS"
+ AC_CHECK_HEADER(X11/extensions/XShm.h,
+ [xlib_xshm_NONPKGCONFIG_LIBS="-lXext"],
+ [use_xlib_xshm="no (requires Xext http://freedesktop.org/Software/xlibs)"], [
+#include <X11/Xlib.h>
+#include <X11/Xdefs.h>
+])
+ CPPFLAGS=$old_CPPFLAGS
+ ])
+ fi
+])
+
CAIRO_BACKEND_ENABLE(xlib_xrender, Xlib Xrender, xlib-xrender, XLIB_XRENDER_SURFACE, auto, [
if test "x$use_xlib" != "xyes"; then
use_xlib_xrender="no (requires --enable-xlib)"
@@ -1119,6 +1143,7 @@ echo " Quartz: $use_quartz_font"
echo ""
echo "the following features:"
echo " PNG functions: $use_png"
+echo " X Shared Memory: $use_xlib_xshm"
echo ""
echo "and the following debug options:"
echo " gcov support: $use_gcov"
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 895258d..be04a59 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -39,6 +39,12 @@
#include <fontconfig/fontconfig.h>
#include <X11/Xlibint.h> /* For XESetCloseDisplay */
+#ifdef CAIRO_HAS_XLIB_XSHM
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <errno.h>
+#endif
typedef int (*cairo_xlib_error_func_t) (Display *display,
XErrorEvent *event);
@@ -65,6 +71,10 @@ struct _cairo_xlib_job {
static cairo_xlib_display_t *_cairo_xlib_display_list;
static void
+_cairo_xlib_display_shm_mem_pool_destroy (cairo_xlib_display_t *display,
+ cairo_xlib_shm_mem_pool_t *pool);
+
+static void
_cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display)
{
cairo_xlib_screen_info_t *screen;
@@ -72,6 +82,7 @@ _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display)
/* call all registered shutdown routines */
CAIRO_MUTEX_LOCK (display->mutex);
+ display->closing = TRUE;
for (screen = display->screens; screen != NULL; screen = screen->next)
_cairo_xlib_screen_info_close_display (screen);
@@ -99,6 +110,10 @@ _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display)
hooks = display->close_display_hooks;
}
+
+ while (display->shm_pools != NULL)
+ _cairo_xlib_display_shm_mem_pool_destroy (display, display->shm_pools);
+
display->closed = TRUE;
CAIRO_MUTEX_UNLOCK (display->mutex);
@@ -150,6 +165,7 @@ _cairo_xlib_display_destroy (cairo_xlib_display_t *display)
_cairo_freelist_free (&display->wq_freelist, job);
}
+ _cairo_freelist_fini (&display->shm_info_freelist);
_cairo_freelist_fini (&display->wq_freelist);
_cairo_freelist_fini (&display->hook_freelist);
@@ -215,6 +231,51 @@ _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
return 0;
}
+#ifdef CAIRO_HAS_XLIB_XSHM
+static cairo_bool_t _x_error_occurred;
+static int
+_check_error_handler (Display *display,
+ XErrorEvent *event)
+{
+ _x_error_occurred = TRUE;
+ return False; /* return value is ignored */
+}
+static cairo_bool_t
+can_use_shm (Display *dpy)
+{
+ XShmSegmentInfo shm;
+ cairo_xlib_error_func_t old_handler;
+ Status success;
+
+ shm.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+ if (shm.shmid == -1)
+ return FALSE;
+
+ shm.readOnly = FALSE;
+ shm.shmaddr = shmat (shm.shmid, NULL, 0);
+ if (shm.shmaddr == (char *) -1) {
+ shmctl (shm.shmid, IPC_RMID, NULL);
+ return FALSE;
+ }
+
+ /* still holding _cairo_xlib_display_mutex */
+ _x_error_occurred = FALSE;
+ old_handler = XSetErrorHandler (_check_error_handler);
+
+ success = XShmAttach (dpy, &shm);
+ if (success)
+ XShmDetach (dpy, &shm);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+
+ shmctl (shm.shmid, IPC_RMID, NULL);
+ shmdt (shm.shmaddr);
+
+ return success && ! _x_error_occurred;
+}
+#endif
+
cairo_xlib_display_t *
_cairo_xlib_display_get (Display *dpy)
{
@@ -285,11 +346,30 @@ _cairo_xlib_display_get (Display *dpy)
display->screens = NULL;
display->workqueue = NULL;
display->close_display_hooks = NULL;
+ display->closing = FALSE;
display->closed = FALSE;
memset (display->cached_xrender_formats, 0,
sizeof (display->cached_xrender_formats));
+ display->shm_pools = NULL;
+ display->use_shm = FALSE;
+ display->have_shm_pixmaps = FALSE;
+#ifdef CAIRO_HAS_XLIB_XSHM
+ if (XShmQueryExtension (dpy)) {
+ Bool pixmaps;
+ if (XShmQueryVersion (dpy, &major_unused, &minor_unused, &pixmaps)) {
+ display->use_shm = TRUE;
+ if (pixmaps)
+ display->have_shm_pixmaps = XShmPixmapFormat (dpy) == ZPixmap;
+ }
+ }
+ if (display->use_shm)
+ display->use_shm = can_use_shm (dpy);
+#endif
+ _cairo_freelist_init (&display->shm_info_freelist,
+ sizeof (cairo_xlib_shm_info_t));
+
display->buggy_repeat = FALSE;
if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
/* When modularized, the X.Org server VendorRelease was
@@ -519,3 +599,657 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
return xrender_format;
}
+
+#ifdef CAIRO_HAS_XLIB_XSHM
+/* a simple buddy allocator for memory pools */
+/* XXX a slab allocator will have behave better, or adapt Doug Lea's malloc? */
+typedef struct _cairo_xlib_shm_mem_block cairo_xlib_shm_mem_block_t;
+struct _cairo_xlib_shm_mem_block {
+ unsigned long sync_request;
+ unsigned int bits;
+ cairo_xlib_shm_mem_block_t *prev, *next;
+};
+struct _cairo_xlib_shm_mem_pool {
+ XShmSegmentInfo shm;
+ unsigned long attached;
+
+ char *base;
+ unsigned int nBlocks;
+ cairo_xlib_shm_mem_block_t *blocks;
+ cairo_xlib_shm_mem_block_t *free[32], *free_tail[32];
+ unsigned char *map;
+
+ unsigned int min_bits; /* Minimum block size is 1 << min_bits */
+ unsigned int num_sizes;
+
+ size_t free_bytes;
+ size_t max_bytes;
+ unsigned int max_free_bits;
+
+ cairo_xlib_shm_mem_pool_t *next;
+};
+
+#define BITTEST(p, n) ((p)->map[(n) >> 3] & (128 >> ((n) & 7)))
+#define BITSET(p, n) ((p)->map[(n) >> 3] |= (128 >> ((n) & 7)))
+#define BITCLEAR(p, n) ((p)->map[(n) >> 3] &= ~(128 >> ((n) & 7)))
+
+static void
+clear_bits (cairo_xlib_shm_mem_pool_t *pi, size_t first, size_t last)
+{
+ size_t i, n = last;
+ size_t first_full = (first + 7) & ~7;
+ size_t past_full = last & ~7;
+ size_t bytes;
+
+ if (n > first_full)
+ n = first_full;
+ for (i = first; i < n; i++)
+ BITCLEAR (pi, i);
+
+ if (past_full > first_full) {
+ bytes = past_full - first_full;
+ bytes = bytes >> 3;
+ memset (pi->map + (first_full >> 3), 0, bytes);
+ }
+
+ if (past_full < n)
+ past_full = n;
+ for (i = past_full; i < last; i++)
+ BITCLEAR (pi, i);
+}
+
+static void
+free_bits (cairo_xlib_shm_mem_pool_t *pi,
+ size_t start,
+ unsigned int bits,
+ cairo_bool_t clear)
+{
+ cairo_xlib_shm_mem_block_t *block;
+
+ if (clear)
+ clear_bits (pi, start, start + (1 << bits));
+
+ block = pi->blocks + start;
+ block->sync_request = 0;
+ block->bits = bits;
+ block->prev = pi->free_tail[bits];
+ block->next = NULL;
+ if (pi->free_tail[bits])
+ pi->free_tail[bits]->next = block;
+ else
+ pi->free[bits] = block;
+ pi->free_tail[bits] = block;
+
+ pi->free_bytes += 1 << (bits + pi->min_bits);
+ if (bits > pi->max_free_bits)
+ pi->max_free_bits = bits;
+}
+
+/* Add a chunk to the free list */
+static void
+free_blocks (cairo_xlib_shm_mem_pool_t *pi,
+ size_t first,
+ size_t last,
+ cairo_bool_t clear)
+{
+ size_t i;
+ size_t bits = 0;
+ size_t len = 1;
+
+ i = first;
+ while (i < last) {
+ /* To avoid cost quadratic in the number of different
+ * blocks produced from this chunk of store, we have to
+ * use the size of the previous block produced from this
+ * chunk as the starting point to work out the size of the
+ * next block we can produce. If you look at the binary
+ * representation of the starting points of the blocks
+ * produced, you can see that you first of all increase the
+ * size of the blocks produced up to some maximum as the
+ * address dealt with gets offsets added on which zap out
+ * low order bits, then decrease as the low order bits of the
+ * final block produced get added in. E.g. as you go from
+ * 001 to 0111 you generate blocks
+ * of size 001 at 001 taking you to 010
+ * of size 010 at 010 taking you to 100
+ * of size 010 at 100 taking you to 110
+ * of size 001 at 110 taking you to 111
+ * So the maximum total cost of the loops below this comment
+ * is one trip from the lowest blocksize to the highest and
+ * back again.
+ */
+ while (bits < pi->num_sizes - 1) {
+ size_t next_bits = bits + 1;
+ size_t next_len = len << 1;
+
+ if (i + next_bits > last) {
+ /* off end of chunk to be freed */
+ break;
+ }
+
+ if (i & (next_len - 1)) /* block would not be on boundary */
+ break;
+
+ bits = next_bits;
+ len = next_len;
+ }
+
+ do{
+ if (i + len > last) /* off end of chunk to be freed */
+ continue;
+
+ if (i & (len - 1)) /* block would not be on boundary */
+ continue;
+
+ /* OK */
+ break;
+
+ bits--;
+ len >>=1;
+ } while (len > 0);
+
+ if (len == 0)
+ break;
+
+ free_bits (pi, i, bits, clear);
+ i += len;
+ }
+}
+
+static cairo_status_t
+_cairo_xlib_shm_mem_pool_init (cairo_xlib_shm_mem_pool_t *pi,
+ void *base, size_t bytes,
+ unsigned int min_bits, unsigned int num_sizes)
+{
+ size_t setBits;
+
+ assert ((((unsigned long) base) & ((1 << min_bits) - 1)) == 0);
+ assert (num_sizes < ARRAY_LENGTH (pi->free));
+
+ pi->base = base;
+ pi->free_bytes = 0;
+ pi->max_bytes = bytes;
+ pi->max_free_bits = 0;
+
+ setBits = bytes >> min_bits;
+ pi->blocks = calloc (setBits, sizeof (cairo_xlib_shm_mem_block_t));
+ if (pi->blocks == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pi->nBlocks = setBits;
+ pi->min_bits = min_bits;
+ pi->num_sizes = num_sizes;
+ memset (pi->free, 0, sizeof (pi->free));
+ memset (pi->free_tail, 0, sizeof (pi->free_tail));
+
+ pi->map = malloc ((setBits + 7) >> 3);
+ if (pi->map == NULL) {
+ free (pi->blocks);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ memset (pi->map, -1, (setBits + 7) >> 3);
+ clear_bits (pi, 0, setBits);
+
+ /* Now add all blocks to the free list */
+ free_blocks (pi, 0, setBits, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_xlib_display_shm_mem_pool_fini (cairo_xlib_shm_mem_pool_t *pool)
+{
+ free (pool->map);
+ free (pool->blocks);
+}
+
+static cairo_xlib_shm_mem_block_t *
+get_buddy (cairo_xlib_shm_mem_pool_t *pi,
+ size_t offset,
+ unsigned int bits,
+ unsigned long processed)
+{
+ cairo_xlib_shm_mem_block_t *block;
+
+ assert (offset + (1 << bits) <= pi->nBlocks);
+
+ if (BITTEST (pi, offset + (1 << bits) - 1))
+ return NULL; /* buddy is allocated */
+
+ block = pi->blocks + offset;
+ if (block->bits != bits)
+ return NULL; /* buddy is partially allocated */
+ if (block->sync_request > processed)
+ return NULL; /* buddy is still in use */
+
+ return block;
+}
+
+static void
+merge_buddies (cairo_xlib_shm_mem_pool_t *pi,
+ cairo_xlib_shm_mem_block_t *block,
+ unsigned int max_bits,
+ unsigned long sync_request,
+ unsigned long processed)
+{
+ size_t block_offset = block_offset = block - pi->blocks;
+ unsigned int bits = block->bits;
+ cairo_xlib_shm_mem_block_t *other;
+
+ if (sync_request < processed) {
+ while (bits < max_bits - 1) {
+ /* while you can, merge two blocks and get a legal block size */
+ size_t buddy_offset = block_offset ^ (1 << bits);
+
+ block = get_buddy (pi, buddy_offset, bits, processed);
+ if (block == NULL)
+ break;
+
+ /* remove buddy from free lists */
+ if (block->prev != NULL) {
+ block->prev->next = block->next;
+ } else {
+ assert (pi->free[bits] == block);
+ pi->free[bits] = block->next;
+ }
+ if (block->next != NULL) {
+ block->next->prev = block->prev;
+ } else {
+ assert (pi->free_tail[bits] == block);
+ pi->free_tail[bits] = block->prev;
+ }
+
+ if (buddy_offset < block_offset) {
+ /* Merged block starts at buddy */
+ if (block->sync_request > sync_request)
+ sync_request = block->sync_request;
+ block_offset = buddy_offset;
+ }
+
+ bits++;
+ }
+ }
+
+ block = pi->blocks + block_offset;
+ block->bits = bits;
+ block->sync_request = sync_request;
+
+ /* add to free list (sorted by sync_request) */
+ for (other = pi->free_tail[bits]; other != NULL; other = other->prev) {
+ if (sync_request > other->sync_request)
+ break;
+ }
+ block->next = NULL;
+ block->prev = NULL;
+ if (other != NULL) {
+ block->next = other;
+ block->prev = other->prev;
+ if (other->prev != NULL)
+ other->prev->next = block;
+ other->prev = block;
+ }
+ if (block->prev == NULL) {
+ block->next = pi->free[bits];
+ if (pi->free[bits] != NULL)
+ pi->free[bits]->prev = block;
+ pi->free[bits] = block;
+ }
+ if (block->next == NULL) {
+ block->prev = pi->free_tail[bits];
+ if (pi->free_tail[bits] != NULL)
+ pi->free_tail[bits]->next = block;
+ pi->free_tail[bits] = block;
+ }
+
+ if (bits > pi->max_free_bits)
+ pi->max_free_bits = bits;
+}
+
+/* attempt to merge all available buddies up to a particular size */
+static unsigned int
+merge_bits (cairo_xlib_shm_mem_pool_t *pi,
+ unsigned int max_bits,
+ unsigned long processed)
+{
+ unsigned int bits;
+ cairo_xlib_shm_mem_block_t *block, *buddy, *prev;
+
+ for (bits = 0; bits < max_bits - 1; bits++) {
+ for (block = pi->free_tail[bits]; block != NULL; block = prev) {
+ size_t buddy_offset = (block - pi->blocks) ^ (1 << bits);
+
+ if (block->sync_request > processed)
+ break;
+
+ prev = block->prev;
+ buddy = get_buddy (pi, buddy_offset, bits, processed);
+ if (buddy == NULL)
+ continue;
+
+ if (buddy == prev)
+ prev = buddy->prev;
+
+ /* remove block from free lists */
+ if (block->prev != NULL) {
+ block->prev->next = block->next;
+ } else {
+ assert (pi->free[bits] == block);
+ pi->free[bits] = block->next;
+ }
+ if (block->next != NULL) {
+ block->next->prev = block->prev;
+ } else {
+ assert (pi->free_tail[bits] == block);
+ pi->free_tail[bits] = block->prev;
+ }
+
+ merge_buddies (pi, block, max_bits, block->sync_request, -1U);
+ }
+ }
+
+ return pi->max_free_bits;
+}
+
+
+/* find store for 1 << bits blocks */
+static void *
+buddy_malloc (cairo_xlib_shm_mem_pool_t *pi,
+ unsigned int bits,
+ unsigned long *sync_request)
+{
+ unsigned int b;
+ size_t offset;
+ size_t past;
+ cairo_xlib_shm_mem_block_t *block;
+ unsigned long processed = *sync_request;
+ unsigned long min_sync_request = -1UL;
+
+ if (bits > pi->max_free_bits &&
+ bits > merge_bits (pi, bits, processed))
+ return NULL;
+
+ /* Find a list with blocks big enough on it */
+ block = NULL;
+ for (b = bits; b <= pi->max_free_bits; b++) {
+ cairo_xlib_shm_mem_block_t *bb = pi->free[b];
+ if (bb != NULL) {
+ if (bb->sync_request < min_sync_request) {
+ block = bb;
+ min_sync_request = bb->sync_request;
+ if (min_sync_request <= processed)
+ break;
+ }
+ }
+ }
+ assert (block != NULL);
+
+ if (block->sync_request > processed)
+ return NULL;
+
+ b = block->bits;
+ pi->free[b] = block->next;
+ if (pi->free[b] == NULL)
+ pi->free_tail[b] = NULL;
+ else
+ pi->free[b]->prev = NULL;
+
+ while (pi->free[pi->max_free_bits] == NULL) {
+ if (--pi->max_free_bits == 0)
+ break;
+ }
+
+ /* Mark end of allocated area */
+ offset = block - pi->blocks;
+ past = offset + (1 << bits);
+ BITSET (pi, past - 1);
+ block->bits = bits;
+
+ /* If we used a larger free block than we needed, free the rest */
+ pi->free_bytes -= 1 << (b + pi->min_bits);
+ free_blocks (pi, past, offset + (1 << b), 0);
+
+ *sync_request = min_sync_request;
+ return pi->base + ((block - pi->blocks) << pi->min_bits);
+}
+
+static void *
+_cairo_xlib_shm_mem_pool_malloc (cairo_xlib_shm_mem_pool_t *pi,
+ size_t bytes,
+ unsigned long *sync_request)
+{
+ unsigned int bits;
+ size_t size;
+
+ size = 1 << pi->min_bits;
+ for (bits = 0; size < bytes; bits++)
+ size <<= 1;
+ if (bits >= pi->num_sizes)
+ return NULL;
+
+ return buddy_malloc (pi, bits, sync_request);
+}
+
+static void
+_cairo_xlib_shm_mem_pool_free (cairo_xlib_shm_mem_pool_t *pi,
+ char *storage,
+ unsigned long sync_request,
+ unsigned long processed)
+{
+ size_t block_offset;
+ cairo_xlib_shm_mem_block_t *block;
+
+ block_offset = (storage - pi->base) >> pi->min_bits;
+ block = pi->blocks + block_offset;
+
+ BITCLEAR (pi, block_offset + ((1 << block->bits) - 1));
+ pi->free_bytes += 1 << (block->bits + pi->min_bits);
+
+ merge_buddies (pi, block, pi->num_sizes, sync_request, processed);
+}
+
+cairo_int_status_t
+_cairo_xlib_display_allocate_shm_info (cairo_xlib_display_t *display,
+ size_t size,
+ cairo_bool_t needs_sync,
+ cairo_xlib_shm_info_t **shm_info_out)
+{
+ cairo_xlib_shm_info_t *shm_info;
+ Display *dpy = display->display;
+ Status success;
+ cairo_xlib_shm_mem_pool_t *pool, *next;
+ size_t bytes, maxbits = 16, minbits = 8;
+ void *mem = NULL;
+ unsigned long processed = LastKnownRequestProcessed (dpy);
+ unsigned long sync_request = needs_sync ? processed : -1UL;
+ cairo_status_t status;
+
+ assert (display->use_shm);
+
+ CAIRO_MUTEX_LOCK (display->mutex);
+ for (pool = display->shm_pools; pool != NULL; pool = next) {
+ next = pool->next;
+ if (pool->free_bytes > size) {
+ mem = _cairo_xlib_shm_mem_pool_malloc (pool, size, &sync_request);
+ if (mem != NULL)
+ break;
+ }
+ /* scan for old, unused pools */
+ if (pool->free_bytes == pool->max_bytes &&
+ pool->attached < processed)
+ {
+ _cairo_xlib_display_shm_mem_pool_destroy (display, pool);
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+
+ if (pool == NULL) {
+ pool = malloc (sizeof (cairo_xlib_shm_mem_pool_t));
+ if (pool == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ bytes = 1 << maxbits;
+ while (bytes <= size)
+ bytes <<= 1, maxbits++;
+ bytes <<= 3;
+
+ pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+ if (pool->shm.shmid == -1) {
+ int err = errno;
+ if (! (err == EINVAL || err == ENOMEM))
+ display->use_shm = FALSE;
+ free (pool);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ pool->shm.readOnly = FALSE;
+ pool->shm.shmaddr = shmat (pool->shm.shmid, NULL, 0);
+ if (pool->shm.shmaddr == (char *) -1) {
+ shmctl (pool->shm.shmid, IPC_RMID, NULL);
+ free (pool);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ pool->attached = NextRequest (dpy);
+ success = XShmAttach (dpy, &pool->shm);
+ shmctl (pool->shm.shmid, IPC_RMID, NULL);
+
+ if (! success) {
+ shmdt (pool->shm.shmaddr);
+ free (pool);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ status = _cairo_xlib_shm_mem_pool_init (pool,
+ pool->shm.shmaddr, bytes,
+ minbits,
+ maxbits - minbits + 1);
+ if (status) {
+ XShmDetach (dpy, &pool->shm);
+ shmdt (pool->shm.shmaddr);
+ free (pool);
+ return status;
+ }
+
+ CAIRO_MUTEX_LOCK (display->mutex);
+ pool->next = display->shm_pools;
+ display->shm_pools = pool;
+
+ mem = _cairo_xlib_shm_mem_pool_malloc (pool, size, &sync_request);
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+
+ assert (mem != NULL);
+ }
+
+ CAIRO_MUTEX_LOCK (display->mutex);
+ shm_info = _cairo_freelist_alloc (&display->shm_info_freelist);
+ if (shm_info == NULL) {
+ _cairo_xlib_shm_mem_pool_free (pool, mem, sync_request, processed);
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ shm_info->display = _cairo_xlib_display_reference (display);
+ shm_info->pool = pool;
+ shm_info->shm = pool->shm;
+ shm_info->mem = mem;
+ shm_info->last_read = 0;
+ shm_info->last_write = 0;
+
+ if (processed < sync_request) {
+ for (pool = display->shm_pools; pool != NULL; pool = pool->next)
+ merge_bits (pool, pool->num_sizes, -1U);
+
+ /* XXX force the completion of any outstanding requests */
+ XSync (dpy, False);
+ processed = LastKnownRequestProcessed (dpy);
+ }
+
+ /* scan for old, unused pools */
+ for (pool = display->shm_pools; pool != NULL; pool = next) {
+ next = pool->next;
+ if (pool->free_bytes == pool->max_bytes &&
+ pool->attached < processed)
+ {
+ _cairo_xlib_display_shm_mem_pool_destroy (display, pool);
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+
+ /* XXX cairo_image_surface_create() implies that the data should be zeroed,
+ * but does anyone actually rely on that? Cairo itself doesn't. */
+ memset (mem, 0, size);
+
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xlib_shm_info_destroy (cairo_xlib_shm_info_t *shm_info)
+{
+ cairo_xlib_display_t *display = shm_info->display;
+ cairo_xlib_shm_mem_pool_t *pool, *next;
+ unsigned long sync_request, processed;
+
+ sync_request = shm_info->last_read;
+ if (shm_info->last_write > sync_request)
+ sync_request = shm_info->last_write;
+ processed = LastKnownRequestProcessed (display->display);
+
+ CAIRO_MUTEX_LOCK (display->mutex);
+ _cairo_xlib_shm_mem_pool_free (shm_info->pool,
+ shm_info->mem,
+ sync_request,
+ processed);
+ _cairo_freelist_free (&display->shm_info_freelist, shm_info);
+
+ /* scan for old, unused pools - hold at least one in reserve */
+ for (pool = display->shm_pools; pool->next != NULL; pool = next) {
+ next = pool->next;
+ if (pool->free_bytes == pool->max_bytes &&
+ pool->attached < processed)
+ {
+ _cairo_xlib_display_shm_mem_pool_destroy (display, pool);
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+
+ _cairo_xlib_display_destroy (display);
+}
+
+static void
+_cairo_xlib_display_shm_mem_pool_destroy (cairo_xlib_display_t *display,
+ cairo_xlib_shm_mem_pool_t *pool)
+{
+ cairo_xlib_shm_mem_pool_t **prev, *p;
+
+ if (! display->closing) {
+ Display *dpy = display->display;
+
+ /* can't call shmdt until XShmAttach has been processed */
+ if (LastKnownRequestProcessed (dpy) < pool->attached)
+ return;
+
+ XShmDetach (dpy, &pool->shm);
+ }
+
+ for (prev = &display->shm_pools; (p = *prev); prev = &p->next) {
+ if (p == pool) {
+ *prev = p->next;
+ break;
+ }
+ }
+ assert (p != NULL);
+
+ shmdt (pool->shm.shmaddr);
+
+ _cairo_xlib_display_shm_mem_pool_fini (pool);
+ free (pool);
+}
+#else
+static void
+_cairo_xlib_display_shm_mem_pool_destroy (cairo_xlib_display_t *display,
+ cairo_xlib_shm_mem_pool_t *pool)
+{
+}
+#endif
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 61ce889..b78bc5d 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -41,6 +41,10 @@
#include "cairo-mutex-private.h"
#include "cairo-reference-count-private.h"
+#ifdef CAIRO_HAS_XLIB_XSHM
+#include <X11/extensions/XShm.h>
+#endif
+
typedef struct _cairo_xlib_display cairo_xlib_display_t;
typedef struct _cairo_xlib_hook cairo_xlib_hook_t;
typedef struct _cairo_xlib_job cairo_xlib_job_t;
@@ -53,6 +57,24 @@ struct _cairo_xlib_hook {
void *data;
};
+typedef struct _cairo_xlib_shm_mem_pool cairo_xlib_shm_mem_pool_t;
+typedef struct _cairo_xlib_shm_info cairo_xlib_shm_info_t;
+
+struct _cairo_xlib_shm_info {
+ cairo_xlib_display_t *display;
+#ifdef CAIRO_HAS_XLIB_XSHM
+ XShmSegmentInfo shm;
+#endif
+ void *mem;
+ unsigned long last_read;
+ unsigned long last_write;
+ cairo_xlib_shm_mem_pool_t *pool;
+};
+
+cairo_private void
+_cairo_xlib_shm_destroy (cairo_xlib_display_t *display,
+ cairo_xlib_shm_info_t *shm_info);
+
struct _cairo_xlib_display {
cairo_xlib_display_t *next;
cairo_reference_count_t ref_count;
@@ -66,9 +88,15 @@ struct _cairo_xlib_display {
cairo_xlib_job_t *workqueue;
cairo_freelist_t wq_freelist;
+ cairo_xlib_shm_mem_pool_t *shm_pools;
+ cairo_freelist_t shm_info_freelist;
+
cairo_freelist_t hook_freelist;
cairo_xlib_hook_t *close_display_hooks;
unsigned int buggy_repeat :1;
+ unsigned int use_shm :1;
+ unsigned int have_shm_pixmaps :1;
+ unsigned int closing :1;
unsigned int closed :1;
};
@@ -108,6 +136,7 @@ _cairo_xlib_display_get (Display *display);
cairo_private cairo_xlib_display_t *
_cairo_xlib_display_reference (cairo_xlib_display_t *info);
+
cairo_private void
_cairo_xlib_display_destroy (cairo_xlib_display_t *info);
@@ -132,6 +161,15 @@ cairo_private XRenderPictFormat *
_cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
cairo_format_t format);
+cairo_private cairo_int_status_t
+_cairo_xlib_display_allocate_shm_info (cairo_xlib_display_t *display,
+ size_t size,
+ cairo_bool_t needs_sync,
+ cairo_xlib_shm_info_t **shm_info_out);
+
+cairo_private void
+_cairo_xlib_shm_info_destroy (cairo_xlib_shm_info_t *shm_info);
+
cairo_private cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *display, Screen *screen);
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index d5df19c..0a4b351 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -55,6 +55,9 @@ struct _cairo_xlib_surface {
int use_pixmap;
+ cairo_bool_t use_shm;
+ cairo_xlib_shm_info_t *shm_info;
+
int render_major;
int render_minor;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 4877e7e..e6a08e0 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -34,6 +34,7 @@
* Contributor(s):
* Carl D. Worth <cworth at cworth.org>
* Behdad Esfahbod <behdad at behdad.org>
+ * Chris Wilson <chris at chris-wilson.co.uk>
*/
#include "cairoint.h"
@@ -45,6 +46,31 @@
#include <X11/Xutil.h> /* for XDestroyImage */
+#ifdef CAIRO_HAS_XLIB_XSHM
+#include <X11/extensions/XShm.h>
+
+/* if an image has too few pixels, skip the XShm paths */
+#define SMALL_IMAGE 1500 /* bytes */
+
+static cairo_int_status_t
+_cairo_xlib_surface_create_shm_image (cairo_xlib_surface_t *target,
+ int width,
+ int height,
+ cairo_image_surface_t **image_out,
+ cairo_xlib_shm_info_t **shm_info_out);
+
+static const cairo_user_data_key_t _cairo_xlib_shm_info_key;
+
+static void
+_cairo_xlib_shm_detach (void *data);
+#endif
+
+static void
+_cairo_xlib_surface_shm_mark_read (cairo_xlib_surface_t *surface);
+
+static void
+_cairo_xlib_surface_shm_mark_write (cairo_xlib_surface_t *surface);
+
/* Xlib doesn't define a typedef, so define one ourselves */
typedef int (*cairo_xlib_error_func_t) (Display *display,
XErrorEvent *event);
@@ -545,6 +571,78 @@ static const int8_t dither_pattern[4][4] = {
};
#undef X
+static void
+_ximage_init_for_image_surface (XImage *ximage,
+ cairo_image_surface_t *image,
+ void *obdata)
+{
+ int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
+ cairo_format_masks_t image_masks;
+ int ret;
+
+ _pixman_format_to_masks (image->pixman_format, &image_masks);
+
+ ximage->width = image->width;
+ ximage->height = image->height;
+ ximage->format = ZPixmap;
+ ximage->data = (char *) image->data;
+ ximage->obdata = obdata;
+ ximage->byte_order = native_byte_order;
+ ximage->bitmap_unit = 32; /* always for libpixman */
+ ximage->bitmap_bit_order = native_byte_order;
+ ximage->bitmap_pad = 32; /* always for libpixman */
+ ximage->depth = image->depth;
+ ximage->bytes_per_line = image->stride;
+ ximage->bits_per_pixel = image_masks.bpp;
+ ximage->red_mask = image_masks.red_mask;
+ ximage->green_mask = image_masks.green_mask;
+ ximage->blue_mask = image_masks.blue_mask;
+ ximage->xoffset = 0;
+
+ ret = XInitImage (ximage);
+ assert (ret != 0);
+}
+
+#ifdef CAIRO_HAS_XLIB_XSHM
+static cairo_int_status_t
+get_shm_image_surface (cairo_xlib_surface_t *target,
+ int x1, int y1, int x2, int y2,
+ cairo_image_surface_t **image_out)
+{
+ XImage ximage;
+ cairo_int_status_t status;
+ cairo_image_surface_t *image;
+ cairo_xlib_shm_info_t *shm_info;
+ cairo_xlib_error_func_t old_handler;
+ Status success;
+
+ status = _cairo_xlib_surface_create_shm_image (target,
+ x2 - x1, y2 - y1,
+ &image,
+ &shm_info);
+ if (status)
+ return status;
+
+ _ximage_init_for_image_surface (&ximage, image, &shm_info->shm);
+
+ old_handler = XSetErrorHandler (_noop_error_handler);
+
+ success = XShmGetImage (target->dpy, target->drawable,
+ &ximage, x1, y1, AllPlanes);
+
+ XSetErrorHandler (old_handler);
+
+ if (! success) {
+ /* most probably a BadMatch from an offscreen window... */
+ cairo_surface_destroy (&image->base);
+ target->use_pixmap = CAIRO_ASSUME_PIXMAP;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ *image_out = image;
+ return CAIRO_STATUS_SUCCESS;
+}
+#endif
static cairo_status_t
_get_image_surface (cairo_xlib_surface_t *surface,
@@ -594,10 +692,17 @@ _get_image_surface (cairo_xlib_surface_t *surface,
image_rect->height = y2 - y1;
}
- /* XXX: This should try to use the XShm extension if available */
+#ifdef CAIRO_HAS_XLIB_XSHM
+ if (surface->use_pixmap == 0) {
+ cairo_status_t status;
- if (surface->use_pixmap == 0)
- {
+ status = get_shm_image_surface (surface, x1, y1, x2, y2, image_out);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+#endif
+
+ if (surface->use_pixmap == 0) {
cairo_xlib_error_func_t old_handler;
old_handler = XSetErrorHandler (_noop_error_handler);
@@ -613,18 +718,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
/* If we get an error, the surface must have been a window,
* so retry with the safe code path.
*/
- if (!ximage)
+ if (ximage == NULL)
surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
- }
- else
- {
+ } else {
surface->use_pixmap--;
ximage = NULL;
}
- if (!ximage)
- {
-
+ if (ximage == NULL) {
/* XGetImage from a window is dangerous because it can
* produce errors if the window is unmapped or partially
* outside the screen. We could check for errors and
@@ -665,7 +766,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
xlib_masks.blue_mask = surface->b_mask;
status = _pixman_format_from_masks (&xlib_masks, &pixman_format);
- if (xlib_masks.bpp >= 24 &&status == CAIRO_STATUS_SUCCESS) {
+ if (xlib_masks.bpp >= 24 && status == CAIRO_STATUS_SUCCESS) {
image = (cairo_image_surface_t*)
_cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
pixman_format,
@@ -889,6 +990,53 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
cairo_status_t status;
cairo_bool_t own_data;
+#ifdef CAIRO_HAS_XLIB_XSHM
+ cairo_xlib_shm_info_t *shm_info;
+#endif
+
+ /* fix up image size to fit within bounds (required for XShm) */
+ if (dst_x < 0) {
+ src_x += dst_x;
+ width += dst_x;
+ dst_x = 0;
+ }
+ if (dst_x > surface->width)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src_x < 0) {
+ width += src_x;
+ src_x = 0;
+ }
+ if (src_x > image->width)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src_x + width > image->width)
+ width = image->width - src_x;
+ if (dst_x + width > surface->width)
+ width = surface->width - dst_x;
+
+ if (dst_y < 0) {
+ src_y += dst_y;
+ height += dst_y;
+ dst_y = 0;
+ }
+ if (dst_y > surface->height)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src_y < 0) {
+ height += src_y;
+ src_y = 0;
+ }
+ if (src_y > image->height)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src_y + height > image->height)
+ height = image->height - src_y;
+ if (dst_y + height > surface->height)
+ height = surface->height - dst_y;
+
+ if (width == 0 || height == 0)
+ return CAIRO_STATUS_SUCCESS;
_pixman_format_to_masks (image->pixman_format, &image_masks);
@@ -913,7 +1061,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
ximage.bits_per_pixel = image_masks.bpp;
ximage.bytes_per_line = image->stride;
- ximage.data = (char *)image->data;
+ ximage.data = (char *) image->data;
own_data = FALSE;
ret = XInitImage (&ximage);
@@ -1020,9 +1168,24 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
if (status)
goto BAIL;
- XPutImage(surface->dpy, surface->drawable, surface->gc,
- &ximage, src_x, src_y, dst_x, dst_y,
- width, height);
+#ifdef CAIRO_HAS_XLIB_XSHM
+ shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
+ &_cairo_xlib_shm_info_key);
+ if (shm_info != NULL && ximage.data == (char *) image->data) {
+ ximage.obdata = (char *) &shm_info->shm;
+ shm_info->last_read = NextRequest (surface->dpy);
+ XShmPutImage (surface->dpy, surface->drawable, surface->gc,
+ &ximage, src_x, src_y, dst_x, dst_y,
+ width, height,
+ False);
+ } else
+ /* XXX upload via XShm? */
+#endif
+ {
+ XPutImage (surface->dpy, surface->drawable, surface->gc,
+ &ximage, src_x, src_y, dst_x, dst_y,
+ width, height);
+ }
BAIL:
if (own_data)
@@ -1159,7 +1322,6 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface,
}
*clone_out = &clone->base;
-
return CAIRO_STATUS_SUCCESS;
}
@@ -1614,6 +1776,24 @@ _render_operator (cairo_operator_t op)
}
}
+static void
+_cairo_xlib_surface_shm_mark_write (cairo_xlib_surface_t *surface)
+{
+ if (surface->shm_info == NULL)
+ return;
+
+ surface->shm_info->last_write = NextRequest (surface->dpy) - 1;
+}
+
+static void
+_cairo_xlib_surface_shm_mark_read (cairo_xlib_surface_t *surface)
+{
+ if (surface->shm_info == NULL)
+ return;
+
+ surface->shm_info->last_read = NextRequest (surface->dpy) - 1;
+}
+
static cairo_int_status_t
_cairo_xlib_surface_composite (cairo_operator_t op,
cairo_pattern_t *src_pattern,
@@ -1755,6 +1935,10 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
default:
ASSERT_NOT_REACHED;
}
+ _cairo_xlib_surface_shm_mark_write (dst);
+ _cairo_xlib_surface_shm_mark_read (src);
+ if (mask)
+ _cairo_xlib_surface_shm_mark_read (mask);
if (!_cairo_operator_bounded_by_source (op))
status = _cairo_surface_composite_fixup_unbounded (&dst->base,
@@ -1875,6 +2059,7 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
_render_operator (op),
surface->dst_picture,
&render_color, xrects, num_rects);
+ _cairo_xlib_surface_shm_mark_write (surface);
if (xrects != static_xrects)
free (xrects);
@@ -2127,6 +2312,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
if (xtraps != xtraps_stack)
free(xtraps);
}
+ _cairo_xlib_surface_shm_mark_write (dst);
+ _cairo_xlib_surface_shm_mark_read (src);
BAIL:
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
@@ -2256,6 +2443,18 @@ _cairo_xlib_surface_get_font_options (void *abstract_surface,
*options = surface->screen_info->font_options;
}
+static cairo_status_t
+_cairo_xlib_surface_mark_dirty_rectangle (void *abstract_surface,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ _cairo_xlib_surface_shm_mark_write (abstract_surface);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static void
_cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
@@ -2304,6 +2503,99 @@ _cairo_xlib_surface_reset (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
+#ifdef CAIRO_HAS_XLIB_XSHM
+static void
+_cairo_xlib_shm_detach (void *data)
+{
+ cairo_xlib_shm_info_t *shm_info = data;
+ cairo_xlib_display_t *display = shm_info->display;
+
+ _cairo_xlib_remove_close_display_hooks (display->display, shm_info);
+ _cairo_xlib_shm_info_destroy (shm_info);
+}
+
+static cairo_int_status_t
+_cairo_xlib_surface_create_shm_image (cairo_xlib_surface_t *target,
+ int width,
+ int height,
+ cairo_image_surface_t **image_out,
+ cairo_xlib_shm_info_t **shm_info_out)
+{
+ cairo_xlib_display_t *display = target->screen_info->display;
+ cairo_format_masks_t xlib_masks;
+ pixman_format_code_t pixman_format;
+ cairo_surface_t *image;
+ cairo_xlib_shm_info_t *shm_info;
+ cairo_status_t status;
+ size_t size, stride;
+
+ if (! target->use_shm)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (target->dpy == NULL || ! display->use_shm) {
+ target->use_shm = FALSE;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (target->depth > 16) {
+ xlib_masks.bpp = 32;
+ } else if (target->depth > 8) {
+ xlib_masks.bpp = 16;
+ } else if (target->depth > 1) {
+ xlib_masks.bpp = 8;
+ } else {
+ xlib_masks.bpp = 1;
+ }
+ xlib_masks.alpha_mask = target->a_mask;
+ xlib_masks.red_mask = target->r_mask;
+ xlib_masks.green_mask = target->g_mask;
+ xlib_masks.blue_mask = target->b_mask;
+
+ status = _pixman_format_from_masks (&xlib_masks, &pixman_format);
+ if (status) {
+ /* Cannot be represented by a pixman_format, ignore in future */
+ target->use_shm = FALSE;
+ return status;
+ }
+
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, xlib_masks.bpp);
+ size = stride * height;
+ if (size < SMALL_IMAGE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_xlib_display_allocate_shm_info (display,
+ size, FALSE,
+ &shm_info);
+ if (status)
+ return status;
+
+ image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ pixman_format,
+ width,
+ height,
+ stride);
+ status = image->status;
+ if (status) {
+ _cairo_xlib_shm_detach (shm_info);
+ return status;
+ }
+
+ status = _cairo_user_data_array_set_data (&image->user_data,
+ &_cairo_xlib_shm_info_key,
+ shm_info,
+ _cairo_xlib_shm_detach);
+ if (status) {
+ cairo_surface_destroy (image);
+ _cairo_xlib_shm_detach (shm_info);
+ return status;
+ }
+
+ *image_out = (cairo_image_surface_t *) image;
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+#endif
+
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
CAIRO_SURFACE_TYPE_XLIB,
_cairo_xlib_surface_create_similar,
@@ -2324,7 +2616,7 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
NULL, /* old_show_glyphs */
_cairo_xlib_surface_get_font_options,
NULL, /* flush */
- NULL, /* mark_dirty_rectangle */
+ _cairo_xlib_surface_mark_dirty_rectangle,
_cairo_xlib_surface_scaled_font_fini,
_cairo_xlib_surface_scaled_glyph_fini,
@@ -2473,6 +2765,9 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->width = width;
surface->height = height;
+ surface->use_shm = screen_info->display->use_shm;
+ surface->shm_info = NULL;
+
surface->buggy_repeat = screen_info->display->buggy_repeat;
if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
/* so we can use the XTile fallback */
@@ -2492,6 +2787,7 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->have_clip_rects = FALSE;
surface->clip_rects = surface->embedded_clip_rects;
surface->num_clip_rects = 0;
+ surface->clip_dirty = 0;
/*
* Compute the pixel format masks from either a XrenderFormat or
@@ -3886,6 +4182,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
src,
&attributes,
remaining_glyphs);
+ _cairo_xlib_surface_shm_mark_write (dst);
+ _cairo_xlib_surface_shm_mark_read (src);
BAIL1:
if (src)
--
1.5.4.3
--=-vy8YbLXeHNclDGl7h0NH--
More information about the cairo
mailing list