[cairo] [PATCH] V2 image: xlib/xcb backends use filtering to match image backend

Bill Spitzak spitzak at gmail.com
Mon Sep 22 20:21:28 PDT 2014


I am unclear whether this patch was rejected, misunderstood, or that
changes were requested. This version has been changed to reduce unnecessary
diffs and merged into a single patch so the capability flags are always there.

The xlib and xcb backends will use the image fallback if necessary
to get correct filtering of transformed surfaces. This should
produce output that matches the image backend.

- Added capability flags CAIRO_RENDER_HAS_FILTER_GOOD,
CAIRO_RENDER_HAS_FILTER_BEST, CAIRO_XCB_RENDER_HAS_FILTER_GOOD, and
CAIRO_XCB_RENDER_HAS_FILTER_BEST, to indicate if the backend can do the
filters. Currently nothing turnes these on but they could be set by the
version of X that implements them.

- _cairo_pattern_analyze_filter() changes GOOD to BILINEAR if if thinks
biliniear is acceptable. This allows image and xlib and xcb to all share the
same logic for deciding this, and should also assist other backends that are
pixman based. Removed the equivalent test from _pixman_image_set_properties.

- xlib backend pattern_is_supported changed to return false if GOOD or
BEST is requested and the backend does not support it.

- xcb backend _pattern_is_supported changed to return false if GOOD or
BEST is requested and the backend does not support it.
---
 src/cairo-image-source.c       |   22 +++++++++-------------
 src/cairo-pattern.c            |   17 +++++++++++++++++
 src/cairo-xcb-connection.c     |   10 ++++++++++
 src/cairo-xcb-private.h        |    6 +++++-
 src/cairo-xcb-surface-render.c |   34 ++++++++++++++++------------------
 src/cairo-xlib-private.h       |    2 ++
 src/cairo-xlib-source.c        |   23 ++++++++++++++---------
 7 files changed, 73 insertions(+), 41 deletions(-)

diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index b6b6b9f..f85d511 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -941,21 +941,17 @@ _pixman_image_set_properties (pixman_image_t *pixman_image,
 	    pixman_filter = PIXMAN_FILTER_FAST;
 	    break;
 	case CAIRO_FILTER_GOOD:
-	    pixman_filter = PIXMAN_FILTER_GOOD;
-	    if (dx > 1.35 || dy > 1.35) {
-		pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION;
-		kernel = KERNEL_BOX;
-		/* Clip the filter size to prevent extreme slowness. This
-		   value could be raised if 2-pass filtering is done */
-		if (dx > 16.0) dx = 16.0;
-		/* Match the bilinear filter for dimension scaling up: */
-		else if (dx < 1.0) dx = 1.0;
-		if (dy > 16.0) dy = 16.0;
-		else if (dy < 1.0) dy = 1.0;
-	    }
+	    pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION;
+	    kernel = KERNEL_BOX;
+	    /* Clip the filter size to prevent extreme slowness. This
+	       value could be raised if 2-pass filtering is done */
+	    if (dx > 16.0) dx = 16.0;
+	    if (dy > 16.0) dy = 16.0;
+	    /* Match the bilinear filter for scales > .75: */
+	    if (dx < 1.35) dx = 1.0;
+	    if (dy < 1.35) dy = 1.0;
 	    break;
 	case CAIRO_FILTER_BEST:
-	    pixman_filter = PIXMAN_FILTER_BEST;
 	    pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION;
 	    kernel = KERNEL_CATMULL_ROM; /* LANCZOS3 is better but not much */
 	    /* Clip the filter size to prevent extreme slowness. This
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e6fdae6..0f77670 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -3371,6 +3371,7 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
 	if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
 	    pad = 0.;
 	    optimized_filter = CAIRO_FILTER_NEAREST;
+	    break;
 	} else {
 	    /* 0.5 is enough for a bilinear filter. It's possible we
 	     * should defensively use more for CAIRO_FILTER_BEST, but
@@ -3379,6 +3380,22 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
 	     */
 	    pad = 0.5;
 	    optimized_filter = pattern->filter;
+	    /* Use BILINEAR for any scale greater than 1/1.35 instead
+	     * of GOOD. For scales of 1 and larger this is identical,
+	     * for the smaller sizes it was judged that the artifacts
+	     * were not worse than the artifacts from a box filer.
+	     */
+	    if (pattern->filter == CAIRO_FILTER_GOOD) {
+		double h;
+		h = pattern->matrix.xx * pattern->matrix.xx +
+		    pattern->matrix.xy * pattern->matrix.xy;
+		if (h < 1.35 * 1.35) {
+		    h = pattern->matrix.yx * pattern->matrix.yx +
+			pattern->matrix.yy * pattern->matrix.yy;
+		    if (h < 1.35 * 1.35)
+			optimized_filter = CAIRO_FILTER_BILINEAR;
+		}
+	    }
 	}
 	break;
 
diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c
index b48add1..2d51e14 100644
--- a/src/cairo-xcb-connection.c
+++ b/src/cairo-xcb-connection.c
@@ -77,6 +77,8 @@ typedef struct _cairo_xcb_xid {
 
 #define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface)	XCB_RENDER_AT_LEAST((surface), 0, 6)
 #define XCB_RENDER_HAS_FILTERS(surface)			XCB_RENDER_AT_LEAST((surface), 0, 6)
+#define XCB_RENDER_HAS_FILTER_GOOD(surface) FALSE
+#define XCB_RENDER_HAS_FILTER_BEST(surface) FALSE
 
 #define XCB_RENDER_HAS_EXTENDED_REPEAT(surface)	XCB_RENDER_AT_LEAST((surface), 0, 10)
 #define XCB_RENDER_HAS_GRADIENTS(surface)	XCB_RENDER_AT_LEAST((surface), 0, 10)
@@ -390,6 +392,12 @@ _cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection)
     if (XCB_RENDER_HAS_FILTERS (version))
 	connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS;
 
+    if (XCB_RENDER_HAS_FILTER_GOOD (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_FILTER_GOOD;
+
+    if (XCB_RENDER_HAS_FILTER_BEST (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_FILTER_BEST;
+
     if (XCB_RENDER_HAS_PDF_OPERATORS (version))
 	connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
 
@@ -882,6 +890,8 @@ cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
 			       CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
 			       CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM |
 			       CAIRO_XCB_RENDER_HAS_FILTERS |
+			       CAIRO_XCB_RENDER_HAS_FILTER_GOOD |
+			       CAIRO_XCB_RENDER_HAS_FILTER_BEST |
 			       CAIRO_XCB_RENDER_HAS_PDF_OPERATORS |
 			       CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT |
 			       CAIRO_XCB_RENDER_HAS_GRADIENTS);
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index 2610458..1e1d1ee 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -259,6 +259,8 @@ enum {
     CAIRO_XCB_RENDER_HAS_PDF_OPERATORS		= 0x0080,
     CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT	= 0x0100,
     CAIRO_XCB_RENDER_HAS_GRADIENTS		= 0x0200,
+    CAIRO_XCB_RENDER_HAS_FILTER_GOOD		= 0x0400,
+    CAIRO_XCB_RENDER_HAS_FILTER_BEST		= 0x0800,
 
     CAIRO_XCB_HAS_SHM				= 0x80000000,
 
@@ -271,7 +273,9 @@ enum {
 			    CAIRO_XCB_RENDER_HAS_FILTERS |
 			    CAIRO_XCB_RENDER_HAS_PDF_OPERATORS |
 			    CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT |
-			    CAIRO_XCB_RENDER_HAS_GRADIENTS,
+			    CAIRO_XCB_RENDER_HAS_GRADIENTS |
+			    CAIRO_XCB_RENDER_HAS_FILTER_GOOD |
+			    CAIRO_XCB_RENDER_HAS_FILTER_BEST,
     CAIRO_XCB_SHM_MASK    = CAIRO_XCB_HAS_SHM
 };
 
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index edfa34c..21a89cc 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -394,11 +394,6 @@ _pattern_is_supported (uint32_t flags,
     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
 	return TRUE;
 
-    if (! _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) {
-	if ((flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) == 0)
-	    return FALSE;
-    }
-
     switch (pattern->extend) {
     default:
 	ASSERT_NOT_REACHED;
@@ -412,18 +407,22 @@ _pattern_is_supported (uint32_t flags,
     }
 
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
-	cairo_filter_t filter;
-
-	filter = pattern->filter;
-	if (_cairo_matrix_is_pixel_exact (&pattern->matrix))
-	{
-	    filter = CAIRO_FILTER_NEAREST;
-	}
-
-	if (! (filter == CAIRO_FILTER_NEAREST || filter == CAIRO_FILTER_FAST)) {
-	    if ((flags & CAIRO_XCB_RENDER_HAS_FILTERS) == 0)
-		return FALSE;
+	switch (pattern->filter) {
+	case CAIRO_FILTER_FAST:
+	case CAIRO_FILTER_NEAREST:
+	    return (flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) ||
+		_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL);
+	case CAIRO_FILTER_GOOD:
+	    return flags & CAIRO_XCB_RENDER_HAS_FILTER_GOOD;
+	case CAIRO_FILTER_BEST:
+	    return flags & CAIRO_XCB_RENDER_HAS_FILTER_BEST;
+	case CAIRO_FILTER_BILINEAR:
+	case CAIRO_FILTER_GAUSSIAN:
+	default:
+	    return flags & CAIRO_XCB_RENDER_HAS_FILTERS;
 	}
+    } else if (pattern->type == CAIRO_PATTERN_TYPE_MESH) {
+	return FALSE;
     } else { /* gradient */
 	if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
 	    return FALSE;
@@ -435,9 +434,8 @@ _pattern_is_supported (uint32_t flags,
 	{
 	    return FALSE;
 	}
+	return TRUE;
     }
-
-    return pattern->type != CAIRO_PATTERN_TYPE_MESH;
 }
 
 static void
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 822c85b..6d37896 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -373,6 +373,8 @@ _cairo_xlib_font_close (cairo_xlib_font_t *font);
 
 #define CAIRO_RENDER_HAS_PICTURE_TRANSFORM(surface)	CAIRO_RENDER_AT_LEAST((surface), 0, 6)
 #define CAIRO_RENDER_HAS_FILTERS(surface)	CAIRO_RENDER_AT_LEAST((surface), 0, 6)
+#define CAIRO_RENDER_HAS_FILTER_GOOD(surface) FALSE
+#define CAIRO_RENDER_HAS_FILTER_BEST(surface) FALSE
 
 #define CAIRO_RENDER_HAS_EXTENDED_REPEAT(surface)	CAIRO_RENDER_AT_LEAST((surface), 0, 10)
 #define CAIRO_RENDER_HAS_GRADIENTS(surface)	CAIRO_RENDER_AT_LEAST((surface), 0, 10)
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 8275da3..81cc028 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -1093,17 +1093,22 @@ pattern_is_supported (cairo_xlib_display_t *display,
 	    return FALSE;
     }
 
-    if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
-	if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
-	    return FALSE;
-    }
-
-    if (! CAIRO_RENDER_HAS_FILTERS (display)) {
-	    /* No filters implies no transforms, so we optimise away BILINEAR */
+    switch (pattern->filter) {
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	return CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display) ||
+	    _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL);
+    case CAIRO_FILTER_GOOD:
+	return CAIRO_RENDER_HAS_FILTER_GOOD (display);
+    case CAIRO_FILTER_BEST:
+	return CAIRO_RENDER_HAS_FILTER_BEST (display);
+    case CAIRO_FILTER_BILINEAR:
+    case CAIRO_FILTER_GAUSSIAN:
+    default:
+	return CAIRO_RENDER_HAS_FILTERS (display);
     }
-
-    return TRUE;
 }
+
 cairo_surface_t *
 _cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
 				       const cairo_pattern_t *pattern,
-- 
1.7.9.5



More information about the cairo mailing list