diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-01-02 22:27:55 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-01-03 12:28:33 +0000 |
commit | 74941f822015cc50cd8477d0cf97f1a70dbff60b (patch) | |
tree | 432939bedbcfc8d61c6ac8b1432eec96435d4325 /src/cairo-xlib-surface.c | |
parent | bf2a04c5ab91c93d4d188afd030b3004c67a180f (diff) | |
download | cairo-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.c | 100 |
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); |