[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