summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-08-13 01:34:12 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-08-17 13:58:09 +0100
commit0bfd2acd35547fc2bd0de99cc67d153f0170697d (patch)
treec59ffaad038cb57115c68505b36aa6bc15d88fa7
parent140fafed89508c4685f3a464c9dbe8df769f2411 (diff)
xlib: Implement SHM fallbacks and fast upload paths
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--configure.ac4
-rw-r--r--src/Makefile.sources3
-rw-r--r--src/cairo-cogl-surface.c8
-rw-r--r--src/cairo-damage.c1
-rw-r--r--src/cairo-directfb-surface.c6
-rw-r--r--src/cairo-gl-surface.c9
-rw-r--r--src/cairo-image-compositor.c26
-rw-r--r--src/cairo-image-surface-inline.h2
-rw-r--r--src/cairo-image-surface-private.h6
-rw-r--r--src/cairo-image-surface.c2
-rw-r--r--src/cairo-mempool-private.h83
-rw-r--r--src/cairo-mempool.c359
-rw-r--r--src/cairo-quartz-image-surface.c6
-rw-r--r--src/cairo-scaled-font.c2
-rw-r--r--src/cairo-surface-backend-private.h3
-rw-r--r--src/cairo-surface-inline.h4
-rw-r--r--src/cairo-surface-observer.c6
-rw-r--r--src/cairo-surface-private.h3
-rw-r--r--src/cairo-surface-snapshot.c5
-rw-r--r--src/cairo-surface-subsurface.c6
-rw-r--r--src/cairo-surface.c101
-rw-r--r--src/cairo-xcb-surface.c6
-rw-r--r--src/cairo-xlib-display.c9
-rw-r--r--src/cairo-xlib-fallback-compositor.c190
-rw-r--r--src/cairo-xlib-private.h59
-rw-r--r--src/cairo-xlib-render-compositor.c155
-rw-r--r--src/cairo-xlib-source.c231
-rw-r--r--src/cairo-xlib-surface-shm.c1119
-rw-r--r--src/cairo-xlib-surface.c286
-rw-r--r--src/cairo-xlib-xcb-surface.c5
-rw-r--r--src/cairoint.h2
-rw-r--r--src/drm/cairo-drm-gallium-surface.c6
-rw-r--r--src/drm/cairo-drm-i915-private.h2
-rw-r--r--src/drm/cairo-drm-i915-surface.c8
-rw-r--r--src/drm/cairo-drm-i965-shader.c4
-rw-r--r--src/drm/cairo-drm-i965-surface.c5
-rw-r--r--src/drm/cairo-drm-intel-private.h3
-rw-r--r--src/drm/cairo-drm-intel-surface.c5
-rw-r--r--src/drm/cairo-drm-radeon-surface.c6
-rw-r--r--src/win32/cairo-win32-display-surface.c5
-rw-r--r--src/win32/cairo-win32-gdi-compositor.c4
41 files changed, 2517 insertions, 238 deletions
diff --git a/configure.ac b/configure.ac
index 0067bfc9..3d668b68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,7 +63,7 @@ AM_CONDITIONAL(CAIRO_HAS_DLSYM, test "x$have_dlsym" = "xyes")
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
- xlib_REQUIRES="x11"
+ xlib_REQUIRES="x11 xext"
PKG_CHECK_MODULES(xlib, $xlib_REQUIRES, ,
[AC_MSG_RESULT(no)
xlib_REQUIRES=""
@@ -71,7 +71,7 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
if test "x$no_x" = xyes; then
use_xlib="no (requires X development libraries)"
else
- xlib_NONPKGCONFIG_LIBS="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS"
+ xlib_NONPKGCONFIG_LIBS="$X_PRE_LIBS $X_LIBS -lX11 -lXext $X_EXTRA_LIBS"
xlib_NONPKGCONFIG_CFLAGS=$X_CFLAGS
fi])
])
diff --git a/src/Makefile.sources b/src/Makefile.sources
index f487fc11..9a336779 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -87,6 +87,7 @@ cairo_private = \
cairo-list-inline.h \
cairo-list-private.h \
cairo-malloc-private.h \
+ cairo-mempool-private.h \
cairo-mutex-impl-private.h \
cairo-mutex-list-private.h \
cairo-mutex-private.h \
@@ -178,6 +179,7 @@ cairo_sources = \
cairo-matrix.c \
cairo-mask-compositor.c \
cairo-mesh-pattern-rasterizer.c \
+ cairo-mempool.c \
cairo-misc.c \
cairo-mono-scan-converter.c \
cairo-mutex.c \
@@ -311,6 +313,7 @@ cairo_xlib_sources = \
cairo-xlib-screen.c \
cairo-xlib-source.c \
cairo-xlib-surface.c \
+ cairo-xlib-surface-shm.c \
cairo-xlib-visual.c \
cairo-xlib-xcb-surface.c \
$(NULL)
diff --git a/src/cairo-cogl-surface.c b/src/cairo-cogl-surface.c
index ed86acca..d192d75f 100644
--- a/src/cairo-cogl-surface.c
+++ b/src/cairo-cogl-surface.c
@@ -929,10 +929,14 @@ _cairo_cogl_journal_flush (cairo_cogl_surface_t *surface)
}
static cairo_status_t
-_cairo_cogl_surface_flush (void *abstract_surface)
+_cairo_cogl_surface_flush (void *abstract_surface,
+ unsigned flags)
{
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_cogl_journal_flush (surface);
return CAIRO_STATUS_SUCCESS;
@@ -1331,7 +1335,7 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t *reference_surface,
if (abstract_surface->device == reference_surface->base.device) {
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
- _cairo_cogl_surface_flush (surface);
+ _cairo_cogl_surface_flush (surface, 0);
return surface->texture ? cogl_object_ref (surface->texture) : NULL;
}
diff --git a/src/cairo-damage.c b/src/cairo-damage.c
index 61a58af0..1e06b264 100644
--- a/src/cairo-damage.c
+++ b/src/cairo-damage.c
@@ -95,7 +95,6 @@ _cairo_damage_add_boxes(cairo_damage_t *damage,
if (damage->status)
return damage;
-
damage->dirty += count;
n = count;
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 494ec079..16e367af 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -209,10 +209,14 @@ _cairo_dfb_surface_unmap_image (void *abstract_surface,
}
static cairo_status_t
-_cairo_dfb_surface_flush (void *abstract_surface)
+_cairo_dfb_surface_flush (void *abstract_surface,
+ unsigned flags)
{
cairo_dfb_surface_t *surface = abstract_surface;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->image.pixman_image) {
surface->dfb_surface->Unlock (surface->dfb_surface);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 8b63fd2f..c0ee79f8 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -52,7 +52,7 @@
static const cairo_surface_backend_t _cairo_gl_surface_backend;
static cairo_status_t
-_cairo_gl_surface_flush (void *abstract_surface);
+_cairo_gl_surface_flush (void *abstract_surface, unsigned flags);
static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
{
@@ -834,7 +834,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
- status = _cairo_gl_surface_flush (&dst->base);
+ status = _cairo_gl_surface_flush (&dst->base, 0);
if (unlikely (status))
goto FAIL;
@@ -1200,12 +1200,15 @@ _cairo_gl_surface_get_extents (void *abstract_surface,
}
static cairo_status_t
-_cairo_gl_surface_flush (void *abstract_surface)
+_cairo_gl_surface_flush (void *abstract_surface, unsigned flags)
{
cairo_gl_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_gl_context_t *ctx;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
status = _cairo_gl_context_acquire (surface->base.device, &ctx);
if (unlikely (status))
return status;
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index 1ec98386..768e3a50 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -750,6 +750,16 @@ composite_tristrip (void *_dst,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#if HAS_PIXMAN_GLYPHS
static pixman_glyph_cache_t *global_glyph_cache;
static inline pixman_glyph_cache_t *
@@ -777,16 +787,6 @@ _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
}
static cairo_int_status_t
-check_composite_glyphs (const cairo_composite_rectangles_t *extents,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int *num_glyphs)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-#if HAS_PIXMAN_GLYPHS
-static cairo_int_status_t
composite_glyphs (void *_dst,
cairo_operator_t op,
cairo_surface_t *_src,
@@ -896,6 +896,12 @@ out_unlock:
return status;
}
#else
+void
+_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph)
+{
+}
+
static cairo_int_status_t
composite_one_glyph (void *_dst,
cairo_operator_t op,
diff --git a/src/cairo-image-surface-inline.h b/src/cairo-image-surface-inline.h
index f6bed719..49591073 100644
--- a/src/cairo-image-surface-inline.h
+++ b/src/cairo-image-surface-inline.h
@@ -73,7 +73,7 @@ _cairo_image_surface_is_clone (cairo_image_surface_t *image)
static inline cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface)
{
- return surface->backend == &_cairo_image_surface_backend;
+ return surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE;
}
/**
diff --git a/src/cairo-image-surface-private.h b/src/cairo-image-surface-private.h
index 96601808..6a159d8a 100644
--- a/src/cairo-image-surface-private.h
+++ b/src/cairo-image-surface-private.h
@@ -151,6 +151,12 @@ _cairo_image_surface_init (cairo_image_surface_t *surface,
pixman_image_t *pixman_image,
pixman_format_code_t pixman_format);
+cairo_private cairo_surface_t *
+_cairo_image_surface_create_similar (void *abstract_other,
+ cairo_content_t content,
+ int width,
+ int height);
+
cairo_private cairo_image_surface_t *
_cairo_image_surface_map_to_image (void *abstract_other,
const cairo_rectangle_int_t *extents);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 23e6ca67..3fe6e433 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -723,7 +723,7 @@ _cairo_format_bits_per_pixel (cairo_format_t format)
}
}
-static cairo_surface_t *
+cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_other,
cairo_content_t content,
int width,
diff --git a/src/cairo-mempool-private.h b/src/cairo-mempool-private.h
new file mode 100644
index 00000000..4435a5aa
--- /dev/null
+++ b/src/cairo-mempool-private.h
@@ -0,0 +1,83 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributors(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_MEMPOOL_PRIVATE_H
+#define CAIRO_MEMPOOL_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-error-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_mempool cairo_mempool_t;
+
+struct _cairo_mempool {
+ char *base;
+ struct _cairo_memblock {
+ int bits;
+ cairo_list_t link;
+ } *blocks;
+ cairo_list_t free[32];
+ unsigned char *map;
+
+ unsigned int num_blocks;
+ int min_bits; /* Minimum block size is 1 << min_bits */
+ int num_sizes;
+ int max_free_bits;
+
+ size_t free_bytes;
+ size_t max_bytes;
+};
+
+cairo_private cairo_status_t
+_cairo_mempool_init (cairo_mempool_t *pool,
+ void *base,
+ size_t bytes,
+ int min_bits,
+ int num_sizes);
+
+cairo_private void *
+_cairo_mempool_alloc (cairo_mempool_t *pi, size_t bytes);
+
+cairo_private void
+_cairo_mempool_free (cairo_mempool_t *pi, void *storage);
+
+cairo_private void
+_cairo_mempool_fini (cairo_mempool_t *pool);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_MEMPOOL_PRIVATE_H */
diff --git a/src/cairo-mempool.c b/src/cairo-mempool.c
new file mode 100644
index 00000000..296b7393
--- /dev/null
+++ b/src/cairo-mempool.c
@@ -0,0 +1,359 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipoolent may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributors(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-mempool-private.h"
+#include "cairo-list-inline.h"
+
+/* a simple buddy allocator for memory pools
+ * XXX fragmentation? use Doug Lea's malloc?
+ */
+
+#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_mempool_t *pool, 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 (pool, i);
+
+ if (past_full > first_full) {
+ bytes = past_full - first_full;
+ bytes = bytes >> 3;
+ memset (pool->map + (first_full >> 3), 0, bytes);
+ }
+
+ if (past_full < n)
+ past_full = n;
+ for (i = past_full; i < last; i++)
+ BITCLEAR (pool, i);
+}
+
+static void
+free_bits (cairo_mempool_t *pool, size_t start, int bits, cairo_bool_t clear)
+{
+ struct _cairo_memblock *block;
+
+ if (clear)
+ clear_bits (pool, start, start + (1 << bits));
+
+ block = pool->blocks + start;
+ block->bits = bits;
+
+ cairo_list_add (&block->link, &pool->free[bits]);
+
+ pool->free_bytes += 1 << (bits + pool->min_bits);
+ if (bits > pool->max_free_bits)
+ pool->max_free_bits = bits;
+}
+
+/* Add a chunk to the free list */
+static void
+free_blocks (cairo_mempool_t *pool,
+ size_t first,
+ size_t last,
+ cairo_bool_t clear)
+{
+ size_t i, len;
+ int bits = 0;
+
+ for (i = first, len = 1; i < last; i += len) {
+ /* 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 < pool->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 */
+ (i & (len - 1)) == 0) /* block would not be on boundary */
+ break;
+
+ bits--; len >>=1;
+ } while (len);
+
+ if (len == 0)
+ break;
+
+ free_bits (pool, i, bits, clear);
+ }
+}
+
+static struct _cairo_memblock *
+get_buddy (cairo_mempool_t *pool, size_t offset, int bits)
+{
+ struct _cairo_memblock *block;
+
+ assert (offset + (1 << bits) <= pool->num_blocks);
+
+ if (BITTEST (pool, offset + (1 << bits) - 1))
+ return NULL; /* buddy is allocated */
+
+ block = pool->blocks + offset;
+ if (block->bits != bits)
+ return NULL; /* buddy is partially allocated */
+
+ return block;
+}
+
+static void
+merge_buddies (cairo_mempool_t *pool,
+ struct _cairo_memblock *block,
+ int max_bits)
+{
+ size_t block_offset = block - pool->blocks;
+ int bits = block->bits;
+
+ 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 (pool, buddy_offset, bits);
+ if (block == NULL)
+ break;
+
+ cairo_list_del (&block->link);
+
+ /* Merged block starts at buddy */
+ if (buddy_offset < block_offset)
+ block_offset = buddy_offset;
+
+ bits++;
+ }
+
+ block = pool->blocks + block_offset;
+ block->bits = bits;
+ cairo_list_add (&block->link, &pool->free[bits]);
+
+ if (bits > pool->max_free_bits)
+ pool->max_free_bits = bits;
+}
+
+/* attempt to merge all available buddies up to a particular size */
+static int
+merge_bits (cairo_mempool_t *pool, int max_bits)
+{
+ struct _cairo_memblock *block, *buddy, *next;
+ int bits;
+
+ for (bits = 0; bits < max_bits - 1; bits++) {
+ cairo_list_foreach_entry_safe (block, next,
+ struct _cairo_memblock,
+ &pool->free[bits],
+ link)
+ {
+ size_t buddy_offset = (block - pool->blocks) ^ (1 << bits);
+
+ buddy = get_buddy (pool, buddy_offset, bits);
+ if (buddy == NULL)
+ continue;
+
+ if (buddy == next) {
+ next = cairo_container_of (buddy->link.next,
+ struct _cairo_memblock,
+ link);
+ }
+
+ cairo_list_del (&block->link);
+ merge_buddies (pool, block, max_bits);
+ }
+ }
+
+ return pool->max_free_bits;
+}
+
+/* find store for 1 << bits blocks */
+static void *
+buddy_malloc (cairo_mempool_t *pool, int bits)
+{
+ size_t past, offset;
+ struct _cairo_memblock *block;
+ int b;
+
+ if (bits > pool->max_free_bits && bits > merge_bits (pool, bits))
+ return NULL;
+
+ /* Find a list with blocks big enough on it */
+ block = NULL;
+ for (b = bits; b <= pool->max_free_bits; b++) {
+ if (! cairo_list_is_empty (&pool->free[b])) {
+ block = cairo_list_first_entry (&pool->free[b],
+ struct _cairo_memblock,
+ link);
+ break;
+ }
+ }
+ assert (block != NULL);
+
+ cairo_list_del (&block->link);
+
+ while (cairo_list_is_empty (&pool->free[pool->max_free_bits])) {
+ if (--pool->max_free_bits == -1)
+ break;
+ }
+
+ /* Mark end of allocated area */
+ offset = block - pool->blocks;
+ past = offset + (1 << bits);
+ BITSET (pool, past - 1);
+ block->bits = bits;
+
+ /* If we used a larger free block than we needed, free the rest */
+ pool->free_bytes -= 1 << (b + pool->min_bits);
+ free_blocks (pool, past, offset + (1 << b), 0);
+
+ return pool->base + ((block - pool->blocks) << pool->min_bits);
+}
+
+cairo_status_t
+_cairo_mempool_init (cairo_mempool_t *pool,
+ void *base, size_t bytes,
+ int min_bits, int num_sizes)
+{
+ int num_blocks;
+ int i;
+
+ assert ((((unsigned long) base) & ((1 << min_bits) - 1)) == 0);
+ assert (num_sizes < ARRAY_LENGTH (pool->free));
+
+ pool->base = base;
+ pool->free_bytes = 0;
+ pool->max_bytes = bytes;
+ pool->max_free_bits = -1;
+
+ num_blocks = bytes >> min_bits;
+ pool->blocks = calloc (num_blocks, sizeof (struct _cairo_memblock));
+ if (pool->blocks == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pool->num_blocks = num_blocks;
+ pool->min_bits = min_bits;
+ pool->num_sizes = num_sizes;
+
+ for (i = 0; i < ARRAY_LENGTH (pool->free); i++)
+ cairo_list_init (&pool->free[i]);
+
+ pool->map = malloc ((num_blocks + 7) >> 3);
+ if (pool->map == NULL) {
+ free (pool->blocks);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ memset (pool->map, -1, (num_blocks + 7) >> 3);
+ clear_bits (pool, 0, num_blocks);
+
+ /* Now add all blocks to the free list */
+ free_blocks (pool, 0, num_blocks, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void *
+_cairo_mempool_alloc (cairo_mempool_t *pool, size_t bytes)
+{
+ size_t size;
+ int bits;
+
+ size = 1 << pool->min_bits;
+ for (bits = 0; size < bytes; bits++)
+ size <<= 1;
+ if (bits >= pool->num_sizes)
+ return NULL;
+
+ return buddy_malloc (pool, bits);
+}
+
+void
+_cairo_mempool_free (cairo_mempool_t *pool, void *storage)
+{
+ size_t block_offset;
+ struct _cairo_memblock *block;
+
+ block_offset = ((char *)storage - pool->base) >> pool->min_bits;
+ block = pool->blocks + block_offset;
+
+ BITCLEAR (pool, block_offset + ((1 << block->bits) - 1));
+ pool->free_bytes += 1 << (block->bits + pool->min_bits);
+
+ merge_buddies (pool, block, pool->num_sizes);
+}
+
+void
+_cairo_mempool_fini (cairo_mempool_t *pool)
+{
+ free (pool->map);
+ free (pool->blocks);
+}
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index d3bd9403..2715abd0 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -141,12 +141,16 @@ _cairo_quartz_image_surface_get_extents (void *asurface,
*/
static cairo_status_t
-_cairo_quartz_image_surface_flush (void *asurface)
+_cairo_quartz_image_surface_flush (void *asurface,
+ unsigned flags)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
CGImageRef oldImage = surface->image;
CGImageRef newImage = NULL;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
/* XXX only flush if the image has been modified. */
/* To be released by the ReleaseCallback */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 8c2b6452..e7eb4cc2 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -213,7 +213,7 @@ _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
}
_cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph);
-
+
if (scaled_glyph->surface != NULL)
cairo_surface_destroy (&scaled_glyph->surface->base);
diff --git a/src/cairo-surface-backend-private.h b/src/cairo-surface-backend-private.h
index c275ce6e..955a79ff 100644
--- a/src/cairo-surface-backend-private.h
+++ b/src/cairo-surface-backend-private.h
@@ -110,7 +110,8 @@ struct _cairo_surface_backend {
cairo_font_options_t *options);
cairo_warn cairo_status_t
- (*flush) (void *surface);
+ (*flush) (void *surface,
+ unsigned flags);
cairo_warn cairo_status_t
(*mark_dirty_rectangle) (void *surface,
diff --git a/src/cairo-surface-inline.h b/src/cairo-surface-inline.h
index 27ea8f0e..85fbc919 100644
--- a/src/cairo-surface-inline.h
+++ b/src/cairo-surface-inline.h
@@ -41,11 +41,11 @@
#include "cairo-surface-private.h"
static inline cairo_status_t
-_cairo_surface_flush (cairo_surface_t *surface)
+__cairo_surface_flush (cairo_surface_t *surface, unsigned flags)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (surface->backend->flush)
- status = surface->backend->flush (surface);
+ status = surface->backend->flush (surface, flags);
return status;
}
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index 83fd1f80..64036b64 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -1202,14 +1202,12 @@ _cairo_surface_observer_glyphs (void *abstract_surface,
}
static cairo_status_t
-_cairo_surface_observer_flush (void *abstract_surface)
+_cairo_surface_observer_flush (void *abstract_surface, unsigned flags)
{
cairo_surface_observer_t *surface = abstract_surface;
do_callbacks (surface, &surface->flush_callbacks);
-
- cairo_surface_flush (surface->target);
- return surface->target->status;
+ return _cairo_surface_flush (surface->target, flags);
}
static cairo_status_t
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 63202fbf..f20ab073 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -115,4 +115,7 @@ cairo_private cairo_surface_t *
_cairo_surface_get_source (cairo_surface_t *surface,
cairo_rectangle_int_t *extents);
+cairo_private cairo_status_t
+_cairo_surface_flush (cairo_surface_t *surface, unsigned flags);
+
#endif /* CAIRO_SURFACE_PRIVATE_H */
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 9471e474..68bf9054 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -64,15 +64,14 @@ _cairo_surface_snapshot_finish (void *abstract_surface)
}
static cairo_status_t
-_cairo_surface_snapshot_flush (void *abstract_surface)
+_cairo_surface_snapshot_flush (void *abstract_surface, unsigned flags)
{
cairo_surface_snapshot_t *surface = abstract_surface;
cairo_surface_t *target;
cairo_status_t status;
target = _cairo_surface_snapshot_get_target (&surface->base);
- cairo_surface_flush (target);
- status = target->status;
+ status = _cairo_surface_flush (target, flags);
cairo_surface_destroy (target);
return status;
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 7ceef112..051e95f2 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -222,12 +222,10 @@ _cairo_surface_subsurface_glyphs (void *abstract_surface,
}
static cairo_status_t
-_cairo_surface_subsurface_flush (void *abstract_surface)
+_cairo_surface_subsurface_flush (void *abstract_surface, unsigned flags)
{
cairo_surface_subsurface_t *surface = abstract_surface;
-
- cairo_surface_flush (surface->target);
- return surface->target->status;
+ return _cairo_surface_flush (surface->target, flags);
}
static cairo_status_t
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 6ab2140b..dcce41ed 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -48,6 +48,7 @@
#include "cairo-image-surface-inline.h"
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
+#include "cairo-surface-inline.h"
#include "cairo-tee-surface-private.h"
/**
@@ -386,17 +387,13 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
return NULL;
}
-void
+cairo_status_t
_cairo_surface_begin_modification (cairo_surface_t *surface)
{
assert (surface->status == CAIRO_STATUS_SUCCESS);
assert (! surface->finished);
- _cairo_surface_detach_snapshots (surface);
- if (surface->snapshot_of != NULL)
- _cairo_surface_detach_snapshot (surface);
-
- _cairo_surface_detach_mime_data (surface);
+ return _cairo_surface_flush (surface, 1);
}
void
@@ -416,6 +413,7 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->status = CAIRO_STATUS_SUCCESS;
surface->unique_id = _cairo_surface_allocate_unique_id ();
surface->finished = FALSE;
+ surface->_finishing = FALSE;
surface->is_clear = FALSE;
surface->serial = 0;
surface->damage = NULL;
@@ -989,14 +987,12 @@ cairo_surface_get_reference_count (cairo_surface_t *surface)
static void
_cairo_surface_finish_snapshots (cairo_surface_t *surface)
{
- cairo_surface_flush (surface);
+ cairo_status_t status;
/* update the snapshots *before* we declare the surface as finished */
surface->_finishing = TRUE;
-
- _cairo_surface_detach_snapshots (surface);
- if (surface->snapshot_of != NULL)
- _cairo_surface_detach_snapshot (surface);
+ status = _cairo_surface_flush (surface, 0);
+ (void) status;
}
static void
@@ -1459,6 +1455,18 @@ cairo_surface_get_font_options (cairo_surface_t *surface,
}
slim_hidden_def (cairo_surface_get_font_options);
+cairo_status_t
+_cairo_surface_flush (cairo_surface_t *surface, unsigned flags)
+{
+ /* update the current snapshots *before* the user updates the surface */
+ _cairo_surface_detach_snapshots (surface);
+ if (surface->snapshot_of != NULL)
+ _cairo_surface_detach_snapshot (surface);
+ _cairo_surface_detach_mime_data (surface);
+
+ return __cairo_surface_flush (surface, flags);
+}
+
/**
* cairo_surface_flush:
* @surface: a #cairo_surface_t
@@ -1483,15 +1491,9 @@ cairo_surface_flush (cairo_surface_t *surface)
if (surface->finished)
return;
- /* update the current snapshots *before* the user updates the surface */
- _cairo_surface_detach_snapshots (surface);
- _cairo_surface_detach_mime_data (surface);
-
- if (surface->backend->flush) {
- status = surface->backend->flush (surface);
- if (unlikely (status))
- _cairo_surface_set_error (surface, status);
- }
+ status = _cairo_surface_flush (surface, 0);
+ if (unlikely (status))
+ _cairo_surface_set_error (surface, status);
}
slim_hidden_def (cairo_surface_flush);
@@ -1508,7 +1510,12 @@ slim_hidden_def (cairo_surface_flush);
void
cairo_surface_mark_dirty (cairo_surface_t *surface)
{
- cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1);
+ cairo_rectangle_int_t extents;
+
+ _cairo_surface_get_extents (surface, &extents);
+ cairo_surface_mark_dirty_rectangle (surface,
+ extents.x, extents.y,
+ extents.width, extents.height);
}
slim_hidden_def (cairo_surface_mark_dirty);
@@ -1620,7 +1627,11 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
return;
}
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status)) {
+ _cairo_surface_set_error (surface, status);
+ return;
+ }
surface->device_transform.xx = sx;
surface->device_transform.yy = sy;
@@ -1672,7 +1683,11 @@ cairo_surface_set_device_offset (cairo_surface_t *surface,
return;
}
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status)) {
+ _cairo_surface_set_error (surface, status);
+ return;
+ }
surface->device_transform.x0 = x_offset;
surface->device_transform.y0 = y_offset;
@@ -1747,6 +1762,8 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
double x_pixels_per_inch,
double y_pixels_per_inch)
{
+ cairo_status_t status;
+
if (unlikely (surface->status))
return;
@@ -1765,7 +1782,11 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
return;
}
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status)) {
+ _cairo_surface_set_error (surface, status);
+ return;
+ }
surface->x_fallback_resolution = x_pixels_per_inch;
surface->y_fallback_resolution = y_pixels_per_inch;
@@ -1971,7 +1992,9 @@ _cairo_surface_paint (cairo_surface_t *surface,
if (nothing_to_do (surface, op, source))
return CAIRO_STATUS_SUCCESS;
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status))
+ return status;
status = surface->backend->paint (surface, op, source, clip);
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
@@ -2016,7 +2039,9 @@ _cairo_surface_mask (cairo_surface_t *surface,
if (nothing_to_do (surface, op, source))
return CAIRO_STATUS_SUCCESS;
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status))
+ return status;
status = surface->backend->mask (surface, op, source, mask, clip);
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
@@ -2068,7 +2093,9 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
if (unlikely (status))
return status;
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status))
+ return status;
if (surface->backend->fill_stroke) {
cairo_matrix_t dev_ctm = *stroke_ctm;
@@ -2138,7 +2165,9 @@ _cairo_surface_stroke (cairo_surface_t *surface,
if (nothing_to_do (surface, op, source))
return CAIRO_STATUS_SUCCESS;
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status))
+ return status;
status = surface->backend->stroke (surface, op, source,
path, stroke_style,
@@ -2179,7 +2208,9 @@ _cairo_surface_fill (cairo_surface_t *surface,
if (nothing_to_do (surface, op, source))
return CAIRO_STATUS_SUCCESS;
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status))
+ return status;
status = surface->backend->fill (surface, op, source,
path, fill_rule,
@@ -2243,6 +2274,8 @@ slim_hidden_def (cairo_surface_copy_page);
void
cairo_surface_show_page (cairo_surface_t *surface)
{
+ cairo_status_t status;
+
if (unlikely (surface->status))
return;
@@ -2251,7 +2284,11 @@ cairo_surface_show_page (cairo_surface_t *surface)
return;
}
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status)) {
+ _cairo_surface_set_error (surface, status);
+ return;
+ }
/* It's fine if some backends don't implement show_page */
if (surface->backend->show_page == NULL)
@@ -2389,7 +2426,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (nothing_to_do (surface, op, source))
return CAIRO_STATUS_SUCCESS;
- _cairo_surface_begin_modification (surface);
+ status = _cairo_surface_begin_modification (surface);
+ if (unlikely (status))
+ return status;
if (_cairo_surface_has_device_transform (surface) &&
! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 1a591ca3..bdd6217d 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -714,11 +714,15 @@ _put_image_boxes (cairo_xcb_surface_t *surface,
}
static cairo_status_t
-_cairo_xcb_surface_flush (void *abstract_surface)
+_cairo_xcb_surface_flush (void *abstract_surface,
+ unsigned flags)
{
cairo_xcb_surface_t *surface = abstract_surface;
cairo_status_t status;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
if (likely (surface->fallback == NULL)) {
status = CAIRO_STATUS_SUCCESS;
if (! surface->base.finished && surface->deferred_clear)
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 06242ff1..bfe61681 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -95,6 +95,8 @@ _cairo_xlib_display_destroy (void *abstract_display)
{
cairo_xlib_display_t *display = abstract_display;
+ _cairo_xlib_display_fini_shm (display);
+
free (display);
}
@@ -147,15 +149,18 @@ static const cairo_device_backend_t _cairo_xlib_device_backend = {
_cairo_xlib_display_destroy,
};
-
static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t *display)
{
+#if 1
if (display->render_major > 0 || display->render_minor >= 4)
display->compositor = _cairo_xlib_traps_compositor_get ();
else if (display->render_major > 0 || display->render_minor >= 0)
display->compositor = _cairo_xlib_mask_compositor_get ();
else
display->compositor = _cairo_xlib_core_compositor_get ();
+#else
+ display->compositor = _cairo_xlib_fallback_compositor_get ();
+#endif
}
/**
@@ -263,6 +268,8 @@ _cairo_xlib_device_create (Display *dpy)
display->force_precision = -1;
+ _cairo_xlib_display_init_shm (display);
+
/* Prior to Render 0.10, there is no protocol support for gradients and
* we call function stubs instead, which would silently consume the drawing.
*/
diff --git a/src/cairo-xlib-fallback-compositor.c b/src/cairo-xlib-fallback-compositor.c
index 7d45cd14..d573276f 100644
--- a/src/cairo-xlib-fallback-compositor.c
+++ b/src/cairo-xlib-fallback-compositor.c
@@ -47,12 +47,198 @@
#include "cairo-xlib-private.h"
#include "cairo-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-surface-offset-private.h"
+
+static const cairo_compositor_t *
+_get_compositor (cairo_surface_t *surface)
+{
+ return ((cairo_image_surface_t *)surface)->compositor;
+}
+
+static cairo_bool_t
+unclipped (cairo_xlib_surface_t *xlib, cairo_clip_t *clip)
+{
+ cairo_rectangle_int_t r;
+
+ r.x = r.y = 0;
+ r.width = xlib->width;
+ r.height = xlib->height;
+ return _cairo_clip_contains_rectangle (clip, &r);
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_paint (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+ cairo_int_status_t status;
+ cairo_surface_t *shm;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ shm = _cairo_xlib_surface_get_shm (xlib);
+ if (shm == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_compositor_paint (_get_compositor (shm), shm,
+ extents->op,
+ &extents->source_pattern.base,
+ extents->clip);
+ if (unlikely (status))
+ return status;
+
+ xlib->base.is_clear =
+ extents->op == CAIRO_OPERATOR_CLEAR && unclipped (xlib, extents->clip);
+ xlib->base.serial++;
+ xlib->fallback++;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_mask (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+ cairo_int_status_t status;
+ cairo_surface_t *shm;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ shm = _cairo_xlib_surface_get_shm (xlib);
+ if (shm == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_compositor_mask (_get_compositor (shm), shm,
+ extents->op,
+ &extents->source_pattern.base,
+ &extents->mask_pattern.base,
+ extents->clip);
+ if (unlikely (status))
+ return status;
+
+ xlib->base.is_clear = FALSE;
+ xlib->base.serial++;
+ xlib->fallback++;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_stroke (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+ cairo_int_status_t status;
+ cairo_surface_t *shm;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ shm = _cairo_xlib_surface_get_shm (xlib);
+ if (shm == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_compositor_stroke (_get_compositor (shm), shm,
+ extents->op,
+ &extents->source_pattern.base,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ antialias,
+ extents->clip);
+ if (unlikely (status))
+ return status;
+
+ xlib->base.is_clear = FALSE;
+ xlib->base.serial++;
+ xlib->fallback++;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_fill (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+ cairo_int_status_t status;
+ cairo_surface_t *shm;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ shm = _cairo_xlib_surface_get_shm (xlib);
+ if (shm == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_compositor_fill (_get_compositor (shm), shm,
+ extents->op,
+ &extents->source_pattern.base,
+ path,
+ fill_rule, tolerance, antialias,
+ extents->clip);
+ if (unlikely (status))
+ return status;
+
+ xlib->base.is_clear = FALSE;
+ xlib->base.serial++;
+ xlib->fallback++;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_glyphs (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t overlap)
+{
+ cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+ cairo_int_status_t status;
+ cairo_surface_t *shm;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ shm = _cairo_xlib_surface_get_shm (xlib);
+ if (shm == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_compositor_glyphs (_get_compositor (shm), shm,
+ extents->op,
+ &extents->source_pattern.base,
+ glyphs, num_glyphs, scaled_font,
+ extents->clip);
+ if (unlikely (status))
+ return status;
+
+ xlib->base.is_clear = FALSE;
+ xlib->base.serial++;
+ xlib->fallback++;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static const cairo_compositor_t _cairo_xlib_shm_compositor = {
+ &_cairo_fallback_compositor,
+
+ _cairo_xlib_shm_compositor_paint,
+ _cairo_xlib_shm_compositor_mask,
+ _cairo_xlib_shm_compositor_stroke,
+ _cairo_xlib_shm_compositor_fill,
+ _cairo_xlib_shm_compositor_glyphs,
+};
const cairo_compositor_t *
_cairo_xlib_fallback_compositor_get (void)
{
- /* XXX Do something interesting here to mitigate fallbacks ala xcb */
- return &_cairo_fallback_compositor;
+ return &_cairo_xlib_shm_compositor;
}
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 45228323..8e9c044d 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -52,8 +52,10 @@
#include <pixman.h>
typedef struct _cairo_xlib_display cairo_xlib_display_t;
+typedef struct _cairo_xlib_shm_display cairo_xlib_shm_display_t;
typedef struct _cairo_xlib_screen cairo_xlib_screen_t;
typedef struct _cairo_xlib_source cairo_xlib_source_t;
+typedef struct _cairo_xlib_proxy cairo_xlib_proxy_t;
typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
/* size of color cube */
@@ -72,6 +74,8 @@ struct _cairo_xlib_display {
cairo_list_t screens;
cairo_list_t fonts;
+ cairo_xlib_shm_display_t *shm;
+
const cairo_compositor_t *compositor;
int render_major;
@@ -168,6 +172,8 @@ struct _cairo_xlib_surface {
Picture picture;
const cairo_compositor_t *compositor;
+ cairo_surface_t *shm;
+ int fallback;
cairo_xlib_display_t *display;
cairo_xlib_screen_t *screen;
@@ -205,6 +211,11 @@ struct _cairo_xlib_surface {
} embedded_source;
};
+struct _cairo_xlib_proxy {
+ struct _cairo_xlib_source source;
+ cairo_surface_t *owner;
+};
+
cairo_private cairo_status_t
_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
cairo_xlib_surface_t *surface,
@@ -213,6 +224,12 @@ _cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
cairo_private cairo_device_t *
_cairo_xlib_device_create (Display *display);
+cairo_private void
+_cairo_xlib_display_init_shm (cairo_xlib_display_t *display);
+
+cairo_private void
+_cairo_xlib_display_fini_shm (cairo_xlib_display_t *display);
+
cairo_private cairo_xlib_screen_t *
_cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
Screen *screen);
@@ -381,4 +398,46 @@ _cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
gc);
}
+cairo_private cairo_surface_t *
+_cairo_xlib_surface_create_similar_shm (void *surface,
+ cairo_format_t format,
+ int width, int height);
+
+cairo_private cairo_surface_t *
+_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface);
+
+cairo_private cairo_int_status_t
+_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface);
+
+cairo_private cairo_surface_t *
+_cairo_xlib_surface_create_shm_image (cairo_xlib_surface_t *surface,
+ pixman_format_code_t format,
+ int width, int height);
+
+cairo_private void
+_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
+ XImage *ximage);
+
+cairo_private void *
+_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface);
+
+cairo_private cairo_bool_t
+_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface);
+
+cairo_private cairo_bool_t
+_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface);
+
+cairo_private Pixmap
+_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface);
+
+cairo_private void
+_cairo_xlib_shm_surface_mark_active (cairo_surface_t *surface);
+
+cairo_private XRenderPictFormat *
+_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface);
+
+cairo_private pixman_format_code_t
+_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface);
+
+
#endif /* CAIRO_XLIB_PRIVATE_H */
diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
index a892985b..f76db24a 100644
--- a/src/cairo-xlib-render-compositor.c
+++ b/src/cairo-xlib-render-compositor.c
@@ -47,6 +47,7 @@
#include "cairo-xlib-private.h"
#include "cairo-compositor-private.h"
+#include "cairo-damage-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-list-inline.h"
#include "cairo-pattern-private.h"
@@ -125,14 +126,140 @@ set_clip_region (void *_surface,
}
static cairo_int_status_t
+copy_image_boxes (void *_dst,
+ cairo_image_surface_t *image,
+ cairo_boxes_t *boxes,
+ int dx, int dy)
+{
+ cairo_xlib_surface_t *dst = _dst;
+ struct _cairo_boxes_chunk *chunk;
+ cairo_int_status_t status;
+ Pixmap src;
+ GC gc;
+ int i, j;
+
+ status = acquire (dst);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
+ if (unlikely (status)) {
+ release (dst);
+ return status;
+ }
+
+ src = _cairo_xlib_shm_surface_get_pixmap (&image->base);
+ if (boxes->num_boxes == 1) {
+ int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
+ int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
+ int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
+ int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
+
+ XCopyArea (dst->dpy, src, dst->drawable, gc,
+ x1 + dx, y1 + dy,
+ x2 - x1, y2 - y1,
+ x1, y1);
+ } else {
+ XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+ XRectangle *rects = stack_rects;
+
+ if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
+ rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
+ if (unlikely (rects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ j = 0;
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ rects[j].x = x1;
+ rects[j].y = y1;
+ rects[j].width = x2 - x1;
+ rects[j].height = y2 - y1;
+ j++;
+ }
+ }
+ assert (j == boxes->num_boxes);
+
+ XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
+
+ XCopyArea (dst->dpy, src, dst->drawable, gc,
+ dx, dy,
+ image->width, image->height,
+ 0, 0);
+
+ XSetClipMask (dst->dpy, gc, None);
+
+ if (rects != stack_rects)
+ free (rects);
+ }
+
+ _cairo_xlib_shm_surface_mark_active (&image->base);
+ _cairo_xlib_surface_put_gc (dst->display, dst, gc);
+ release (dst);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
draw_image_boxes (void *_dst,
cairo_image_surface_t *image,
cairo_boxes_t *boxes,
int dx, int dy)
{
+ cairo_xlib_surface_t *dst = _dst;
struct _cairo_boxes_chunk *chunk;
+ cairo_image_surface_t *shm;
int i;
+ if (image->base.device == dst->base.device &&
+ _cairo_xlib_shm_surface_get_pixmap (&image->base))
+ return copy_image_boxes (dst, image, boxes, dx, dy);
+
+ shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst);
+ if (shm) {
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ cairo_box_t *b = &chunk->base[i];
+ cairo_rectangle_int_t r;
+
+ r.x = _cairo_fixed_integer_part (b->p1.x);
+ r.y = _cairo_fixed_integer_part (b->p1.y);
+ r.width = _cairo_fixed_integer_part (b->p2.x) - r.x;
+ r.height = _cairo_fixed_integer_part (b->p2.y) - r.y;
+
+ if (shm->pixman_format != image->pixman_format ||
+ ! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data,
+ image->stride / sizeof (uint32_t),
+ shm->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (image->pixman_format),
+ PIXMAN_FORMAT_BPP (shm->pixman_format),
+ r.x + dx, r.y + dy,
+ r.x, r.y,
+ r.width, r.height))
+ {
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, shm->pixman_image,
+ r.x + dx, r.y + dy,
+ 0, 0,
+ r.x, r.y,
+ r.width, r.height);
+ }
+
+ shm->base.damage =
+ _cairo_damage_add_rectangle (shm->base.damage, &r);
+ }
+ }
+ dst->base.is_clear = FALSE;
+ dst->fallback++;
+ dst->base.serial++;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
cairo_box_t *b = &chunk->base[i];
@@ -140,7 +267,7 @@ draw_image_boxes (void *_dst,
int y1 = _cairo_fixed_integer_part (b->p1.y);
int x2 = _cairo_fixed_integer_part (b->p2.x);
int y2 = _cairo_fixed_integer_part (b->p2.y);
- if ( _cairo_xlib_surface_draw_image (_dst, image,
+ if ( _cairo_xlib_surface_draw_image (dst, image,
x1 + dx, y1 + dy,
x2 - x1, y2 - y1,
x1, y1))
@@ -163,6 +290,7 @@ copy_boxes (void *_dst,
struct _cairo_boxes_chunk *chunk;
cairo_int_status_t status;
GC gc;
+ Drawable d;
int i, j;
if (! _cairo_xlib_surface_same_screen (dst, src))
@@ -181,11 +309,18 @@ copy_boxes (void *_dst,
return status;
}
- if (! src->owns_pixmap) {
- XGCValues gcv;
+ if (src->fallback && src->shm->damage->dirty) {
+ assert (src != dst);
+ d = _cairo_xlib_shm_surface_get_pixmap (src->shm);
+ assert (d != 0);
+ } else {
+ if (! src->owns_pixmap) {
+ XGCValues gcv;
- gcv.subwindow_mode = IncludeInferiors;
- XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
+ gcv.subwindow_mode = IncludeInferiors;
+ XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
+ }
+ d = src->drawable;
}
if (boxes->num_boxes == 1) {
@@ -194,7 +329,7 @@ copy_boxes (void *_dst,
int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
- XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+ XCopyArea (dst->dpy, d, dst->drawable, gc,
x1 + dx, y1 + dy,
x2 - x1, y2 - y1,
x1, y1);
@@ -215,7 +350,7 @@ copy_boxes (void *_dst,
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+ XCopyArea (dst->dpy, d, dst->drawable, gc,
x1 + dx, y1 + dy,
x2 - x1, y2 - y1,
x1, y1);
@@ -250,7 +385,7 @@ copy_boxes (void *_dst,
XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
- XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+ XCopyArea (dst->dpy, d, dst->drawable, gc,
extents->x + dx, extents->y + dy,
extents->width, extents->height,
extents->x, extents->y);
@@ -262,7 +397,9 @@ copy_boxes (void *_dst,
}
}
- if (! src->owns_pixmap) {
+ if (src->fallback && src->shm->damage->dirty) {
+ _cairo_xlib_shm_surface_mark_active (src->shm);
+ } else if (! src->owns_pixmap) {
XGCValues gcv;
gcv.subwindow_mode = ClipByChildren;
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 09f824f8..42fc46ab 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -75,11 +75,28 @@ _cairo_xlib_source_finish (void *abstract_surface)
}
static const cairo_surface_backend_t cairo_xlib_source_backend = {
- CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_SURFACE_TYPE_XLIB,
_cairo_xlib_source_finish,
NULL, /* read-only wrapper */
};
+static cairo_status_t
+_cairo_xlib_proxy_finish (void *abstract_surface)
+{
+ cairo_xlib_proxy_t *proxy = abstract_surface;
+
+ XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
+ _cairo_xlib_shm_surface_mark_active (proxy->owner);
+ cairo_surface_destroy (proxy->owner);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
+ CAIRO_SURFACE_TYPE_XLIB,
+ _cairo_xlib_proxy_finish,
+ NULL, /* read-only wrapper */
+};
+
static cairo_surface_t *
source (cairo_xlib_surface_t *dst, Picture picture)
{
@@ -286,6 +303,12 @@ render_pattern (cairo_xlib_surface_t *dst,
return _cairo_surface_create_in_error (status);
}
+ status = _cairo_xlib_surface_put_shm (src);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&src->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
src->picture = XRenderCreatePicture (dpy,
src->drawable, src->xrender_format,
0, NULL);
@@ -295,7 +318,6 @@ render_pattern (cairo_xlib_surface_t *dst,
return &src->base;
}
-
static cairo_surface_t *
gradient_source (cairo_xlib_surface_t *dst,
const cairo_gradient_pattern_t *gradient,
@@ -538,24 +560,15 @@ solid_source (cairo_xlib_surface_t *dst,
return transparent_source (dst, color);
}
-static cairo_surface_t *
-embedded_source (cairo_xlib_surface_t *dst,
- const cairo_surface_pattern_t *pattern,
- cairo_xlib_surface_t *src,
- const cairo_rectangle_int_t *extents,
- int *src_x, int *src_y)
+static cairo_xlib_source_t *init_source (cairo_xlib_surface_t *dst,
+ cairo_xlib_surface_t *src)
{
- cairo_xlib_source_t *source;
Display *dpy = dst->display->display;
- cairo_int_status_t status;
- XTransform xtransform;
- XRenderPictureAttributes pa;
- unsigned mask = 0;
+ cairo_xlib_source_t *source = &src->embedded_source;
/* As these are frequent and meant to be fast, we track pictures for
* native surface and minimise update requests.
*/
- source = &src->embedded_source;
if (source->picture == None) {
XRenderPictureAttributes pa;
@@ -576,6 +589,22 @@ embedded_source (cairo_xlib_surface_t *dst,
source->extend = CAIRO_EXTEND_NONE;
}
+ return (cairo_xlib_source_t *) cairo_surface_reference (&source->base);
+}
+
+static cairo_surface_t *
+embedded_source (cairo_xlib_surface_t *dst,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *src_x, int *src_y,
+ cairo_xlib_source_t *source)
+{
+ Display *dpy = dst->display->display;
+ cairo_int_status_t status;
+ XTransform xtransform;
+ XRenderPictureAttributes pa;
+ unsigned mask = 0;
+
status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
pattern->base.filter,
extents->x + extents->width / 2,
@@ -614,7 +643,7 @@ embedded_source (cairo_xlib_surface_t *dst,
if (mask)
XRenderChangePicture (dpy, source->picture, mask, &pa);
- return cairo_surface_reference (&source->base);
+ return &source->base;
}
static cairo_surface_t *
@@ -642,6 +671,9 @@ subsurface_source (cairo_xlib_surface_t *dst,
sample->y + sample->height <= sub->extents.height)
{
src = (cairo_xlib_surface_t *) sub->target;
+ status = _cairo_surface_flush (&src->base, 0);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
_cairo_matrix_is_translation (&pattern->base.matrix))
@@ -658,8 +690,8 @@ subsurface_source (cairo_xlib_surface_t *dst,
local_pattern.base.matrix.x0 += sub->extents.x;
local_pattern.base.matrix.y0 += sub->extents.y;
local_pattern.base.extend = CAIRO_EXTEND_NONE;
- return embedded_source (dst, &local_pattern, src, extents,
- src_x, src_y);
+ return embedded_source (dst, &local_pattern, extents,
+ src_x, src_y, init_source (dst, src));
}
}
@@ -750,7 +782,8 @@ native_source (cairo_xlib_surface_t *dst,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y)
{
- cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) pattern->surface;
+ cairo_xlib_surface_t *src;
+ cairo_int_status_t status;
if (_cairo_surface_is_subsurface (pattern->surface))
return subsurface_source (dst, pattern, is_mask,
@@ -758,6 +791,9 @@ native_source (cairo_xlib_surface_t *dst,
src_x, src_y);
src = unwrap_source (pattern);
+ status = _cairo_surface_flush (&src->base, 0);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
sample->x >= 0 && sample->y >= 0 &&
@@ -771,65 +807,10 @@ native_source (cairo_xlib_surface_t *dst,
return cairo_surface_reference (&src->base);
}
- return embedded_source (dst, pattern, src, extents, src_x, src_y);
+ return embedded_source (dst, pattern, extents, src_x, src_y,
+ init_source (dst, src));
}
-#if 0
-/* It is general quicker if we let the application choose which images
- * to cache for itself and only upload the fragments required for this
- * operation.
- */
-static cairo_surface_t *
-image_source (cairo_xlib_surface_t *dst,
- const cairo_surface_pattern_t *pattern,
- const cairo_rectangle_int_t *extents,
- int *src_x, int *src_y)
-{
- cairo_image_surface_t *src = (cairo_image_surface_t *) pattern->surface;
- cairo_xlib_surface_t *snapshot;
- cairo_surface_pattern_t local_pattern;
- cairo_status_t status;
-
- snapshot = (cairo_xlib_surface_t *)
- _cairo_surface_has_snapshot (&src->base, dst->base.backend);
- if (snapshot == NULL || snapshot->screen != dst->screen) {
- if (snapshot)
- _cairo_surface_detach_snapshot (&snapshot->base);
-
- snapshot = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- src->base.content,
- src->width,
- src->height);
- if (snapshot->base.type != CAIRO_SURFACE_TYPE_XLIB) {
- cairo_surface_destroy (&snapshot->base);
- return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- status = _cairo_xlib_surface_draw_image (snapshot, src,
- 0, 0,
- src->width, src->height,
- 0, 0);
- if (unlikely (status)) {
- cairo_surface_destroy (&snapshot->base);
- return _cairo_surface_create_in_error (status);
- }
-
- _cairo_surface_attach_snapshot (&src->base,
- &snapshot->base,
- cairo_surface_finish);
-
- /* reference remains held by the snapshot from image */
- cairo_surface_destroy (&snapshot->base);
- }
-
- local_pattern = *pattern;
- local_pattern.surface = &snapshot->base;
-
- return native_source (dst, &local_pattern, extents, src_x, src_y);
-}
-#endif
-
static cairo_surface_t *
recording_pattern_get_surface (const cairo_pattern_t *pattern)
{
@@ -912,13 +893,49 @@ surface_source (cairo_xlib_surface_t *dst,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y)
{
- cairo_xlib_surface_t *src;
- cairo_image_surface_t *image;
+ cairo_surface_t *src;
+ cairo_xlib_surface_t *xsrc;
cairo_surface_pattern_t local_pattern;
cairo_status_t status;
cairo_rectangle_int_t upload, limit, map_extents;
cairo_matrix_t m;
+ src = pattern->surface;
+ if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
+ src->device == dst->base.device &&
+ _cairo_xlib_shm_surface_get_pixmap (src)) {
+ cairo_xlib_proxy_t *proxy;
+
+ cairo_surface_reference (src);
+
+prepare_shm_image:
+ proxy = malloc (sizeof(*proxy));
+ if (unlikely (proxy == NULL)) {
+ cairo_surface_destroy (src);
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ _cairo_surface_init (&proxy->source.base,
+ &cairo_xlib_proxy_backend,
+ dst->base.device,
+ CAIRO_CONTENT_COLOR_ALPHA);
+
+ proxy->source.dpy = dst->display->display;
+ proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
+ _cairo_xlib_shm_surface_get_pixmap (src),
+ _cairo_xlib_shm_surface_get_xrender_format (src),
+ 0, NULL);
+
+ proxy->source.has_component_alpha = 0;
+ proxy->source.has_matrix = 0;
+ proxy->source.filter = CAIRO_FILTER_NEAREST;
+ proxy->source.extend = CAIRO_EXTEND_NONE;
+ proxy->owner = src;
+
+ return embedded_source (dst, pattern, extents, src_x, src_y,
+ &proxy->source);
+ }
+
upload = *sample;
if (_cairo_surface_get_extents (pattern->surface, &limit)) {
if (pattern->base.extend == CAIRO_EXTEND_NONE) {
@@ -935,15 +952,10 @@ surface_source (cairo_xlib_surface_t *dst,
}
}
- src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- pattern->surface->content,
- upload.width,
- upload.height);
- if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
- cairo_surface_destroy (&src->base);
- return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
+ src = _cairo_xlib_surface_create_similar_shm (&dst->base,
+ _cairo_format_from_content (pattern->surface->content),
+ upload.width,
+ upload.height);
_cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
cairo_matrix_init_translate (&local_pattern.base.matrix,
@@ -952,20 +964,18 @@ surface_source (cairo_xlib_surface_t *dst,
map_extents = upload;
map_extents.x = map_extents.y = 0;
- image = _cairo_surface_map_to_image (&src->base, &map_extents);
- status = _cairo_surface_paint (&image->base,
+ status = _cairo_surface_paint (src,
CAIRO_OPERATOR_SOURCE,
&local_pattern.base,
NULL);
- status = _cairo_surface_unmap_image (&src->base, image);
_cairo_pattern_fini (&local_pattern.base);
if (unlikely (status)) {
- cairo_surface_destroy (&src->base);
+ cairo_surface_destroy (src);
return _cairo_surface_create_in_error (status);
}
- local_pattern.base.matrix = pattern->base.matrix;
+ _cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
if (upload.x | upload.y) {
cairo_matrix_init_translate (&m, -upload.x, -upload.y);
cairo_matrix_multiply (&local_pattern.base.matrix,
@@ -974,21 +984,44 @@ surface_source (cairo_xlib_surface_t *dst,
}
*src_x = *src_y = 0;
- _cairo_xlib_surface_ensure_picture (src);
- if (! picture_set_properties (src->display,
- src->picture,
- &pattern->base,
+ if (src->device == dst->base.device &&
+ _cairo_xlib_shm_surface_get_pixmap (src)) {
+ pattern = &local_pattern;
+ goto prepare_shm_image;
+ }
+
+ xsrc = (cairo_xlib_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ src->content,
+ upload.width,
+ upload.height);
+ if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ cairo_surface_destroy (src);
+ cairo_surface_destroy (&xsrc->base);
+ return None;
+ }
+
+ status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
+ 0, 0,
+ upload.width, upload.height,
+ 0, 0);
+ cairo_surface_destroy (src);
+
+ _cairo_xlib_surface_ensure_picture (xsrc);
+ if (! picture_set_properties (xsrc->display,
+ xsrc->picture,
+ &local_pattern.base,
&local_pattern.base.matrix,
extents,
src_x, src_y))
{
- cairo_surface_destroy (&src->base);
+ cairo_surface_destroy (&xsrc->base);
return render_pattern (dst, &pattern->base,
is_mask, extents,
src_x, src_y);
}
- return &src->base;
+ return &xsrc->base;
}
static cairo_bool_t
@@ -1052,10 +1085,6 @@ _cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
return record_source (dst, spattern, is_mask,
extents, sample,
src_x, src_y);
-#if 0
- if (spattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE)
- return image_source (dst, spattern, extents, src_x, src_y);
-#endif
return surface_source (dst, spattern, is_mask,
extents, sample,
diff --git a/src/cairo-xlib-surface-shm.c b/src/cairo-xlib-surface-shm.c
new file mode 100644
index 00000000..37423d55
--- /dev/null
+++ b/src/cairo-xlib-surface-shm.c
@@ -0,0 +1,1119 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
+
+#include "cairo-xlib-private.h"
+#include "cairo-xlib-surface-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-mempool-private.h"
+
+#include "cairo-damage-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-list-inline.h"
+
+#include <X11/Xlibint.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#define MIN_PIXMAP_SIZE 4096
+
+#define MIN_BITS 8
+#define MIN_SIZE (1<<(MIN_BITS-1))
+
+typedef struct _cairo_xlib_shm cairo_xlib_shm_t;
+typedef struct _cairo_xlib_shm_info cairo_xlib_shm_info_t;
+typedef struct _cairo_xlib_shm_surface cairo_xlib_shm_surface_t;
+
+struct _cairo_xlib_shm {
+ cairo_mempool_t mem;
+
+ XShmSegmentInfo shm;
+ unsigned long attached;
+ cairo_list_t link;
+};
+
+struct _cairo_xlib_shm_info {
+ unsigned long last_request;
+ void *mem;
+ size_t size;
+ cairo_xlib_shm_t *pool;
+};
+
+struct _cairo_xlib_shm_surface {
+ cairo_image_surface_t image;
+
+ cairo_xlib_shm_info_t *info;
+ Pixmap pixmap;
+ unsigned long active;
+ int idle;
+};
+
+/* the parent is always given by index/2 */
+#define PQ_PARENT_INDEX(i) ((i) >> 1)
+#define PQ_FIRST_ENTRY 1
+
+/* left and right children are index * 2 and (index * 2) +1 respectively */
+#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
+
+#define PQ_TOP(pq) ((pq)->elements[PQ_FIRST_ENTRY])
+
+struct pqueue {
+ int size, max_size;
+ cairo_xlib_shm_info_t **elements;
+};
+
+struct _cairo_xlib_shm_display {
+ int has_pixmaps;
+
+ cairo_list_t pool;
+ struct pqueue info;
+};
+
+static inline cairo_bool_t
+seqno_passed (unsigned long a, unsigned long b)
+{
+ return (long)(b - a) > 0;
+}
+
+static inline cairo_status_t
+_pqueue_init (struct pqueue *pq)
+{
+ pq->max_size = 32;
+ pq->size = 0;
+
+ pq->elements = _cairo_malloc_ab (pq->max_size,
+ sizeof (cairo_xlib_shm_info_t *));
+ if (unlikely (pq->elements == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ PQ_TOP(pq) = NULL;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+_pqueue_fini (struct pqueue *pq)
+{
+ free (pq->elements);
+}
+
+static cairo_status_t
+_pqueue_grow (struct pqueue *pq)
+{
+ cairo_xlib_shm_info_t **new_elements;
+
+ new_elements = _cairo_realloc_ab (pq->elements,
+ 2 * pq->max_size,
+ sizeof (cairo_xlib_shm_info_t *));
+ if (unlikely (new_elements == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pq->elements = new_elements;
+ pq->max_size *= 2;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_pqueue_shrink (struct pqueue *pq, int min_size)
+{
+ cairo_xlib_shm_info_t **new_elements;
+
+ if (min_size <= pq->max_size)
+ return;
+
+ new_elements = _cairo_realloc_ab (pq->elements,
+ min_size,
+ sizeof (cairo_xlib_shm_info_t *));
+ if (unlikely (new_elements == NULL))
+ return;
+
+ pq->elements = new_elements;
+ pq->max_size = min_size;
+}
+
+static inline cairo_status_t
+_pqueue_push (struct pqueue *pq, cairo_xlib_shm_info_t *info)
+{
+ cairo_xlib_shm_info_t **elements;
+ int i, parent;
+
+ if (unlikely (pq->size + 1 == pq->max_size)) {
+ cairo_status_t status;
+
+ status = _pqueue_grow (pq);
+ if (unlikely (status))
+ return status;
+ }
+
+ elements = pq->elements;
+
+ for (i = ++pq->size;
+ i != PQ_FIRST_ENTRY &&
+ info->last_request < elements[parent = PQ_PARENT_INDEX (i)]->last_request;
+ i = parent)
+ {
+ elements[i] = elements[parent];
+ }
+
+ elements[i] = info;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+_pqueue_pop (struct pqueue *pq)
+{
+ cairo_xlib_shm_info_t **elements = pq->elements;
+ cairo_xlib_shm_info_t *tail;
+ int child, i;
+
+ tail = elements[pq->size--];
+ if (pq->size == 0) {
+ elements[PQ_FIRST_ENTRY] = NULL;
+ _pqueue_shrink (pq, 32);
+ return;
+ }
+
+ for (i = PQ_FIRST_ENTRY;
+ (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
+ i = child)
+ {
+ if (child != pq->size &&
+ elements[child+1]->last_request < elements[child]->last_request)
+ {
+ child++;
+ }
+
+ if (elements[child]->last_request >= tail->last_request)
+ break;
+
+ elements[i] = elements[child];
+ }
+ elements[i] = tail;
+}
+
+static cairo_bool_t _x_error_occurred;
+static int
+_check_error_handler (Display *display,
+ XErrorEvent *event)
+{
+ _x_error_occurred = TRUE;
+ return False; /* ignored */
+}
+
+static cairo_bool_t
+can_use_shm (Display *dpy, int *has_pixmap)
+{
+ XShmSegmentInfo shm;
+ int (*old_handler) (Display *display, XErrorEvent *event);
+ Status success;
+ int major, minor;
+
+ if (! XShmQueryExtension (dpy))
+ return FALSE;
+
+ XShmQueryVersion (dpy, &major, &minor, has_pixmap);
+
+ 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;
+ }
+
+ _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;
+}
+
+static void trigger_event (Display *dpy)
+{
+ xReq *req;
+
+ LockDisplay(dpy);
+ GetEmptyReq(GetInputFocus, req);
+ UnlockDisplay(dpy);
+}
+
+static void
+_cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
+ cairo_xlib_shm_t *pool)
+{
+ shmdt (pool->shm.shmaddr);
+ if (display->display) /* may be called after CloseDisplay */
+ XShmDetach (display->display, &pool->shm);
+
+ _cairo_mempool_fini (&pool->mem);
+
+ cairo_list_del (&pool->link);
+ free (pool);
+}
+
+static void
+_cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
+{
+ cairo_xlib_shm_info_t *info;
+ Display *dpy = display->display;
+ struct pqueue *pq = &display->shm->info;
+ unsigned long processed;
+
+ if (PQ_TOP(pq) == NULL)
+ return;
+
+ XEventsQueued (dpy, QueuedAfterReading);
+ processed = LastKnownRequestProcessed (dpy);
+
+ info = PQ_TOP(pq);
+ do {
+ if (! seqno_passed (info->last_request, processed))
+ break;
+
+ _cairo_mempool_free (&info->pool->mem, info->mem);
+ _pqueue_pop (&display->shm->info);
+ free (info);
+ } while ((info = PQ_TOP(pq)));
+}
+
+static cairo_xlib_shm_info_t *
+_cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size)
+{
+ cairo_xlib_shm_info_t *info;
+ struct pqueue *pq = &display->shm->info;
+
+ if (PQ_TOP(pq) == NULL)
+ return NULL;
+
+ info = PQ_TOP(pq);
+ do {
+ _pqueue_pop (&display->shm->info);
+
+ if (info->size >= size && size <= 2*info->size)
+ return info;
+
+ _cairo_mempool_free (&info->pool->mem, info->mem);
+ free (info);
+ } while ((info = PQ_TOP(pq)));
+
+ return NULL;
+}
+
+static cairo_xlib_shm_t *
+_cairo_xlib_shm_pool_find (cairo_xlib_display_t *display,
+ size_t size,
+ void **ptr)
+{
+ cairo_xlib_shm_t *pool;
+
+ cairo_list_foreach_entry (pool, cairo_xlib_shm_t, &display->shm->pool, link) {
+ if (pool->mem.free_bytes >= size) {
+ void *mem = _cairo_mempool_alloc (&pool->mem, size);
+ if (mem != NULL) {
+ *ptr = mem;
+ return pool;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void
+_cairo_xlib_shm_pool_cleanup (cairo_xlib_display_t *display)
+{
+ cairo_xlib_shm_t *pool, *next;
+ unsigned long processed;
+
+ processed = LastKnownRequestProcessed (display->display);
+
+ cairo_list_foreach_entry_safe (pool, next, cairo_xlib_shm_t,
+ &display->shm->pool, link) {
+ if (! seqno_passed (pool->attached, processed))
+ break;
+
+ if (pool->mem.free_bytes == pool->mem.max_bytes)
+ _cairo_xlib_display_shm_pool_destroy (display, pool);
+ }
+}
+
+static cairo_xlib_shm_t *
+_cairo_xlib_shm_pool_create(cairo_xlib_display_t *display,
+ size_t size, void **ptr)
+{
+ Display *dpy = display->display;
+ cairo_xlib_shm_t *pool;
+ size_t bytes, maxbits = 16, minbits = MIN_BITS;
+ Status success;
+
+ pool = malloc (sizeof (cairo_xlib_shm_t));
+ if (pool == NULL)
+ return NULL;
+
+ bytes = 1 << maxbits;
+ while (bytes <= size)
+ bytes <<= 1, maxbits++;
+ bytes <<= 3;
+
+ minbits += (maxbits - 16) / 2;
+
+ pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+ while (pool->shm.shmid == -1 && bytes >= 2*size) {
+ bytes >>= 1;
+ pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+ }
+ if (pool->shm.shmid == -1)
+ goto cleanup;
+
+ 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);
+ goto cleanup;
+ }
+
+ pool->attached = NextRequest (dpy);
+ success = XShmAttach (dpy, &pool->shm);
+ shmctl (pool->shm.shmid, IPC_RMID, NULL);
+
+ if (! success)
+ goto cleanup_shm;
+
+ if (_cairo_mempool_init (&pool->mem, pool->shm.shmaddr, bytes,
+ minbits, maxbits - minbits + 1))
+ goto cleanup_detach;
+
+ cairo_list_add (&pool->link, &display->shm->pool);
+ trigger_event (display->display);
+
+ *ptr = _cairo_mempool_alloc (&pool->mem, size);
+ assert (*ptr != NULL);
+ return pool;
+
+cleanup_detach:
+ XShmDetach (dpy, &pool->shm);
+cleanup_shm:
+ shmdt (pool->shm.shmaddr);
+cleanup:
+ free (pool);
+ return NULL;
+}
+
+static cairo_xlib_shm_info_t *
+_cairo_xlib_shm_info_create (cairo_xlib_display_t *display,
+ size_t size, cairo_bool_t will_sync)
+{
+ cairo_xlib_shm_info_t *info;
+ cairo_xlib_shm_t *pool;
+ void *mem = NULL;
+
+ if (will_sync) {
+ info = _cairo_xlib_shm_info_find (display, size);
+ if (info)
+ return info;
+ }
+
+ _cairo_xlib_shm_info_cleanup (display);
+ pool = _cairo_xlib_shm_pool_find (display, size, &mem);
+ _cairo_xlib_shm_pool_cleanup (display);
+ if (pool == NULL)
+ pool = _cairo_xlib_shm_pool_create (display, size, &mem);
+ if (pool == NULL)
+ return NULL;
+
+ assert (mem != NULL);
+
+ info = malloc (sizeof (*info));
+ if (info == NULL) {
+ _cairo_mempool_free (&pool->mem, mem);
+ return NULL;
+ }
+
+ info->pool = pool;
+ info->mem = mem;
+ info->size = size;
+ info->last_request = 0;
+
+ return info;
+}
+
+static inline Display *
+peek_display (cairo_device_t *device)
+{
+ return ((cairo_xlib_display_t *)device)->display;
+}
+
+static inline unsigned long
+peek_processed (cairo_device_t *device)
+{
+ return LastKnownRequestProcessed (peek_display(device));
+}
+
+static cairo_status_t
+_cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
+{
+ cairo_xlib_shm_surface_t *shm = abstract_surface;
+ cairo_xlib_display_t *display;
+ cairo_status_t status;
+
+ if (shm->active == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (shm->image.base._finishing)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
+ shm->active = 0;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
+ if (unlikely (status))
+ return status;
+
+ XEventsQueued (display->display, QueuedAfterReading);
+ if (!seqno_passed (shm->active,
+ LastKnownRequestProcessed (display->display)))
+ XSync (display->display, False);
+
+ cairo_device_release (&display->base);
+ shm->active = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static inline cairo_bool_t
+active (cairo_xlib_shm_surface_t *shm, Display *dpy)
+{
+ return (shm->active &&
+ !seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
+}
+
+static cairo_status_t
+_cairo_xlib_shm_surface_finish (void *abstract_surface)
+{
+ cairo_xlib_shm_surface_t *shm = abstract_surface;
+ cairo_xlib_display_t *display;
+ cairo_status_t status;
+
+ status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
+ if (unlikely (status))
+ return status;
+
+ if (shm->pixmap)
+ XFreePixmap (display->display, shm->pixmap);
+
+ if (active (shm, display->display)) {
+ shm->info->last_request = shm->active;
+ _pqueue_push (&display->shm->info, shm->info);
+ } else {
+ cairo_xlib_shm_t *pool = shm->info->pool;
+
+ _cairo_mempool_free (&pool->mem, shm->info->mem);
+ free (shm->info);
+
+ _cairo_xlib_shm_pool_cleanup (display);
+ }
+
+ cairo_device_release (&display->base);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
+ CAIRO_SURFACE_TYPE_IMAGE,
+ _cairo_xlib_shm_surface_finish,
+
+ _cairo_default_context_create,
+
+ _cairo_image_surface_create_similar,
+ NULL, /* create similar image */
+ _cairo_image_surface_map_to_image,
+ _cairo_image_surface_unmap_image,
+
+ _cairo_image_surface_source,
+ _cairo_image_surface_acquire_source_image,
+ _cairo_image_surface_release_source_image,
+ _cairo_image_surface_snapshot,
+
+ NULL, /* copy_page */
+ NULL, /* show_page */
+
+ _cairo_image_surface_get_extents,
+ _cairo_image_surface_get_font_options,
+
+ _cairo_xlib_shm_surface_flush,
+ NULL,
+
+ _cairo_image_surface_paint,
+ _cairo_image_surface_mask,
+ _cairo_image_surface_stroke,
+ _cairo_image_surface_fill,
+ NULL, /* fill-stroke */
+ _cairo_image_surface_glyphs,
+};
+
+static cairo_bool_t
+has_shm (cairo_xlib_surface_t *surface)
+{
+ cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
+ return display->shm != NULL;
+}
+
+static int
+has_shm_pixmaps (cairo_xlib_surface_t *surface)
+{
+ cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
+ return display->shm->has_pixmaps;
+}
+
+static cairo_xlib_shm_surface_t *
+_cairo_xlib_shm_surface_create (cairo_xlib_surface_t *other,
+ pixman_format_code_t format,
+ int width, int height,
+ cairo_bool_t will_sync,
+ int create_pixmap)
+{
+ cairo_xlib_shm_surface_t *shm;
+ cairo_xlib_display_t *display;
+ pixman_image_t *image;
+ int stride, size;
+
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP(format));
+ size = stride * height;
+ if (size < MIN_SIZE)
+ return NULL;
+
+ shm = malloc (sizeof (*shm));
+ if (unlikely (shm == NULL))
+ return (cairo_xlib_shm_surface_t *)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ _cairo_surface_init (&shm->image.base,
+ &cairo_xlib_shm_surface_backend,
+ other->base.device,
+ _cairo_content_from_pixman_format (format));
+
+ if (_cairo_xlib_display_acquire (other->base.device, &display))
+ goto cleanup_shm;
+
+ shm->info = _cairo_xlib_shm_info_create (display, size, will_sync);
+ if (shm->info == NULL)
+ goto cleanup_display;
+
+ image = pixman_image_create_bits (format, width, height,
+ (uint32_t *) shm->info->mem, stride);
+ if (image == NULL)
+ goto cleanup_info;
+
+ _cairo_image_surface_init (&shm->image, image, format);
+
+ shm->pixmap = 0;
+ if (create_pixmap && size >= create_pixmap) {
+ shm->pixmap = XShmCreatePixmap (display->display,
+ other->drawable,
+ shm->info->mem,
+ &shm->info->pool->shm,
+ shm->image.width,
+ shm->image.height,
+ shm->image.depth);
+ }
+ shm->active = shm->info->last_request;
+ shm->idle = -5;
+
+ cairo_device_release (&display->base);
+
+ return shm;
+
+cleanup_info:
+ _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
+ free(shm->info);
+cleanup_display:
+ cairo_device_release (&display->base);
+cleanup_shm:
+ free (shm);
+ return NULL;
+}
+
+static void
+_cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
+ cairo_xlib_display_t *display;
+ cairo_damage_t *damage;
+ GC gc;
+
+ damage = _cairo_damage_reduce (surface->base.damage);
+ surface->base.damage = _cairo_damage_create();
+
+ if (_cairo_xlib_display_acquire (surface->base.device, &display))
+ goto cleanup_damage;
+
+ if (_cairo_xlib_surface_get_gc (display, surface, &gc))
+ goto cleanup_display;
+
+ if (damage->region) {
+ XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
+ XRectangle *rects = stack_rects;
+ cairo_rectangle_int_t r;
+ int n_rects, i;
+
+ n_rects = cairo_region_num_rectangles (damage->region);
+ if (n_rects == 0) {
+ } else if (n_rects == 1) {
+ cairo_region_get_rectangle (damage->region, 0, &r);
+ XCopyArea (display->display,
+ surface->drawable, shm->pixmap, gc,
+ r.x, r.y,
+ r.width, r.height,
+ r.x, r.y);
+ } else {
+ if (n_rects > ARRAY_LENGTH (stack_rects)) {
+ rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
+ if (unlikely (rects == NULL)) {
+ rects = stack_rects;
+ n_rects = ARRAY_LENGTH (stack_rects);
+ }
+ }
+ for (i = 0; i < n_rects; i++) {
+ cairo_region_get_rectangle (damage->region, i, &r);
+
+ rects[i].x = r.x;
+ rects[i].y = r.y;
+ rects[i].width = r.width;
+ rects[i].height = r.height;
+ }
+ XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
+
+ XCopyArea (display->display,
+ surface->drawable, shm->pixmap, gc,
+ 0, 0,
+ shm->image.width, shm->image.height,
+ 0, 0);
+
+ if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
+ XSetClipMask (display->display, gc, None);
+ }
+ } else {
+ XCopyArea (display->display,
+ surface->drawable, shm->pixmap, gc,
+ 0, 0,
+ shm->image.width, shm->image.height,
+ 0, 0);
+ }
+
+ XSync (display->display, False);
+ shm->active = 0;
+ shm->idle--;
+
+ _cairo_xlib_surface_put_gc (display, surface, gc);
+cleanup_display:
+ cairo_device_release (&display->base);
+cleanup_damage:
+ _cairo_damage_destroy (damage);
+}
+
+static void
+_cairo_xlib_surface_clear_shm (cairo_xlib_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
+
+ assert (shm->active == 0);
+
+ _cairo_damage_destroy (surface->base.damage);
+ surface->base.damage = _cairo_damage_create();
+
+ memset (shm->image.data, 0, shm->image.stride * shm->image.height);
+}
+
+static void inc_idle (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
+ shm->idle++;
+}
+
+static void dec_idle (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
+ shm->idle--;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface)
+{
+ if (surface->fallback) {
+ assert (surface->base.damage);
+ assert (surface->shm);
+ assert (surface->shm->damage);
+ goto done;
+ }
+
+ if (surface->shm == NULL) {
+ pixman_format_code_t pixman_format;
+
+ if (! has_shm_pixmaps (surface))
+ return NULL;
+
+ if ((surface->width | surface->height) < 32)
+ return NULL;
+
+ pixman_format = _pixman_format_for_xlib_surface (surface);
+ if (pixman_format == 0)
+ return NULL;
+
+ surface->shm =
+ &_cairo_xlib_shm_surface_create (surface, pixman_format,
+ surface->width, surface->height,
+ TRUE, 1)->image.base;
+ if (surface->shm == NULL)
+ return NULL;
+
+ assert (surface->base.damage == NULL);
+ if (surface->base.serial || !surface->owns_pixmap) {
+ cairo_rectangle_int_t rect;
+
+ rect.x = rect.y = 0;
+ rect.width = surface->width;
+ rect.height = surface->height;
+
+ surface->base.damage =
+ _cairo_damage_add_rectangle (NULL, &rect);
+ } else
+ surface->base.damage = _cairo_damage_create ();
+
+ surface->shm->damage = _cairo_damage_create ();
+ }
+
+ if (!surface->base.is_clear && surface->base.damage->dirty)
+ _cairo_xlib_surface_update_shm (surface);
+
+ _cairo_xlib_shm_surface_flush (surface->shm, 1);
+
+ if (surface->base.is_clear && surface->base.damage->dirty)
+ _cairo_xlib_surface_clear_shm (surface);
+
+done:
+ dec_idle(surface->shm);
+ return surface->shm;
+}
+
+cairo_int_status_t
+_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
+{
+ cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+
+ if (!surface->fallback) {
+ if (surface->shm)
+ inc_idle (surface->shm);
+ return CAIRO_INT_STATUS_SUCCESS;
+ }
+
+ if (surface->shm->damage->dirty) {
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface->shm;
+ cairo_xlib_display_t *display;
+ cairo_damage_t *damage;
+ GC gc;
+
+ status = _cairo_xlib_display_acquire (surface->base.device, &display);
+ if (unlikely (status))
+ return status;
+
+ damage = _cairo_damage_reduce (shm->image.base.damage);
+ shm->image.base.damage = _cairo_damage_create ();
+
+ status = _cairo_xlib_surface_get_gc (display, surface, &gc);
+ if (unlikely (status))
+ goto out;
+
+ TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
+ damage->region ? cairo_region_num_rectangles (damage->region) : 0));
+ if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
+ XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
+ XRectangle *rects = stack_rects;
+ cairo_rectangle_int_t r;
+ int n_rects, i;
+
+ n_rects = cairo_region_num_rectangles (damage->region);
+ if (n_rects == 0) {
+ } else if (n_rects == 1) {
+ cairo_region_get_rectangle (damage->region, 0, &r);
+ XCopyArea (display->display,
+ shm->pixmap, surface->drawable, gc,
+ r.x, r.y,
+ r.width, r.height,
+ r.x, r.y);
+ } else {
+ if (n_rects > ARRAY_LENGTH (stack_rects)) {
+ rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
+ if (unlikely (rects == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto out;
+ }
+ }
+ for (i = 0; i < n_rects; i++) {
+ cairo_region_get_rectangle (damage->region, i, &r);
+
+ rects[i].x = r.x;
+ rects[i].y = r.y;
+ rects[i].width = r.width;
+ rects[i].height = r.height;
+ }
+ XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
+
+ XCopyArea (display->display,
+ shm->pixmap, surface->drawable, gc,
+ 0, 0,
+ shm->image.width, shm->image.height,
+ 0, 0);
+
+ if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
+ XSetClipMask (display->display, gc, None);
+ }
+ }
+ _cairo_damage_destroy (damage);
+
+ _cairo_xlib_surface_put_gc (display, surface, gc);
+out:
+ cairo_device_release (&display->base);
+ }
+
+ return status;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm_image (cairo_xlib_surface_t *surface,
+ pixman_format_code_t format,
+ int width, int height)
+{
+ if (! has_shm(surface))
+ return NULL;
+
+ return &_cairo_xlib_shm_surface_create (surface, format,
+ surface->width, surface->height,
+ TRUE, 0)->image.base;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_similar_shm (void *other,
+ cairo_format_t format,
+ int width, int height)
+{
+ cairo_surface_t *surface;
+
+ surface = NULL;
+ if (has_shm (other))
+ surface = &_cairo_xlib_shm_surface_create (other,
+ _cairo_format_to_pixman_format_code (format),
+ width, height, FALSE,
+ has_shm_pixmaps (other))->image.base;
+ if (surface == NULL)
+ surface = cairo_image_surface_create (format, width, height);
+
+ return surface;
+}
+
+static unsigned next_request (cairo_device_t *device)
+{
+ cairo_xlib_display_t *display = (cairo_xlib_display_t *) device;
+ return NextRequest (display->display);
+}
+
+void
+_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
+ XImage *ximage)
+{
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
+ int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
+ cairo_format_masks_t image_masks;
+ int ret;
+
+ ret = _pixman_format_to_masks (shm->image.pixman_format, &image_masks);
+ assert (ret);
+
+ ximage->width = shm->image.width;
+ ximage->height = shm->image.height;
+ ximage->format = ZPixmap;
+ ximage->data = (char *) shm->image.data;
+ ximage->obdata = (char *)&shm->info->pool->shm;
+ 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 = shm->image.depth;
+ ximage->bytes_per_line = shm->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);
+}
+
+void *
+_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm;
+
+ shm = (cairo_xlib_shm_surface_t *) surface;
+ shm->active = next_request (surface->device);
+ return &shm->info->pool->shm;
+}
+
+Pixmap
+_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm;
+
+ shm = (cairo_xlib_shm_surface_t *) surface;
+ return shm->pixmap;
+}
+
+void
+_cairo_xlib_shm_surface_mark_active (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm;
+
+ shm = (cairo_xlib_shm_surface_t *) surface;
+ shm->active = next_request (surface->device);
+ trigger_event (peek_display (surface->device));
+}
+
+XRenderPictFormat *
+_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm;
+
+ shm = (cairo_xlib_shm_surface_t *) surface;
+ if (shm->image.format != CAIRO_FORMAT_INVALID)
+ return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t *)surface->device,
+ shm->image.format);
+
+ return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t *)surface->device,
+ shm->image.pixman_format);
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm;
+
+ shm = (cairo_xlib_shm_surface_t *) surface;
+ if (shm->active == 0)
+ return FALSE;
+
+ if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
+ shm->active = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
+{
+ cairo_xlib_shm_surface_t *shm;
+
+ shm = (cairo_xlib_shm_surface_t *) surface;
+ return shm->idle > 0;
+}
+
+void
+_cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
+{
+ int has_pixmap;
+ cairo_xlib_shm_display_t *shm;
+
+ display->shm = NULL;
+
+ if (!can_use_shm (display->display, &has_pixmap))
+ return;
+
+ shm = malloc (sizeof (*shm));
+ if (unlikely (shm == NULL))
+ return;
+
+ if (unlikely (_pqueue_init (&shm->info))) {
+ free (shm);
+ return;
+ }
+
+ shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
+ cairo_list_init (&shm->pool);
+
+ display->shm = shm;
+}
+
+void
+_cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
+{
+ cairo_xlib_shm_display_t *shm = display->shm;
+
+ if (shm == NULL)
+ return;
+
+ _pqueue_fini (&shm->info);
+
+ while (!cairo_list_is_empty (&shm->pool)) {
+ cairo_xlib_shm_t *pool;
+
+ pool = cairo_list_first_entry (&shm->pool, cairo_xlib_shm_t, link);
+ _cairo_xlib_display_shm_pool_destroy (display, pool);
+ }
+
+ free (shm);
+ display->shm = NULL;
+}
+
+#endif
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 59a7885f..aeff746a 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -54,6 +54,7 @@
#include "cairo-compositor-private.h"
#include "cairo-clip-private.h"
+#include "cairo-damage-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
@@ -66,6 +67,10 @@
#include <X11/Xutil.h> /* for XDestroyImage */
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
#define XLIB_COORD_MAX 32767
#define DEBUG 0
@@ -375,6 +380,8 @@ _cairo_xlib_surface_finish (void *abstract_surface)
if (surface->owns_pixmap)
XFreePixmap (display->display, surface->drawable);
+ cairo_surface_destroy (surface->shm);
+
cairo_device_release (&display->base);
return status;
@@ -678,15 +685,32 @@ static int bits_per_pixel(cairo_xlib_surface_t *surface)
return 1;
}
+pixman_format_code_t
+_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface)
+{
+ cairo_format_masks_t masks;
+ pixman_format_code_t format;
+
+ masks.bpp = bits_per_pixel (surface);
+ masks.alpha_mask = surface->a_mask;
+ masks.red_mask = surface->r_mask;
+ masks.green_mask = surface->g_mask;
+ masks.blue_mask = surface->b_mask;
+ if (! _pixman_format_from_masks (&masks, &format))
+ return 0;
+
+ return format;
+}
+
static cairo_surface_t *
_get_image_surface (cairo_xlib_surface_t *surface,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ int try_shm)
{
cairo_int_status_t status;
cairo_image_surface_t *image = NULL;
XImage *ximage;
pixman_format_code_t pixman_format;
- cairo_format_masks_t xlib_masks;
cairo_xlib_display_t *display;
assert (extents->x >= 0);
@@ -697,13 +721,8 @@ _get_image_surface (cairo_xlib_surface_t *surface,
if (surface->base.is_clear ||
(surface->base.serial == 0 && surface->owns_pixmap))
{
- xlib_masks.bpp = bits_per_pixel (surface);
- xlib_masks.alpha_mask = surface->a_mask;
- xlib_masks.red_mask = surface->r_mask;
- xlib_masks.green_mask = surface->g_mask;
- xlib_masks.blue_mask = surface->b_mask;
- if (_pixman_format_from_masks (&xlib_masks, &pixman_format) &&
- _cairo_format_from_pixman_format (pixman_format) != CAIRO_FORMAT_INVALID)
+ pixman_format = _pixman_format_for_xlib_surface (surface);
+ if (pixman_format)
{
return _cairo_image_surface_create_with_pixman_format (NULL,
pixman_format,
@@ -713,11 +732,59 @@ _get_image_surface (cairo_xlib_surface_t *surface,
}
}
+ if (surface->shm) {
+ cairo_image_surface_t *src = (cairo_image_surface_t *) surface->shm;
+ cairo_surface_t *dst;
+ cairo_surface_pattern_t pattern;
+
+ dst = cairo_image_surface_create (src->format,
+ extents->width, extents->height);
+ if (unlikely (dst->status))
+ return dst;
+
+ _cairo_pattern_init_for_surface (&pattern, &src->base);
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ extents->x, extents->y);
+ status = _cairo_surface_paint (dst, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (dst);
+ dst = _cairo_surface_create_in_error (status);
+ }
+
+ return dst;
+ }
+
status = _cairo_xlib_display_acquire (surface->base.device, &display);
if (status)
return _cairo_surface_create_in_error (status);
- /* XXX: This should try to use the XShm extension if available */
+ pixman_format = _pixman_format_for_xlib_surface (surface);
+ if (try_shm && pixman_format) {
+ image = (cairo_image_surface_t *)
+ _cairo_xlib_surface_create_shm_image (surface, pixman_format,
+ extents->width, extents->height);
+ if (image && image->base.status == CAIRO_STATUS_SUCCESS) {
+ cairo_xlib_error_func_t old_handler;
+ XImage shm_image;
+ Bool success;
+
+ _cairo_xlib_shm_surface_get_ximage (&image->base, &shm_image);
+
+ old_handler = XSetErrorHandler (_noop_error_handler);
+ success = XShmGetImage (display->display,
+ surface->drawable,
+ &shm_image,
+ extents->x, extents->y,
+ AllPlanes);
+ XSetErrorHandler (old_handler);
+
+ if (success)
+ return &image->base;
+
+ cairo_surface_destroy (&image->base);
+ }
+ }
if (surface->use_pixmap == 0) {
cairo_xlib_error_func_t old_handler;
@@ -793,19 +860,13 @@ _get_image_surface (cairo_xlib_surface_t *surface,
_swap_ximage_to_native (ximage);
- xlib_masks.bpp = ximage->bits_per_pixel;
- xlib_masks.alpha_mask = surface->a_mask;
- xlib_masks.red_mask = surface->r_mask;
- xlib_masks.green_mask = surface->g_mask;
- xlib_masks.blue_mask = surface->b_mask;
-
/* We can't use pixman to simply write to image if:
* (a) the pixels are not appropriately aligned,
* (b) pixman does not the pixel format, or
* (c) if the image is palettized and we need to convert.
*/
- if (ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
- _pixman_format_from_masks (&xlib_masks, &pixman_format) &&
+ if (pixman_format &&
+ ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
(surface->visual == NULL || surface->visual->class == TrueColor))
{
image = (cairo_image_surface_t*)
@@ -1024,6 +1085,7 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
ximage.green_mask = surface->g_mask;
ximage.blue_mask = surface->b_mask;
ximage.xoffset = 0;
+ ximage.obdata = NULL;
status = _cairo_xlib_display_acquire (surface->base.device, &display);
if (unlikely (status))
@@ -1042,6 +1104,9 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
ximage.bits_per_pixel = image_masks.bpp;
ximage.bytes_per_line = image->stride;
ximage.data = (char *)image->data;
+ ximage.obdata = NULL;
+ if (image->base.device == surface->base.device)
+ ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base);
own_data = FALSE;
ret = XInitImage (&ximage);
@@ -1207,13 +1272,16 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
if (unlikely (status))
goto BAIL;
- XPutImage (display->display, surface->drawable, gc, &ximage,
- src_x, src_y, dst_x, dst_y, width, height);
+ if (ximage.obdata)
+ XShmPutImage (display->display, surface->drawable, gc, &ximage,
+ src_x, src_y, dst_x, dst_y, width, height, TRUE);
+ else
+ XPutImage (display->display, surface->drawable, gc, &ximage,
+ src_x, src_y, dst_x, dst_y, width, height);
_cairo_xlib_surface_put_gc (display, surface, gc);
BAIL:
-
cairo_device_release (&display->base);
if (own_data)
@@ -1247,12 +1315,18 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf
cairo_xlib_surface_t *surface = abstract_surface;
cairo_rectangle_int_t extents;
+ *image_extra = NULL;
+ *image_out = (cairo_image_surface_t *)
+ _cairo_xlib_surface_get_shm (abstract_surface);
+ if (*image_out)
+ return (*image_out)->base.status;
+
extents.x = extents.y = 0;
extents.width = surface->width;
extents.height = surface->height;
- *image_extra = NULL;
- *image_out = (cairo_image_surface_t*)_get_image_surface (surface, &extents);
+ *image_out = (cairo_image_surface_t*)
+ _get_image_surface (surface, &extents, TRUE);
return (*image_out)->base.status;
}
@@ -1266,8 +1340,7 @@ _cairo_xlib_surface_snapshot (void *abstract_surface)
extents.width = surface->width;
extents.height = surface->height;
- /* XXX notice the duplication with acquire source */
- return _get_image_surface (surface, &extents);
+ return _get_image_surface (surface, &extents, FALSE);
}
static void
@@ -1275,6 +1348,11 @@ _cairo_xlib_surface_release_source_image (void *abstract_surfa
cairo_image_surface_t *image,
void *image_extra)
{
+ cairo_xlib_surface_t *surface = abstract_surface;
+
+ if (&image->base == surface->shm)
+ return;
+
cairo_surface_destroy (&image->base);
}
@@ -1282,9 +1360,17 @@ static cairo_image_surface_t *
_cairo_xlib_surface_map_to_image (void *abstract_surface,
const cairo_rectangle_int_t *extents)
{
+ cairo_xlib_surface_t *surface = abstract_surface;
cairo_surface_t *image;
- image = _get_image_surface (abstract_surface, extents);
+ image = _cairo_xlib_surface_get_shm (abstract_surface);
+ if (image) {
+ assert (surface->base.damage);
+ surface->fallback++;
+ return _cairo_image_surface_map_to_image (image, extents);
+ }
+
+ image = _get_image_surface (abstract_surface, extents, TRUE);
cairo_surface_set_device_offset (image, -extents->x, -extents->y);
return (cairo_image_surface_t *) image;
@@ -1294,8 +1380,28 @@ static cairo_int_status_t
_cairo_xlib_surface_unmap_image (void *abstract_surface,
cairo_image_surface_t *image)
{
+ cairo_xlib_surface_t *surface = abstract_surface;
cairo_int_status_t status;
+ if (surface->shm) {
+ cairo_rectangle_int_t r;
+
+ assert (surface->fallback);
+ assert (surface->base.damage);
+
+ r.x = image->base.device_transform_inverse.x0;
+ r.y = image->base.device_transform_inverse.y0;
+ r.width = image->width;
+ r.height = image->height;
+
+ TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n",
+ __FUNCTION__, r.x, r.y, r.width, r.height));
+ surface->shm->damage =
+ _cairo_damage_add_rectangle (surface->shm->damage, &r);
+
+ return _cairo_image_surface_unmap_image (surface->shm, image);
+ }
+
status = _cairo_xlib_surface_draw_image (abstract_surface, image,
0, 0,
image->width, image->height,
@@ -1308,6 +1414,32 @@ _cairo_xlib_surface_unmap_image (void *abstract_surface,
return status;
}
+static cairo_status_t
+_cairo_xlib_surface_flush (void *abstract_surface,
+ unsigned flags)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_int_status_t status;
+
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_xlib_surface_put_shm (surface);
+ if (unlikely (status))
+ return status;
+
+ surface->fallback >>= 1;
+ if (surface->shm && _cairo_xlib_shm_surface_is_idle (surface->shm)) {
+ cairo_surface_destroy (surface->shm);
+ surface->shm = NULL;
+
+ _cairo_damage_destroy (surface->base.damage);
+ surface->base.damage = NULL;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_bool_t
_cairo_xlib_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
@@ -1332,6 +1464,31 @@ _cairo_xlib_surface_get_font_options (void *abstract_surface,
*options = *_cairo_xlib_screen_get_font_options (surface->screen);
}
+static inline cairo_int_status_t
+get_compositor (cairo_xlib_surface_t **surface,
+ const cairo_compositor_t **compositor)
+{
+ cairo_xlib_surface_t *s = *surface;
+ cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;;
+
+ if (s->fallback) {
+ assert (s->base.damage != NULL);
+ assert (s->shm != NULL);
+ assert (s->shm->damage != NULL);
+ if (! _cairo_xlib_shm_surface_is_active (s->shm)) {
+ *surface = (cairo_xlib_surface_t *) s->shm;
+ *compositor = ((cairo_image_surface_t *) s->shm)->compositor;
+ s->fallback++;
+ } else {
+ status = _cairo_xlib_surface_put_shm (s);
+ s->fallback = 0;
+ *compositor = s->compositor;
+ }
+ } else
+ *compositor = s->compositor;
+
+ return status;
+}
static cairo_int_status_t
_cairo_xlib_surface_paint (void *_surface,
@@ -1340,8 +1497,15 @@ _cairo_xlib_surface_paint (void *_surface,
const cairo_clip_t *clip)
{
cairo_xlib_surface_t *surface = _surface;
- return _cairo_compositor_paint (surface->compositor,
- &surface->base, op, source,
+ const cairo_compositor_t *compositor;
+ cairo_int_status_t status;
+
+ status = get_compositor (&surface, &compositor);
+ if (unlikely (status))
+ return status;
+
+ return _cairo_compositor_paint (compositor, &surface->base,
+ op, source,
clip);
}
@@ -1353,8 +1517,15 @@ _cairo_xlib_surface_mask (void *_surface,
const cairo_clip_t *clip)
{
cairo_xlib_surface_t *surface = _surface;
- return _cairo_compositor_mask (surface->compositor,
- &surface->base, op, source, mask,
+ const cairo_compositor_t *compositor;
+ cairo_int_status_t status;
+
+ status = get_compositor (&surface, &compositor);
+ if (unlikely (status))
+ return status;
+
+ return _cairo_compositor_mask (compositor, &surface->base,
+ op, source, mask,
clip);
}
@@ -1371,8 +1542,15 @@ _cairo_xlib_surface_stroke (void *_surface,
const cairo_clip_t *clip)
{
cairo_xlib_surface_t *surface = _surface;
- return _cairo_compositor_stroke (surface->compositor,
- &surface->base, op, source,
+ const cairo_compositor_t *compositor;
+ cairo_int_status_t status;
+
+ status = get_compositor (&surface, &compositor);
+ if (unlikely (status))
+ return status;
+
+ return _cairo_compositor_stroke (compositor, &surface->base,
+ op, source,
path, style, ctm, ctm_inverse,
tolerance, antialias,
clip);
@@ -1389,8 +1567,15 @@ _cairo_xlib_surface_fill (void *_surface,
const cairo_clip_t *clip)
{
cairo_xlib_surface_t *surface = _surface;
- return _cairo_compositor_fill (surface->compositor,
- &surface->base, op, source,
+ const cairo_compositor_t *compositor;
+ cairo_int_status_t status;
+
+ status = get_compositor (&surface, &compositor);
+ if (unlikely (status))
+ return status;
+
+ return _cairo_compositor_fill (compositor, &surface->base,
+ op, source,
path, fill_rule, tolerance, antialias,
clip);
}
@@ -1405,8 +1590,15 @@ _cairo_xlib_surface_glyphs (void *_surface,
const cairo_clip_t *clip)
{
cairo_xlib_surface_t *surface = _surface;
- return _cairo_compositor_glyphs (surface->compositor,
- &surface->base, op, source,
+ const cairo_compositor_t *compositor;
+ cairo_int_status_t status;
+
+ status = get_compositor (&surface, &compositor);
+ if (unlikely (status))
+ return status;
+
+ return _cairo_compositor_glyphs (compositor, &surface->base,
+ op, source,
glyphs, num_glyphs, scaled_font,
clip);
}
@@ -1418,7 +1610,7 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_default_context_create,
_cairo_xlib_surface_create_similar,
- NULL, //_cairo_xlib_surface_create_similar_image, /* XXX shm */
+ _cairo_xlib_surface_create_similar_shm,
_cairo_xlib_surface_map_to_image,
_cairo_xlib_surface_unmap_image,
@@ -1433,7 +1625,7 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_get_extents,
_cairo_xlib_surface_get_font_options,
- NULL, /* flush */
+ _cairo_xlib_surface_flush,
NULL, /* mark_dirty_rectangle */
_cairo_xlib_surface_paint,
@@ -1539,6 +1731,8 @@ found:
surface->screen = screen;
surface->compositor = display->compositor;
+ surface->shm = NULL;
+ surface->fallback = 0;
surface->drawable = drawable;
surface->owns_pixmap = FALSE;
@@ -1830,6 +2024,7 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
int height)
{
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
+ cairo_status_t status;
if (unlikely (abstract_surface->status))
return;
@@ -1851,6 +2046,12 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
return;
}
+ status = _cairo_surface_begin_modification (abstract_surface);
+ if (unlikely (status)) {
+ _cairo_surface_set_error (abstract_surface, status);
+ return;
+ }
+
surface->width = width;
surface->height = height;
}
@@ -1903,7 +2104,13 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
if (surface->owns_pixmap)
return;
- if (surface->drawable != drawable) {
+ status = _cairo_surface_begin_modification (abstract_surface);
+ if (unlikely (status)) {
+ _cairo_surface_set_error (abstract_surface, status);
+ return;
+ }
+
+ if (surface->drawable == drawable) {
cairo_xlib_display_t *display;
status = _cairo_xlib_display_acquire (surface->base.device, &display);
@@ -1926,6 +2133,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
surface->drawable = drawable;
}
+
surface->width = width;
surface->height = height;
}
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index c1069649..9c0d4b41 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -249,12 +249,11 @@ _cairo_xlib_xcb_surface_glyphs (void *abstract_surface,
}
static cairo_status_t
-_cairo_xlib_xcb_surface_flush (void *abstract_surface)
+_cairo_xlib_xcb_surface_flush (void *abstract_surface, unsigned flags)
{
cairo_xlib_xcb_surface_t *surface = abstract_surface;
/* We have to call cairo_surface_flush() to make sure snapshots are detached */
- cairo_surface_flush (&surface->xcb->base);
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_surface_flush (&surface->xcb->base, flags);
}
static cairo_status_t
diff --git a/src/cairoint.h b/src/cairoint.h
index ff101c15..26a8de14 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1394,7 +1394,7 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
cairo_private void
_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
-cairo_private void
+cairo_private cairo_status_t
_cairo_surface_begin_modification (cairo_surface_t *surface);
cairo_private_no_warn cairo_bool_t
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index aa3f45eb..164ab03c 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -314,12 +314,16 @@ gallium_surface_release_source_image (void *abstract_surface,
}
static cairo_status_t
-gallium_surface_flush (void *abstract_surface)
+gallium_surface_flush (void *abstract_surface,
+ unsigned flags)
{
gallium_surface_t *surface = abstract_surface;
gallium_device_t *device = gallium_device (surface);
cairo_status_t status;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->fallback == NULL) {
device->pipe->flush (device->pipe,
PIPE_FLUSH_RENDER_CACHE,
diff --git a/src/drm/cairo-drm-i915-private.h b/src/drm/cairo-drm-i915-private.h
index 8b2e4228..c750cf4c 100644
--- a/src/drm/cairo-drm-i915-private.h
+++ b/src/drm/cairo-drm-i915-private.h
@@ -1258,7 +1258,7 @@ i915_surface_fallback_flush (i915_surface_t *surface)
cairo_status_t status;
if (unlikely (surface->intel.drm.fallback != NULL))
- return intel_surface_flush (&surface->intel);
+ return intel_surface_flush (&surface->intel, 0);
status = CAIRO_STATUS_SUCCESS;
if (unlikely (surface->deferred_clear))
diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c
index 02001212..c1a04529 100644
--- a/src/drm/cairo-drm-i915-surface.c
+++ b/src/drm/cairo-drm-i915-surface.c
@@ -716,11 +716,15 @@ i915_surface_batch_flush (i915_surface_t *surface)
}
static cairo_status_t
-i915_surface_flush (void *abstract_surface)
+i915_surface_flush (void *abstract_surface,
+ unsigned flags)
{
i915_surface_t *surface = abstract_surface;
cairo_status_t status;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->intel.drm.fallback == NULL) {
if (surface->intel.drm.base.finished) {
/* Forgo flushing on finish as the user cannot access the surface directly. */
@@ -736,7 +740,7 @@ i915_surface_flush (void *abstract_surface)
return i915_surface_batch_flush (surface);
}
- return intel_surface_flush (abstract_surface);
+ return intel_surface_flush (abstract_surface, flags);
}
/* rasterisation */
diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c
index 5465f42a..eed5f5f0 100644
--- a/src/drm/cairo-drm-i965-shader.c
+++ b/src/drm/cairo-drm-i965-shader.c
@@ -415,7 +415,7 @@ i965_shader_acquire_surface (i965_shader_t *shader,
int x;
if (s->intel.drm.fallback != NULL) {
- status = intel_surface_flush (s);
+ status = intel_surface_flush (s, 0);
if (unlikely (status))
return status;
}
@@ -489,7 +489,7 @@ i965_shader_acquire_surface (i965_shader_t *shader,
if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
if (s != shader->target) {
if (s->intel.drm.fallback != NULL) {
- status = intel_surface_flush (s);
+ status = intel_surface_flush (s, 0);
if (unlikely (status))
return status;
}
diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c
index 0891c954..ec7b5954 100644
--- a/src/drm/cairo-drm-i965-surface.c
+++ b/src/drm/cairo-drm-i965-surface.c
@@ -695,11 +695,14 @@ i965_surface_finish (void *abstract_surface)
}
static cairo_status_t
-i965_surface_flush (void *abstract_surface)
+i965_surface_flush (void *abstract_surface, unsigned flags)
{
i965_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->intel.drm.fallback != NULL)
return intel_surface_flush (abstract_surface);
diff --git a/src/drm/cairo-drm-intel-private.h b/src/drm/cairo-drm-intel-private.h
index 7fe3623d..343270a3 100644
--- a/src/drm/cairo-drm-intel-private.h
+++ b/src/drm/cairo-drm-intel-private.h
@@ -394,7 +394,8 @@ cairo_private cairo_surface_t *
intel_surface_map_to_image (void *abstract_surface);
cairo_private cairo_status_t
-intel_surface_flush (void *abstract_surface);
+intel_surface_flush (void *abstract_surface,
+ unsigned flags);
cairo_private cairo_status_t
intel_surface_finish (void *abstract_surface);
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index fe987593..88f5b8f0 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -157,11 +157,14 @@ intel_surface_map_to_image (void *abstract_surface)
}
cairo_status_t
-intel_surface_flush (void *abstract_surface)
+intel_surface_flush (void *abstract_surface, unsigned flags)
{
intel_surface_t *surface = abstract_surface;
cairo_status_t status;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->drm.fallback == NULL)
return CAIRO_STATUS_SUCCESS;
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index 9f46ca15..6dbddaae 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -159,11 +159,15 @@ radeon_surface_map_to_image (radeon_surface_t *surface)
}
static cairo_status_t
-radeon_surface_flush (void *abstract_surface)
+radeon_surface_flush (void *abstract_surface,
+ unsigned flags)
{
radeon_surface_t *surface = abstract_surface;
cairo_status_t status;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->base.fallback == NULL)
return CAIRO_STATUS_SUCCESS;
diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 0d4c5f9b..5353fd57 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -503,11 +503,14 @@ _cairo_win32_display_surface_unmap_image (void *abstract_surf
}
static cairo_status_t
-_cairo_win32_display_surface_flush (void *abstract_surface)
+_cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
{
cairo_win32_display_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ if (flags)
+ return CAIRO_STATUS_SUCCESS;
+
TRACE ((stderr, "%s (surface=%d)\n",
__FUNCTION__, surface->win32.base.unique_id));
if (surface->fallback == NULL)
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 39db674d..c70b0f90 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -236,7 +236,7 @@ copy_boxes (cairo_win32_display_surface_t *dst,
if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
return CAIRO_INT_STATUS_UNSUPPORTED;
- status = _cairo_surface_flush (surface);
+ status = __cairo_surface_flush (surface, 0);
if (status)
return status;
@@ -360,7 +360,7 @@ alpha_blend_boxes (cairo_win32_display_surface_t *dst,
if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
return CAIRO_INT_STATUS_UNSUPPORTED;
- status = _cairo_surface_flush (&src->win32.base);
+ status = __cairo_surface_flush (&src->win32.base, 0);
if (status)
return status;