diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-01-13 17:20:24 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-01-13 18:37:08 +0000 |
commit | 7012334ebb424b619312e1fa397cc3b8a3ffd770 (patch) | |
tree | 8cbf002161b16ca186651734b4e188aab9b6d97a | |
parent | 503b6b9e2ea65805a77d527c00cf242ec86d479b (diff) | |
download | cairo-7012334ebb424b619312e1fa397cc3b8a3ffd770.tar.gz |
xlib: Handle lack of XRenderFillRectangles
Remember to check for a supported render version before making a
FillRectangle request, and fallback to the core protocol where possible
instead.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/cairo-xlib-core-compositor.c | 79 | ||||
-rw-r--r-- | src/cairo-xlib-private.h | 15 | ||||
-rw-r--r-- | src/cairo-xlib-render-compositor.c | 30 | ||||
-rw-r--r-- | src/cairo-xlib-source.c | 70 |
4 files changed, 157 insertions, 37 deletions
diff --git a/src/cairo-xlib-core-compositor.c b/src/cairo-xlib-core-compositor.c index aaa71d52c..9398079b4 100644 --- a/src/cairo-xlib-core-compositor.c +++ b/src/cairo-xlib-core-compositor.c @@ -83,6 +83,7 @@ struct _fill_box { Display *dpy; Drawable drawable; GC gc; + //cairo_surface_t *dither = NULL; }; static cairo_bool_t fill_box (cairo_box_t *box, void *closure) @@ -128,27 +129,25 @@ color_to_pixel (cairo_xlib_surface_t *dst, } static cairo_int_status_t -fill_boxes (cairo_xlib_surface_t *dst, - const cairo_color_t *color, - cairo_boxes_t *boxes) +_fill_box_init (struct _fill_box *fb, + cairo_xlib_surface_t *dst, + const cairo_color_t *color) { - cairo_surface_t *dither = NULL; - cairo_status_t status; - struct _fill_box fb; + cairo_int_status_t status; - status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb.gc); + status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc); if (unlikely (status)) return status; - fb.dpy = dst->display->display; - fb.drawable = dst->drawable; + fb->dpy = dst->display->display; + fb->drawable = dst->drawable; if (dst->visual && dst->visual->class != TrueColor && 0) { +#if 0 cairo_solid_pattern_t solid; cairo_surface_attributes_t attrs; _cairo_pattern_init_solid (&solid, color); -#if 0 status = _cairo_pattern_acquire_surface (&solid.base, &dst->base, 0, 0, ARRAY_LENGTH (dither_pattern[0]), @@ -160,27 +159,70 @@ fill_boxes (cairo_xlib_surface_t *dst, _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc); return status; } -#endif - XSetTSOrigin (fb.dpy, fb.gc, + XSetTSOrigin (fb->dpy, fb->gc, - (dst->base.device_transform.x0 + attrs.x_offset), - (dst->base.device_transform.y0 + attrs.y_offset)); - XSetTile (fb.dpy, fb.gc, ((cairo_xlib_surface_t *) dither)->drawable); + XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable); +#endif } else { XGCValues gcv; gcv.foreground = color_to_pixel (dst, color); gcv.fill_style = FillSolid; - XChangeGC (fb.dpy, fb.gc, GCFillStyle | GCForeground, &gcv); + XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv); } + return CAIRO_INT_STATUS_SUCCESS; +} + +static void +_fill_box_fini (struct _fill_box *fb, + cairo_xlib_surface_t *dst) +{ + _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc); + //cairo_surface_destroy (fb->dither); +} + +cairo_int_status_t +_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + cairo_int_status_t status; + struct _fill_box fb; + + status = _fill_box_init (&fb, dst, color); + if (unlikely (status)) + return status; + _cairo_boxes_for_each_box (boxes, fill_box, &fb); - _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc); + _fill_box_fini (&fb, dst); + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + int num_rects, + cairo_rectangle_int_t *rects) +{ + cairo_int_status_t status; + struct _fill_box fb; + int i; + + status = _fill_box_init (&fb, dst, color); + if (unlikely (status)) + return status; - cairo_surface_destroy (dither); + for (i = 0; i < num_rects; i++) + XFillRectangle (fb.dpy, fb.drawable, fb.gc, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height); + _fill_box_fini (&fb, dst); return CAIRO_STATUS_SUCCESS; } @@ -495,9 +537,8 @@ draw_boxes (cairo_composite_rectangles_t *extents, return status; if (src->type == CAIRO_PATTERN_TYPE_SOLID) { - status = fill_boxes (dst, - &((cairo_solid_pattern_t *) src)->color, - boxes); + status = _cairo_xlib_core_fill_boxes + (dst, &((cairo_solid_pattern_t *) src)->color, boxes); } else { status = upload_image_inplace (dst, src, boxes); if (status == CAIRO_INT_STATUS_UNSUPPORTED) diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h index 000798a6d..4fd725f93 100644 --- a/src/cairo-xlib-private.h +++ b/src/cairo-xlib-private.h @@ -171,6 +171,7 @@ struct _cairo_xlib_surface { cairo_surface_t base; Picture picture; + Drawable drawable; const cairo_compositor_t *compositor; cairo_surface_t *shm; @@ -181,7 +182,6 @@ struct _cairo_xlib_surface { cairo_list_t link; Display *dpy; /* only valid between acquire/release */ - Drawable drawable; cairo_bool_t owns_pixmap; Visual *visual; @@ -203,6 +203,7 @@ struct _cairo_xlib_surface { cairo_surface_t base; Picture picture; + Pixmap pixmap; Display *dpy; unsigned int filter:3; @@ -395,6 +396,17 @@ _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst, return dst->screen == src->screen; } +cairo_private cairo_int_status_t +_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + cairo_boxes_t *boxes); + +cairo_private cairo_int_status_t +_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + int num_rects, + cairo_rectangle_int_t *rects); + static inline void _cairo_xlib_surface_put_gc (cairo_xlib_display_t *display, cairo_xlib_surface_t *surface, @@ -453,5 +465,4 @@ _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 */ diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c index a5f750eaa..3540d1fda 100644 --- a/src/cairo-xlib-render-compositor.c +++ b/src/cairo-xlib-render-compositor.c @@ -608,14 +608,23 @@ fill_rectangles (void *abstract_surface, //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable)); + if (fill_reduces_to_source (op, color, dst)) + op = CAIRO_OPERATOR_SOURCE; + + if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) { + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (op == CAIRO_OPERATOR_SOURCE) + status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects); + return status; + } + render_color.red = color->red_short; render_color.green = color->green_short; render_color.blue = color->blue_short; render_color.alpha = color->alpha_short; - if (fill_reduces_to_source (op, color, dst)) - op = CAIRO_OPERATOR_SOURCE; - _cairo_xlib_surface_ensure_picture (dst); if (num_rects == 1) { /* Take advantage of the protocol compaction that libXrender performs @@ -665,14 +674,23 @@ fill_boxes (void *abstract_surface, cairo_xlib_surface_t *dst = abstract_surface; XRenderColor render_color; + if (fill_reduces_to_source (op, color, dst)) + op = CAIRO_OPERATOR_SOURCE; + + if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) { + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (op == CAIRO_OPERATOR_SOURCE) + status = _cairo_xlib_core_fill_boxes (dst, color, boxes); + return status; + } + render_color.red = color->red_short; render_color.green = color->green_short; render_color.blue = color->blue_short; render_color.alpha = color->alpha_short; - if (fill_reduces_to_source (op, color, dst)) - op = CAIRO_OPERATOR_SOURCE; - _cairo_xlib_surface_ensure_picture (dst); if (boxes->num_boxes == 1) { int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x); diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c index 0689d8299..d0d6c0edd 100644 --- a/src/cairo-xlib-source.c +++ b/src/cairo-xlib-source.c @@ -71,6 +71,8 @@ _cairo_xlib_source_finish (void *abstract_surface) cairo_xlib_source_t *source = abstract_surface; XRenderFreePicture (source->dpy, source->picture); + if (source->pixmap) + XFreePixmap (source->dpy, source->pixmap); return CAIRO_STATUS_SUCCESS; } @@ -86,6 +88,8 @@ _cairo_xlib_proxy_finish (void *abstract_surface) cairo_xlib_proxy_t *proxy = abstract_surface; XRenderFreePicture (proxy->source.dpy, proxy->source.picture); + if (proxy->source.pixmap) + XFreePixmap (proxy->source.dpy, proxy->source.pixmap); _cairo_xlib_shm_surface_mark_active (proxy->owner); cairo_surface_destroy (proxy->owner); return CAIRO_STATUS_SUCCESS; @@ -98,7 +102,7 @@ static const cairo_surface_backend_t cairo_xlib_proxy_backend = { }; static cairo_surface_t * -source (cairo_xlib_surface_t *dst, Picture picture) +source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap) { cairo_xlib_source_t *source; @@ -108,6 +112,8 @@ source (cairo_xlib_surface_t *dst, Picture picture) source = malloc (sizeof (cairo_image_surface_t)); if (unlikely (source == NULL)) { XRenderFreePicture (dst->display->display, picture); + if (pixmap) + XFreePixmap (dst->display->display, pixmap); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } @@ -118,6 +124,7 @@ source (cairo_xlib_surface_t *dst, Picture picture) /* The source exists only within an operation */ source->picture = picture; + source->pixmap = pixmap; source->dpy = dst->display->display; return &source->base; @@ -433,22 +440,65 @@ gradient_source (cairo_xlib_surface_t *dst, return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y); } - return source (dst, picture); + return source (dst, picture, None); } static cairo_surface_t * color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color) { - XRenderColor xrender_color; + Display *dpy = dst->display->display; + XRenderColor xcolor; + Picture picture; + Pixmap pixmap = None; + + xcolor.red = color->red_short; + xcolor.green = color->green_short; + xcolor.blue = color->blue_short; + xcolor.alpha = color->alpha_short; + + if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) { + picture = XRenderCreateSolidFill (dpy, &xcolor); + } else { + XRenderPictureAttributes pa; + int mask = 0; + + pa.repeat = RepeatNormal; + mask |= CPRepeat; - xrender_color.red = color->red_short; - xrender_color.green = color->green_short; - xrender_color.blue = color->blue_short; - xrender_color.alpha = color->alpha_short; + pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32); + picture = XRenderCreatePicture (dpy, pixmap, + _cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32), + mask, &pa); + + if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) { + XRectangle r = { 0, 0, 1, 1}; + XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1); + } else { + XGCValues gcv; + GC gc; + + gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen, + 32, pixmap); + if (unlikely (gc == NULL)) { + XFreePixmap (dpy, pixmap); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + gcv.foreground = 0; + gcv.foreground |= color->alpha_short >> 8 << 24; + gcv.foreground |= color->red_short >> 8 << 16; + gcv.foreground |= color->green_short >> 8 << 8; + gcv.foreground |= color->blue_short >> 8 << 0; + gcv.fill_style = FillSolid; + + XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv); + XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1); + + _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc); + } + } - return source (dst, - XRenderCreateSolidFill (dst->display->display, - &xrender_color)); + return source (dst, picture, pixmap); } static cairo_surface_t * |