[cairo] Re: cairo gradients
David Reveman
davidr at novell.com
Thu Jun 15 09:25:19 PDT 2006
On Wed, 2006-06-14 at 03:31 -0700, Carl Worth wrote:
> On Wed, 19 Apr 2006 13:22:23 +0200, David Reveman wrote:
> >
> > I'm attaching my current patch for server-side gradients, it checks if
> > Xorg version is greater than 7.0 for server-side gradients to be used.
> > Except for the undefined behavior, gradients works fine in Xgl. However,
> > I'm not sure they work correctly in the non-xgl branch of Xorg.
> > Server-side gradients are a big performance improvement so it would be
> > nice if they can be enabled when they work correctly.
> >
>
> I though I'd try throwing this patch in before the 1.1.8 snapshot, but
> it didn't go so well.
>
> Specifically, all I could get from my (non-xgl and non-EXA) Xorg
> server is X server crashes.
>
> It's possible I merged things wrong, so I'm definitely not going to
> push out a patch that I've never successfully tested. Meanwhile, the
> check for X.org VendorRelease <= 70000000 appears to be insufficient
> for guaranteeing functional gradients in the X server.
Yes, VendorRelease <= 70000000 is not good enough as I don't think it
got fixed for 7.1. xgl-0-0-1 branch contains appropriate gradient
updates.
>
> I've attached the patch I was testing so someone can look at my merge
> to see if I didn't totally botch it. After applying this, simply doing
> "make check" in cairo leads to a server crash after just a few tests.
>
> If someone were interested in tracking down the failure more precisely
> so we could get the X server bug fixed, that would be particularly
> useful.
>
> -Carl
>
> plain text document attachment
> (0001-xlib-Use-server-side-gradients-when-available.txt)
> >From nobody Mon Sep 17 00:00:00 2001
> From: David Reveman <davidr at novell.com>
> Date: Tue, 13 Jun 2006 17:12:05 -0700
> Subject: [PATCH] xlib: Use server-side gradients when available.
>
> No server-side gradients are used if the X server VendorName is
> XFree86 or if it is X.Org with a VendorRelease of 70000000 (7.0)
> or less, (since those X servers are known to have bugs with
> gradients).
>
> ---
>
> src/cairo-xlib-surface.c | 255 ++++++++++++++++++++++++++++++++++++++++++----
> 1 files changed, 235 insertions(+), 20 deletions(-)
>
> eb23970a4c68eb6e92c361fda731bbd186b07666
> diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
> index ad00416..046b81e 100644
> --- a/src/cairo-xlib-surface.c
> +++ b/src/cairo-xlib-surface.c
> @@ -73,6 +73,16 @@ _cairo_xlib_surface_show_glyphs (void
> int num_glyphs,
> cairo_scaled_font_t *scaled_font);
>
> +static cairo_surface_t *
> +_cairo_xlib_surface_create_internal (Display *dpy,
> + Drawable drawable,
> + Screen *screen,
> + Visual *visual,
> + XRenderPictFormat *format,
> + int width,
> + int height,
> + int depth);
> +
> /*
> * Instead of taking two round trips for each blending request,
> * assume that if a particular drawable fails GetImage that it will
> @@ -115,6 +125,12 @@ struct _cairo_xlib_surface {
> */
> cairo_bool_t buggy_repeat;
>
> + /* TRUE if the server has a bug with gradient pictures
> + *
> + * xorg and xfree servers currently have this bug.
> + */
> + cairo_bool_t buggy_gradients;
> +
> int width;
> int height;
> int depth;
> @@ -149,6 +165,8 @@ #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(
>
> #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
> #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
> +#define CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
> +#define CAIRO_SURFACE_RENDER_HAS_GRADIENTS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
>
> static cairo_bool_t cairo_xlib_render_disabled = FALSE;
>
> @@ -1005,14 +1023,23 @@ _cairo_xlib_surface_set_attributes (cair
>
> switch (attributes->extend) {
> case CAIRO_EXTEND_NONE:
> - _cairo_xlib_surface_set_repeat (surface, 0);
> + _cairo_xlib_surface_set_repeat (surface, RepeatNone);
> break;
> case CAIRO_EXTEND_REPEAT:
> - _cairo_xlib_surface_set_repeat (surface, 1);
> + _cairo_xlib_surface_set_repeat (surface, RepeatNormal);
> break;
> case CAIRO_EXTEND_REFLECT:
> + if (!CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT (surface))
> + return CAIRO_INT_STATUS_UNSUPPORTED;
> +
> + _cairo_xlib_surface_set_repeat (surface, RepeatReflect);
> + break;
> case CAIRO_EXTEND_PAD:
> - return CAIRO_INT_STATUS_UNSUPPORTED;
> + if (!CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT (surface))
> + return CAIRO_INT_STATUS_UNSUPPORTED;
> +
> + _cairo_xlib_surface_set_repeat (surface, RepeatPad);
> + break;
> }
>
> status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
> @@ -1253,6 +1280,193 @@ _render_operator (cairo_operator_t op)
> }
>
> static cairo_int_status_t
> +_cairo_xlib_pattern_acquire_surface (cairo_pattern_t *pattern,
> + cairo_xlib_surface_t *dst,
> + int x,
> + int y,
> + unsigned int width,
> + unsigned int height,
> + cairo_xlib_surface_t **surface_out,
> + cairo_surface_attributes_t *attributes)
> +{
> + switch (pattern->type) {
> + case CAIRO_PATTERN_TYPE_LINEAR:
> + case CAIRO_PATTERN_TYPE_RADIAL: {
> + cairo_gradient_pattern_t *gradient =
> + (cairo_gradient_pattern_t *) pattern;
> + cairo_xlib_surface_t *surface;
> + XFixed *stops;
> + XRenderColor *colors;
> + XRenderPictFormat *format;
> + Picture picture;
> + int i;
> +
> + if (!CAIRO_SURFACE_RENDER_HAS_GRADIENTS (dst))
> + break;
> +
> + if (dst->buggy_gradients)
> + break;
> +
> + if (gradient->n_stops < 2)
> + break;
> +
> + stops = malloc ((sizeof (XFixed) + sizeof (XRenderColor)) *
> + gradient->n_stops);
> + if (!stops)
> + return CAIRO_STATUS_NO_MEMORY;
> +
> + colors = (XRenderColor *) (stops + gradient->n_stops);
> +
> + for (i = 0; i < gradient->n_stops; i++)
> + {
> + stops[i] = gradient->stops[i].x;
> +
> + colors[i].red = gradient->stops[i].color.red;
> + colors[i].green = gradient->stops[i].color.green;
> + colors[i].blue = gradient->stops[i].color.blue;
> + colors[i].alpha = gradient->stops[i].color.alpha;
> + }
> +
> + /* For some weird reason the X server is sometimes getting
> + CreateGradient requests with bad length. So far I've only seen
> + XRenderCreateLinearGradient request with 4 stops sometime end up
> + with length field matching 0 stops at the server side. I've looked
> + at the libXrender code and I can't see anything that could
> + cause this behavior. However, for some reason having a XSync call
> + here seems to avoid the issue so I'll keep it here until it's
> + solved. */
> + XSync (dst->dpy, False);
> +
> + if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR)
> + {
> + cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
> +
> + picture = XRenderCreateLinearGradient (dst->dpy,
> + (XLinearGradient *)
> + &grad->gradient,
> + stops, colors,
> + gradient->n_stops);
> + }
> + else
> + {
> + cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
> +
> + picture = XRenderCreateRadialGradient (dst->dpy,
> + (XRadialGradient *)
> + &grad->gradient,
> + stops, colors,
> + gradient->n_stops);
> + }
> +
> + if (!picture)
> + {
> + free (stops);
> + break;
> + }
> +
> + format = XRenderFindStandardFormat (dst->dpy, PictStandardARGB32);
> +
> + surface = (cairo_xlib_surface_t *)
> + _cairo_xlib_surface_create_internal (dst->dpy, None,
> + dst->screen, NULL,
> + format, 0, 0, 32);
> + if (!surface)
> + {
> + XRenderFreePicture (dst->dpy, picture);
> + free (stops);
> + return CAIRO_STATUS_NO_MEMORY;
> + }
> +
> + surface->src_picture = picture;
> +
> + attributes->matrix = pattern->matrix;
> + attributes->extend = pattern->extend;
> + attributes->filter = pattern->filter;
> + attributes->x_offset = 0;
> + attributes->y_offset = 0;
> + attributes->acquired = FALSE;
> +
> + free (stops);
> +
> + *surface_out = surface;
> +
> + return CAIRO_STATUS_SUCCESS;
> + }
> + default:
> + break;
> + }
> +
> + return _cairo_pattern_acquire_surface (pattern, &dst->base,
> + x, y, width, height,
> + (cairo_surface_t **) surface_out,
> + attributes);
> +}
> +
> +static cairo_int_status_t
> +_cairo_xlib_pattern_acquire_surfaces (cairo_pattern_t *src,
> + cairo_pattern_t *mask,
> + cairo_xlib_surface_t *dst,
> + int src_x,
> + int src_y,
> + int mask_x,
> + int mask_y,
> + unsigned int width,
> + unsigned int height,
> + cairo_xlib_surface_t **src_out,
> + cairo_xlib_surface_t **mask_out,
> + cairo_surface_attributes_t *src_attr,
> + cairo_surface_attributes_t *mask_attr)
> +{
> + if (CAIRO_SURFACE_RENDER_HAS_GRADIENTS (dst))
> + {
> + if (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
> + src->type == CAIRO_PATTERN_TYPE_RADIAL ||
> + (mask && (mask->type == CAIRO_PATTERN_TYPE_LINEAR ||
> + mask->type == CAIRO_PATTERN_TYPE_RADIAL)))
> + {
> + cairo_int_status_t status;
> +
> + status = _cairo_xlib_pattern_acquire_surface (src, dst,
> + src_x, src_y,
> + width, height,
> + src_out,
> + src_attr);
> + if (status)
> + return status;
> +
> + if (mask)
> + {
> + status = _cairo_xlib_pattern_acquire_surface (mask, dst,
> + mask_x, mask_y,
> + width, height,
> + mask_out,
> + mask_attr);
> + if (status)
> + {
> + _cairo_pattern_release_surface (src, &(*src_out)->base,
> + src_attr);
> + return status;
> + }
> + }
> + else
> + {
> + *mask_out = NULL;
> + }
> +
> + return CAIRO_STATUS_SUCCESS;
> + }
> + }
> +
> + return _cairo_pattern_acquire_surfaces (src, mask, &dst->base,
> + src_x, src_y,
> + mask_x, mask_y,
> + width, height,
> + (cairo_surface_t **) src_out,
> + (cairo_surface_t **) mask_out,
> + src_attr, mask_attr);
> +}
> +
> +static cairo_int_status_t
> _cairo_xlib_surface_composite (cairo_operator_t op,
> cairo_pattern_t *src_pattern,
> cairo_pattern_t *mask_pattern,
> @@ -1282,14 +1496,13 @@ _cairo_xlib_surface_composite (cairo_ope
> if (operation == DO_UNSUPPORTED)
> return CAIRO_INT_STATUS_UNSUPPORTED;
>
> - status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
> - &dst->base,
> - src_x, src_y,
> - mask_x, mask_y,
> - width, height,
> - (cairo_surface_t **) &src,
> - (cairo_surface_t **) &mask,
> - &src_attr, &mask_attr);
> + status = _cairo_xlib_pattern_acquire_surfaces (src_pattern, mask_pattern,
> + dst,
> + src_x, src_y,
> + mask_x, mask_y,
> + width, height,
> + &src, &mask,
> + &src_attr, &mask_attr);
> if (status)
> return status;
>
> @@ -1545,10 +1758,9 @@ _cairo_xlib_surface_composite_trapezoids
> if (operation == DO_UNSUPPORTED)
> return CAIRO_INT_STATUS_UNSUPPORTED;
>
> - status = _cairo_pattern_acquire_surface (pattern, &dst->base,
> - src_x, src_y, width, height,
> - (cairo_surface_t **) &src,
> - &attributes);
> + status = _cairo_xlib_pattern_acquire_surface (pattern, dst,
> + src_x, src_y, width, height,
> + &src, &attributes);
> if (status)
> return status;
>
> @@ -1862,10 +2074,14 @@ _cairo_xlib_surface_create_internal (Dis
> surface->height = height;
>
> surface->buggy_repeat = FALSE;
> + surface->buggy_gradients = FALSE;
> if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
> if (VendorRelease (dpy) <= 60802000)
> surface->buggy_repeat = TRUE;
> + if (VendorRelease (dpy) <= 70000000)
> + surface->buggy_gradients = TRUE;
> } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
> + surface->buggy_gradients = TRUE;
> if (VendorRelease (dpy) <= 40500000)
> surface->buggy_repeat = TRUE;
> }
> @@ -2658,11 +2874,10 @@ _cairo_xlib_surface_show_glyphs (void
> if (status)
> return status;
>
> - status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
> - glyph_extents.x, glyph_extents.y,
> - glyph_extents.width, glyph_extents.height,
> - (cairo_surface_t **) &src,
> - &attributes);
> + status = _cairo_xlib_pattern_acquire_surface (src_pattern, dst,
> + glyph_extents.x, glyph_extents.y,
> + glyph_extents.width, glyph_extents.height,
> + &src, &attributes);
> }
>
> if (status)
> _______________________________________________
> cairo mailing list
> cairo at cairographics.org
> http://cairographics.org/cgi-bin/mailman/listinfo/cairo
-David
More information about the cairo
mailing list