xlib: Implement SHM fallbacks and fast upload paths

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2012-08-13 01:34:12 +01:00
parent 140fafed89
commit 0bfd2acd35
41 changed files with 2517 additions and 238 deletions

View file

@ -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])
])

View file

@ -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)

View file

@ -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;
}

View file

@ -95,7 +95,6 @@ _cairo_damage_add_boxes(cairo_damage_t *damage,
if (damage->status)
return damage;
damage->dirty += count;
n = count;

View file

@ -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);

View file

@ -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;

View file

@ -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 *
@ -776,16 +786,6 @@ _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
}
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,
@ -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,

View file

@ -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;
}
/**

View file

@ -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);

View file

@ -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,

View file

@ -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 */

359
src/cairo-mempool.c Normal file
View file

@ -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);
}

View file

@ -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 */

View file

@ -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);

View file

@ -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,

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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;

View file

@ -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

View file

@ -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))

View file

@ -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)

View file

@ -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.
*/

View file

@ -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 */

View file

@ -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 */

View file

@ -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"
@ -124,15 +125,141 @@ set_clip_region (void *_surface,
return CAIRO_STATUS_SUCCESS;
}
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;

View file

@ -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,

1119
src/cairo-xlib-surface-shm.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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))

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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;