summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-06-19 10:26:05 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2010-06-19 10:52:52 +0100
commitb322b2e61984c2e9e00fb44343ebe5e423246445 (patch)
tree8ffeacfb0cd1bd3d1f7ea68efe1d83830f101458
parentc3eb95bf6670bbc06ef908481da95f3504c7dc4d (diff)
xlib: Perform image uploads inplace.
Under the restrictive conditions where we are doing an untransformed contained upload of an image into a matching surface, perform it in place. The drivers will attempt to stream such uploads efficiently, far more so than our code.
-rw-r--r--src/cairo-xlib-surface.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index b5ef703d..0202494f 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -52,6 +52,8 @@
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-scaled-font-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
#include "cairo-region-private.h"
#include <X11/Xutil.h> /* for XDestroyImage */
@@ -2272,6 +2274,105 @@ _cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_display_t *displa
}
static cairo_int_status_t
+_cairo_xlib_surface_upload(cairo_xlib_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_region_t *clip_region)
+{
+ cairo_image_surface_t *image;
+ cairo_rectangle_int_t extents;
+ cairo_status_t status;
+ int tx, ty;
+
+ if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ image = (cairo_image_surface_t *) ((cairo_surface_pattern_t *) pattern)->surface;
+ if (image->base.type != CAIRO_SURFACE_TYPE_IMAGE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (! (op == CAIRO_OPERATOR_SOURCE ||
+ (op == CAIRO_OPERATOR_OVER &&
+ (image->base.content & CAIRO_CONTENT_ALPHA) == 0)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (image->base.backend->type != CAIRO_SURFACE_TYPE_IMAGE) {
+ if (image->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ image = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) image)->target;
+ extents.x = extents.y = 0;
+ extents.width = image->width;
+ extents.height = image->height;
+ } else if (image->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) image;
+ image = (cairo_image_surface_t *) sub->target;
+ src_x += sub->extents.x;
+ src_y += sub->extents.y;
+ extents = sub->extents;
+ } else {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ } else {
+ extents.x = extents.y = 0;
+ extents.width = image->width;
+ extents.height = image->height;
+ }
+
+ if (image->format == CAIRO_FORMAT_INVALID)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (image->depth != surface->depth)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (! _cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* XXX for EXTEND_NONE perform unbounded fixups? */
+ if (src_x + tx < extents.x ||
+ src_y + ty < extents.y ||
+ src_x + tx + width > (unsigned) extents.width ||
+ src_y + ty + height > (unsigned) extents.height)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = cairo_device_acquire (surface->base.device);
+ if (unlikely (status))
+ return status;
+
+ if (clip_region != NULL) {
+ int n, num_rect;
+
+ src_x -= dst_x;
+ src_y -= dst_y;
+
+ num_rect = cairo_region_num_rectangles (clip_region);
+ for (n = 0; n < num_rect; n++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, n, &rect);
+ status = _draw_image_surface (surface, image,
+ rect.x + src_x, rect.x + src_y,
+ rect.width, rect.height,
+ rect.x, rect.y);
+ if (unlikely (status))
+ break;
+ }
+ } else {
+ status = _draw_image_surface (surface, image,
+ src_x, src_y,
+ width, height,
+ dst_x, dst_y);
+ }
+
+ cairo_device_release (surface->base.device);
+
+ return status;
+}
+
+static cairo_int_status_t
_cairo_xlib_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
const cairo_pattern_t *mask_pattern,
@@ -2307,6 +2408,17 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
+ if (mask_pattern == NULL) {
+ /* Can we do a simple upload in-place? */
+ status = _cairo_xlib_surface_upload(dst, op, src_pattern,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
+ clip_region);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
status = _cairo_xlib_display_acquire (dst-> base.device, &display);
if (unlikely (status))
return status;