summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-surface.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-01-02 22:27:55 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2013-01-03 12:28:33 +0000
commit74941f822015cc50cd8477d0cf97f1a70dbff60b (patch)
tree432939bedbcfc8d61c6ac8b1432eec96435d4325 /src/cairo-xlib-surface.c
parentbf2a04c5ab91c93d4d188afd030b3004c67a180f (diff)
downloadcairo-74941f822015cc50cd8477d0cf97f1a70dbff60b.tar.gz
xlib: Use SHM transport for ordinary image uploads
In theory this should just save a single copy, however PutImage will break up requests into a series of scanlines requests which is less efficient than the single-shot transfer provided by ShmPutImage. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/cairo-xlib-surface.c')
-rw-r--r--src/cairo-xlib-surface.c100
1 files changed, 77 insertions, 23 deletions
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index e9e647a19..dbc677eb7 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1090,9 +1090,10 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
XImage ximage;
cairo_format_masks_t image_masks;
int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
+ cairo_surface_t *shm_image = NULL;
pixman_image_t *pixman_image = NULL;
cairo_status_t status;
- cairo_bool_t own_data;
+ cairo_bool_t own_data = FALSE;
cairo_bool_t is_rgb_image;
GC gc;
@@ -1127,9 +1128,41 @@ _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;
- if (image->base.device == surface->base.device)
+ if (image->base.device != surface->base.device) {
+ /* If PutImage will break the image up into chunks, prefer to
+ * send it all in one pass with ShmPutImage. For larger images,
+ * it is further advantageous to reduce the number of copies,
+ * albeit at the expense of more SHM bookkeeping.
+ */
+ int max_request_size = XExtendedMaxRequestSize (display->display);
+ if (max_request_size == 0)
+ max_request_size = XMaxRequestSize (display->display);
+ if (max_request_size > 8192)
+ max_request_size = 8192;
+ if (image->stride * image->height > max_request_size) {
+ shm_image = _cairo_xlib_surface_create_shm__image (surface,
+ image->pixman_format,
+ image->width,
+ image->height);
+ if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+ cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+ if (clone->stride == image->stride) {
+ memcpy (clone->data, image->data, clone->stride * clone->height);
+ } else {
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, clone->pixman_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ image->width, image->height);
+ }
+ ximage.obdata = _cairo_xlib_shm_surface_get_obdata (shm_image);
+ ximage.data = (char *)clone->data;
+ ximage.bytes_per_line = clone->stride;
+ }
+ }
+ } else
ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base);
- own_data = FALSE;
ret = XInitImage (&ximage);
assert (ret != 0);
@@ -1147,29 +1180,48 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
assert (ret);
- own_data = FALSE;
-
- pixman_image = pixman_image_create_bits (intermediate_format,
- width, height, NULL, 0);
- if (pixman_image == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
+ shm_image = _cairo_xlib_surface_create_shm__image (surface,
+ intermediate_format,
+ width, height);
+ if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+ cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image,
+ NULL,
+ clone->pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+
+ ximage.data = (char *) clone->data;
+ ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&clone->base);
+ ximage.bytes_per_line = clone->stride;
+ } else {
+ pixman_image = pixman_image_create_bits (intermediate_format,
+ width, height, NULL, 0);
+ if (pixman_image == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
- pixman_image_composite32 (PIXMAN_OP_SRC,
- image->pixman_image,
- NULL,
- pixman_image,
- src_x, src_y,
- 0, 0,
- 0, 0,
- width, height);
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image,
+ NULL,
+ pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+
+ ximage.data = (char *) pixman_image_get_data (pixman_image);
+ ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
+ }
ximage.width = width;
ximage.height = height;
ximage.bits_per_pixel = image_masks.bpp;
- ximage.data = (char *) pixman_image_get_data (pixman_image);
- ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
ret = XInitImage (&ximage);
assert (ret != 0);
@@ -1195,7 +1247,6 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
ximage.bytes_per_line = stride;
ximage.data = _cairo_malloc_ab (stride, ximage.height);
if (unlikely (ximage.data == NULL)) {
- own_data = FALSE;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
@@ -1296,7 +1347,8 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
if (ximage.obdata)
XShmPutImage (display->display, surface->drawable, gc, &ximage,
- src_x, src_y, dst_x, dst_y, width, height, TRUE);
+ src_x, src_y, dst_x, dst_y, width, height,
+ shm_image == NULL);
else
XPutImage (display->display, surface->drawable, gc, &ximage,
src_x, src_y, dst_x, dst_y, width, height);
@@ -1308,6 +1360,8 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
if (own_data)
free (ximage.data);
+ if (shm_image)
+ cairo_surface_destroy (shm_image);
if (pixman_image)
pixman_image_unref (pixman_image);