From 59c4fe93ee30c8182ae1a29267b9c08602e2f6c5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 Sep 2009 00:34:37 +0100 Subject: [xlib] Eliminate GC clipping Eradicate the use of clipping with GC. By never using clipping, we never have to worry about retrieving a dirty clip from the GC cache. --- src/cairo-xlib-private.h | 12 +-- src/cairo-xlib-screen.c | 50 ++++------ src/cairo-xlib-surface-private.h | 2 - src/cairo-xlib-surface.c | 197 ++++++++++++++++++--------------------- 4 files changed, 116 insertions(+), 145 deletions(-) diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h index e92bb942..33601e89 100644 --- a/src/cairo-xlib-private.h +++ b/src/cairo-xlib-private.h @@ -85,7 +85,7 @@ struct _cairo_xlib_screen { cairo_font_options_t font_options; GC gc[4]; - int gc_depths; /* 4 x uint8_t, high bit == needs reset */ + int gc_depths; /* 4 x uint8_t */ cairo_array_t visuals; }; @@ -171,15 +171,13 @@ _cairo_xlib_screen_close_display (cairo_xlib_screen_t *info); cairo_private GC _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, - unsigned int depth, - Drawable drawable, - unsigned int *need_reset); + int depth, + Drawable drawable); cairo_private void _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, - unsigned int depth, - GC gc, - cairo_bool_t reset_clip); + int depth, + GC gc); cairo_private cairo_font_options_t * _cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info); diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 38e64af3..800c6d2e 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -380,9 +380,8 @@ _cairo_xlib_screen_get (Display *dpy, #if HAS_ATOMIC_OPS GC _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, - unsigned int depth, - Drawable drawable, - unsigned int *dirty) + int depth, + Drawable drawable) { XGCValues gcv; int i, new, old; @@ -394,13 +393,13 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, if (old == 0) break; - if (((old >> 0) & 0x7f) == depth) + if (((old >> 0) & 0xff) == depth) i = 0; - else if (((old >> 8) & 0x7f) == depth) + else if (((old >> 8) & 0xff) == depth) i = 1; - else if (((old >> 16) & 0x7f) == depth) + else if (((old >> 16) & 0xff) == depth) i = 2; - else if (((old >> 24) & 0x7f) == depth) + else if (((old >> 24) & 0xff) == depth) i = 3; else break; @@ -411,10 +410,6 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, if (likely (gc != NULL)) { (void) _cairo_atomic_ptr_cmpxchg (&info->gc[i], gc, NULL); - - if (old & 0x80 << (8 * i)) - *dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; - return gc; } @@ -426,25 +421,23 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, void _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, - unsigned int depth, - GC gc, - cairo_bool_t reset_clip) + int depth, + GC gc) { int i, old, new; - depth |= reset_clip ? 0x80 : 0; do { do { i = -1; old = info->gc_depths; - if (((old >> 0) & 0x7f) == 0) + if (((old >> 0) & 0xff) == 0) i = 0; - else if (((old >> 8) & 0x7f) == 0) + else if (((old >> 8) & 0xff) == 0) i = 1; - else if (((old >> 16) & 0x7f) == 0) + else if (((old >> 16) & 0xff) == 0) i = 2; - else if (((old >> 24) & 0x7f) == 0) + else if (((old >> 24) & 0xff) == 0) i = 3; else goto out; @@ -468,19 +461,15 @@ out: #else GC _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, - unsigned int depth, - Drawable drawable, - unsigned int *dirty) + int depth, + Drawable drawable) { GC gc = NULL; int i; CAIRO_MUTEX_LOCK (info->mutex); for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { - if (((info->gc_depths >> (8*i)) & 0x7f) == depth) { - if (info->gc_depths & 0x80 << (8*i)) - *dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; - + if (((info->gc_depths >> (8*i)) & 0xff) == depth) { info->gc_depths &= ~(0xff << (8*i)); gc = info->gc[i]; break; @@ -502,17 +491,14 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, void _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, - unsigned int depth, - GC gc, - cairo_bool_t reset_clip) + int depth, + GC gc) { int i; - depth |= reset_clip ? 0x80 : 0; - CAIRO_MUTEX_LOCK (info->mutex); for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { - if (((info->gc_depths >> (8*i)) & 0x7f) == 0) + if (((info->gc_depths >> (8*i)) & 0xff) == 0) break; } diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h index b3cbe045..f8215696 100644 --- a/src/cairo-xlib-surface-private.h +++ b/src/cairo-xlib-surface-private.h @@ -49,7 +49,6 @@ struct _cairo_xlib_surface { cairo_xlib_screen_t *screen; cairo_xlib_hook_t close_display_hook; - GC gc; Drawable drawable; cairo_bool_t owns_pixmap; Visual *visual; @@ -88,7 +87,6 @@ struct _cairo_xlib_surface { Picture dst_picture, src_picture; unsigned int clip_dirty; - cairo_bool_t gc_has_clip_rects; XRectangle embedded_clip_rects[8]; XRectangle *clip_rects; int num_clip_rects; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index b53f4dec..1de6a974 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -83,11 +83,10 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen, int depth); static cairo_status_t -_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface, - cairo_bool_t set_clip); +_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc); static void -_cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface); +_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc); static void _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface); @@ -380,14 +379,6 @@ _cairo_xlib_surface_finish (void *abstract_surface) XRenderFreePicture (surface->dpy, surface->src_picture); } - if (surface->gc != NULL) { - _cairo_xlib_screen_put_gc (surface->screen, - surface->depth, - surface->gc, - surface->gc_has_clip_rects); - surface->gc = NULL; - } - if (surface->clip_rects != surface->embedded_clip_rects) free (surface->clip_rects); @@ -742,8 +733,9 @@ _get_image_surface (cairo_xlib_surface_t *surface, * temporary pixmap */ Pixmap pixmap; + GC gc; - status = _cairo_xlib_surface_ensure_gc (surface, FALSE); + status = _cairo_xlib_surface_get_gc (surface, &gc); if (unlikely (status)) return status; @@ -752,7 +744,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, extents.width, extents.height, surface->depth); if (pixmap) { - XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc, + XCopyArea (surface->dpy, surface->drawable, pixmap, gc, extents.x, extents.y, extents.width, extents.height, 0, 0); @@ -766,10 +758,10 @@ _get_image_surface (cairo_xlib_surface_t *surface, XFreePixmap (surface->dpy, pixmap); } + _cairo_xlib_surface_put_gc (surface, gc); + if (ximage == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - _cairo_xlib_surface_maybe_put_gc (surface); } _swap_ximage_to_native (ximage); @@ -946,21 +938,6 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE; } -static void -_cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface) -{ - surface->gc_has_clip_rects = surface->clip_region != NULL; - if (surface->clip_region != NULL) { - XSetClipRectangles(surface->dpy, surface->gc, - 0, 0, - surface->clip_rects, - surface->num_clip_rects, YXSorted); - } else - XSetClipMask (surface->dpy, surface->gc, None); - - surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; -} - static void _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface) { @@ -976,49 +953,23 @@ _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface) } static cairo_status_t -_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface, - cairo_bool_t set_clip) +_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc) { - - if (surface->gc == NULL) { - surface->gc = _cairo_xlib_screen_get_gc (surface->screen, - surface->depth, - surface->drawable, - &surface->clip_dirty); - if (unlikely (surface->gc == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - surface->gc_has_clip_rects = - surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; - } - - if (set_clip) { - if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC) - _cairo_xlib_surface_set_gc_clip_rects (surface); - } else { - if (surface->gc_has_clip_rects) { - surface->gc_has_clip_rects = FALSE; - XSetClipMask (surface->dpy, surface->gc, None); - - surface->clip_dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; - } - } + *gc = _cairo_xlib_screen_get_gc (surface->screen, + surface->depth, + surface->drawable); + if (unlikely (*gc == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_SUCCESS; } static void -_cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface) +_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc) { - /* return the GC back to the common pool if clean */ - if (surface->gc_has_clip_rects) - return; - _cairo_xlib_screen_put_gc (surface->screen, surface->depth, - surface->gc, - FALSE); - surface->gc = NULL; + gc); } static cairo_status_t @@ -1036,6 +987,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst; cairo_status_t status; cairo_bool_t own_data; + GC gc; _pixman_format_to_masks (image->pixman_format, &image_masks); @@ -1173,16 +1125,15 @@ _draw_image_surface (cairo_xlib_surface_t *surface, } } - /* XXX set clip? */ - status = _cairo_xlib_surface_ensure_gc (surface, FALSE); + status = _cairo_xlib_surface_get_gc (surface, &gc); if (unlikely (status)) goto BAIL; - XPutImage (surface->dpy, surface->drawable, surface->gc, + XPutImage (surface->dpy, surface->drawable, gc, &ximage, src_x, src_y, dst_x, dst_y, width, height); - _cairo_xlib_surface_maybe_put_gc (surface); + _cairo_xlib_surface_put_gc (surface, gc); BAIL: if (own_data) @@ -2136,6 +2087,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, cairo_bool_t is_integer_translation; cairo_bool_t needs_alpha_composite; cairo_content_t src_content; + GC gc; if (mask_pattern != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return UNSUPPORTED ("no support for masks"); @@ -2183,10 +2135,6 @@ _cairo_xlib_surface_composite (cairo_operator_t op, goto BAIL; } - status = _cairo_xlib_surface_set_clip_region (dst, clip_region); - if (unlikely (status)) - goto BAIL; - switch (operation) { case DO_RENDER: @@ -2196,6 +2144,10 @@ _cairo_xlib_surface_composite (cairo_operator_t op, if (unlikely (status)) goto BAIL; + status = _cairo_xlib_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + goto BAIL; + _cairo_xlib_surface_ensure_dst_picture (dst); if (mask) { status = _cairo_xlib_surface_set_attributes (mask, &mask_attr, @@ -2231,7 +2183,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, break; case DO_XCOPYAREA: - status = _cairo_xlib_surface_ensure_gc (dst, TRUE); + status = _cairo_xlib_surface_get_gc (dst, &gc); if (unlikely (status)) goto BAIL; @@ -2240,16 +2192,38 @@ _cairo_xlib_surface_composite (cairo_operator_t op, /* This is a pre-condition for DO_XCOPYAREA. */ assert (is_integer_translation); - XCopyArea (dst->dpy, - src->drawable, - dst->drawable, - dst->gc, - src_x + src_attr.x_offset + itx, - src_y + src_attr.y_offset + ity, - width, height, - dst_x, dst_y); + if (clip_region == NULL) { + XCopyArea (dst->dpy, + src->drawable, + dst->drawable, + gc, + src_x + src_attr.x_offset + itx, + src_y + src_attr.y_offset + ity, + width, height, + dst_x, dst_y); + } else { + int n, num_rects; + + src_x += src_attr.x_offset + itx - dst_x; + src_y += src_attr.y_offset + ity - dst_y; + + num_rects = cairo_region_num_rectangles (clip_region); + for (n = 0; n < num_rects; n++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, n, &rect); + XCopyArea (dst->dpy, + src->drawable, + dst->drawable, + gc, + rect.x + src_x, + rect.y + src_y, + rect.width, rect.height, + rect.x, rect.y); + } + } - _cairo_xlib_surface_maybe_put_gc (dst); + _cairo_xlib_surface_put_gc (dst, gc); break; case DO_XTILE: @@ -2261,23 +2235,42 @@ _cairo_xlib_surface_composite (cairo_operator_t op, * _recategorize_composite_operation. */ - status = _cairo_xlib_surface_ensure_gc (dst, TRUE); + status = _cairo_xlib_surface_get_gc (dst, &gc); if (unlikely (status)) goto BAIL; + is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity); /* This is a pre-condition for DO_XTILE. */ assert (is_integer_translation); - XSetTSOrigin (dst->dpy, dst->gc, + XSetTSOrigin (dst->dpy, gc, - (itx + src_attr.x_offset), - (ity + src_attr.y_offset)); - XSetTile (dst->dpy, dst->gc, src->drawable); - XSetFillStyle (dst->dpy, dst->gc, FillTiled); + XSetTile (dst->dpy, gc, src->drawable); + XSetFillStyle (dst->dpy, gc, FillTiled); + + if (clip_region == NULL) { + XFillRectangle (dst->dpy, dst->drawable, gc, + dst_x, dst_y, width, height); + } else { + int n, num_rects; - XFillRectangle (dst->dpy, dst->drawable, dst->gc, - dst_x, dst_y, width, height); + src_x += src_attr.x_offset + itx; + src_y += src_attr.y_offset + ity; - _cairo_xlib_surface_maybe_put_gc (dst); + num_rects = cairo_region_num_rectangles (clip_region); + for (n = 0; n < num_rects; n++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, n, &rect); + rect.x -= dst_x; + rect.y -= dst_y; + XFillRectangle (dst->dpy, dst->drawable, gc, + rect.x, rect.y, rect.width, rect.height); + } + } + + _cairo_xlib_surface_put_gc (dst, gc); break; case DO_UNSUPPORTED: @@ -2316,11 +2309,12 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, cairo_solid_pattern_t solid; cairo_surface_t *solid_surface = NULL; cairo_surface_attributes_t attrs; + GC gc; int i; _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR); - status = _cairo_xlib_surface_ensure_gc (surface, FALSE); + status = _cairo_xlib_surface_get_gc (surface, &gc); if (unlikely (status)) return status; @@ -2332,25 +2326,27 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, CAIRO_PATTERN_ACQUIRE_NONE, &solid_surface, &attrs); - if (unlikely (status)) - return status; + if (unlikely (status)) { + _cairo_xlib_surface_put_gc (surface, gc); + return status; + } assert (_cairo_surface_is_xlib (solid_surface)); - XSetTSOrigin (surface->dpy, surface->gc, + XSetTSOrigin (surface->dpy, gc, - (surface->base.device_transform.x0 + attrs.x_offset), - (surface->base.device_transform.y0 + attrs.y_offset)); - XSetTile (surface->dpy, surface->gc, + XSetTile (surface->dpy, gc, ((cairo_xlib_surface_t *) solid_surface)->drawable); - XSetFillStyle (surface->dpy, surface->gc, FillTiled); + XSetFillStyle (surface->dpy, gc, FillTiled); for (i = 0; i < num_rects; i++) { - XFillRectangle (surface->dpy, surface->drawable, surface->gc, + XFillRectangle (surface->dpy, surface->drawable, gc, rects[i].x, rects[i].y, rects[i].width, rects[i].height); } - _cairo_xlib_surface_maybe_put_gc (surface); + _cairo_xlib_surface_put_gc (surface, gc); _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs); @@ -2859,11 +2855,6 @@ _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data) surface->drawable = None; surface->owns_pixmap = FALSE; } - - if (surface->gc != NULL) { - XFreeGC (dpy, surface->gc); - surface->gc = NULL; - } } static cairo_surface_t * @@ -2947,7 +2938,6 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen, surface->screen = _cairo_xlib_screen_reference (screen); surface->display = screen->display; - surface->gc = NULL; surface->drawable = drawable; surface->owns_pixmap = FALSE; surface->use_pixmap = 0; @@ -2979,7 +2969,6 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen, surface->xtransform = identity; surface->clip_region = NULL; - surface->gc_has_clip_rects = FALSE; surface->clip_rects = surface->embedded_clip_rects; surface->num_clip_rects = 0; surface->clip_dirty = 0; -- cgit v1.2.3