diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-08-13 01:34:12 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-08-17 13:58:09 +0100 |
commit | 0bfd2acd35547fc2bd0de99cc67d153f0170697d (patch) | |
tree | c59ffaad038cb57115c68505b36aa6bc15d88fa7 | |
parent | 140fafed89508c4685f3a464c9dbe8df769f2411 (diff) |
xlib: Implement SHM fallbacks and fast upload paths
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
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; |