pixman: Branch 'master' - 8 commits

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Fri Feb 18 03:19:27 PST 2011


 demos/Makefile.am           |    6 
 demos/tri-test.c            |   48 +++++++
 pixman/pixman-image.c       |   20 +++
 pixman/pixman-trap.c        |  271 ++++++++++++++++++++++++++++++++++++++++++++
 pixman/pixman.h             |   30 ++++
 test/Makefile.am            |    2 
 test/composite-traps-test.c |  253 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 627 insertions(+), 3 deletions(-)

New commits:
commit 510c0d088a975efe75cc2b796547f3aaed1c18e6
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Tue Feb 15 09:11:44 2011 -0500

    In pixman_image_set_transform() allow NULL for transform
    
    Previously, this would crash unless the existing transform were also
    NULL.

diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 55fc17a..9103ca6 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -502,7 +502,7 @@ pixman_image_set_transform (pixman_image_t *          image,
     if (common->transform == transform)
 	return TRUE;
 
-    if (memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
+    if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
     {
 	free (common->transform);
 	common->transform = NULL;
commit 7feb710e60cdab5c448a396537a8de16e72091e2
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Tue Feb 15 04:55:02 2011 -0500

    Avoid marking images dirty when properties are reset
    
    When an image property is set to the same value that it already is,
    there is no reason to mark the image dirty and incur a recomputation
    of the flags.

diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index e91d87c..55fc17a 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -511,6 +511,12 @@ pixman_image_set_transform (pixman_image_t *          image,
 	goto out;
     }
 
+    if (common->transform &&
+	memcmp (common->transform, transform, sizeof (pixman_transform_t) == 0))
+    {
+	return TRUE;
+    }
+
     if (common->transform == NULL)
 	common->transform = malloc (sizeof (pixman_transform_t));
 
@@ -535,6 +541,9 @@ PIXMAN_EXPORT void
 pixman_image_set_repeat (pixman_image_t *image,
                          pixman_repeat_t repeat)
 {
+    if (image->common.repeat == repeat)
+	return;
+
     image->common.repeat = repeat;
 
     image_property_changed (image);
@@ -579,6 +588,9 @@ PIXMAN_EXPORT void
 pixman_image_set_source_clipping (pixman_image_t *image,
                                   pixman_bool_t   clip_sources)
 {
+    if (image->common.clip_sources == clip_sources)
+	return;
+
     image->common.clip_sources = clip_sources;
 
     image_property_changed (image);
@@ -594,6 +606,9 @@ pixman_image_set_indexed (pixman_image_t *        image,
 {
     bits_image_t *bits = (bits_image_t *)image;
 
+    if (bits->indexed == indexed)
+	return;
+
     bits->indexed = indexed;
 
     image_property_changed (image);
@@ -656,6 +671,9 @@ PIXMAN_EXPORT void
 pixman_image_set_component_alpha   (pixman_image_t *image,
                                     pixman_bool_t   component_alpha)
 {
+    if (image->common.component_alpha == component_alpha)
+	return;
+
     image->common.component_alpha = component_alpha;
 
     image_property_changed (image);
commit 3598ec26ecf761488e2ac1536553eaf3bb361e72
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Fri Feb 11 08:57:42 2011 -0500

    Add new public function pixman_add_triangles()
    
    This allows some more code to be deleted from the X server. The
    implementation consists of converting to trapezoids, and is shared
    with pixman_composite_triangles().

diff --git a/pixman/pixman-trap.c b/pixman/pixman-trap.c
index adf822c..2957a2b 100644
--- a/pixman/pixman-trap.c
+++ b/pixman/pixman-trap.c
@@ -595,6 +595,25 @@ triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps)
     }
 }
 
+static pixman_trapezoid_t *
+convert_triangles (int n_tris, const pixman_triangle_t *tris)
+{
+    pixman_trapezoid_t *traps;
+    int i;
+
+    if (n_tris <= 0)
+	return NULL;
+    
+    traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t));
+    if (!traps)
+	return NULL;
+
+    for (i = 0; i < n_tris; ++i)
+	triangle_to_trapezoids (&(tris[i]), traps + 2 * i);
+
+    return traps;
+}
+
 PIXMAN_EXPORT void
 pixman_composite_triangles (pixman_op_t			op,
 			    pixman_image_t *		src,
@@ -607,22 +626,32 @@ pixman_composite_triangles (pixman_op_t			op,
 			    int				n_tris,
 			    const pixman_triangle_t *	tris)
 {
-    pixman_trapezoid_t *trapezoids;
-    int i;
+    pixman_trapezoid_t *traps;
 
-    if (n_tris <= 0)
-	return;
-    
-    trapezoids = malloc (2 * n_tris * sizeof (pixman_trapezoid_t));
-    if (!trapezoids)
-	return;
+    if ((traps = convert_triangles (n_tris, tris)))
+    {
+	pixman_composite_trapezoids (op, src, dst, mask_format,
+				     x_src, y_src, x_dst, y_dst,
+				     n_tris * 2, traps);
+	
+	free (traps);
+    }
+}
 
-    for (i = 0; i < n_tris; ++i)
-	triangle_to_trapezoids (&(tris[i]), trapezoids + 2 * i);
-    
-    pixman_composite_trapezoids (op, src, dst, mask_format,
-				 x_src, y_src, x_dst, y_dst,
-				 n_tris * 2, trapezoids);
-	    
-    free (trapezoids);
+PIXMAN_EXPORT void
+pixman_add_triangles (pixman_image_t          *image,
+		      int32_t	               x_off,
+		      int32_t	               y_off,
+		      int	               n_tris,
+		      const pixman_triangle_t *tris)
+{
+    pixman_trapezoid_t *traps;
+
+    if ((traps = convert_triangles (n_tris, tris)))
+    {
+	pixman_add_trapezoids (image, x_off, y_off,
+			       n_tris * 2, traps);
+
+	free (traps);
+    }
 }
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 7d28e78..1305bc1 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -975,7 +975,12 @@ void          pixman_composite_triangles (pixman_op_t		       op,
 					  int			       y_dst,
 					  int			       n_tris,
 					  const pixman_triangle_t *    tris);
-    
+void	      pixman_add_triangles       (pixman_image_t              *image,
+					  int32_t	               x_off,
+					  int32_t	               y_off,
+					  int	                       n_tris,
+					  const pixman_triangle_t     *tris);
+
 PIXMAN_END_DECLS
 
 #endif /* PIXMAN_H__ */
commit 964c7e7cd20a6ed414fdf92b71fdc83db91d7578
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Fri Jan 14 06:19:08 2011 -0500

    Optimize adding opaque trapezoids onto a8 destination.
    
    When the source is opaque and the destination is alpha only, we can
    avoid the temporary mask and just add the trapezoids directly.

diff --git a/pixman/pixman-trap.c b/pixman/pixman-trap.c
index 2675773..adf822c 100644
--- a/pixman/pixman-trap.c
+++ b/pixman/pixman-trap.c
@@ -399,10 +399,7 @@ pixman_composite_trapezoids (pixman_op_t		op,
 			     int			n_traps,
 			     const pixman_trapezoid_t *	traps)
 {
-    pixman_image_t *tmp;
-    pixman_box32_t box;
     int i;
-    int x_rel, y_rel;
 
     if (n_traps <= 0)
 	return;
@@ -410,68 +407,90 @@ pixman_composite_trapezoids (pixman_op_t		op,
     _pixman_image_validate (src);
     _pixman_image_validate (dst);
 
-    box.x1 = INT32_MAX;
-    box.y1 = INT32_MAX;
-    box.x2 = INT32_MIN;
-    box.y2 = INT32_MIN;
-    
-    for (i = 0; i < n_traps; ++i)
+    if (op == PIXMAN_OP_ADD &&
+	(src->common.flags & FAST_PATH_IS_OPAQUE)		&&
+	(mask_format == dst->common.extended_format_code)	&&
+	!(dst->common.have_clip_region))
     {
-	const pixman_trapezoid_t *trap = &(traps[i]);
-	int y1, y2;
-
-	if (!pixman_trapezoid_valid (trap))
-	    continue;
+	for (i = 0; i < n_traps; ++i)
+	{
+	    const pixman_trapezoid_t *trap = &(traps[i]);
+	    
+	    if (!pixman_trapezoid_valid (trap))
+		continue;
+	    
+	    pixman_rasterize_trapezoid (dst, trap, 0, 0);
+	}
+    }
+    else
+    {
+	pixman_image_t *tmp;
+	pixman_box32_t box;
+	int x_rel, y_rel;
 	
-	y1 = pixman_fixed_to_int (trap->top);
-	if (y1 < box.y1)
-	    box.y1 = y1;
+	box.x1 = INT32_MAX;
+	box.y1 = INT32_MAX;
+	box.x2 = INT32_MIN;
+	box.y2 = INT32_MIN;
 	
-	y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
-	if (y2 > box.y2)
-	    box.y2 = y2;
-
+	for (i = 0; i < n_traps; ++i)
+	{
+	    const pixman_trapezoid_t *trap = &(traps[i]);
+	    int y1, y2;
+	    
+	    if (!pixman_trapezoid_valid (trap))
+		continue;
+	    
+	    y1 = pixman_fixed_to_int (trap->top);
+	    if (y1 < box.y1)
+		box.y1 = y1;
+	    
+	    y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
+	    if (y2 > box.y2)
+		box.y2 = y2;
+	    
 #define EXTEND_MIN(x)							\
-	if (pixman_fixed_to_int ((x)) < box.x1)				\
-	    box.x1 = pixman_fixed_to_int ((x));
+	    if (pixman_fixed_to_int ((x)) < box.x1)			\
+		box.x1 = pixman_fixed_to_int ((x));
 #define EXTEND_MAX(x)							\
-	if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box.x2)	\
-	    box.x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
-
+	    if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box.x2)	\
+		box.x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
+	    
 #define EXTEND(x)							\
-	EXTEND_MIN(x);							\
-	EXTEND_MAX(x);
-
-	EXTEND(trap->left.p1.x);
-	EXTEND(trap->left.p2.x);
-	EXTEND(trap->right.p1.x);
-	EXTEND(trap->right.p2.x);
-    }
-
-    if (box.x1 >= box.x2 || box.y1 >= box.y2)
-	return;
-    
-    tmp = pixman_image_create_bits (
-	mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1);
+	    EXTEND_MIN(x);						\
+	    EXTEND_MAX(x);
+	    
+	    EXTEND(trap->left.p1.x);
+	    EXTEND(trap->left.p2.x);
+	    EXTEND(trap->right.p1.x);
+	    EXTEND(trap->right.p2.x);
+	}
 	
-    for (i = 0; i < n_traps; ++i)
-    {
-	const pixman_trapezoid_t *trap = &(traps[i]);
-
-	if (!pixman_trapezoid_valid (trap))
-	    continue;
-
-	pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
+	if (box.x1 >= box.x2 || box.y1 >= box.y2)
+	    return;
+	
+	tmp = pixman_image_create_bits (
+	    mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1);
+	
+	for (i = 0; i < n_traps; ++i)
+	{
+	    const pixman_trapezoid_t *trap = &(traps[i]);
+	    
+	    if (!pixman_trapezoid_valid (trap))
+		continue;
+	    
+	    pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
+	}
+	
+	x_rel = box.x1 + x_src - x_dst;
+	y_rel = box.y1 + y_src - y_dst;
+	
+	pixman_image_composite (op, src, tmp, dst,
+				x_rel, y_rel, 0, 0, box.x1, box.y1,
+				box.x2 - box.x1, box.y2 - box.y1);
+	
+	pixman_image_unref (tmp);
     }
-
-    x_rel = box.x1 + x_src - x_dst;
-    y_rel = box.y1 + y_src - y_dst;
-
-    pixman_image_composite (op, src, tmp, dst,
-			    x_rel, y_rel, 0, 0, box.x1, box.y1,
-			    box.x2 - box.x1, box.y2 - box.y1);
-
-    pixman_image_unref (tmp);
 }
 
 static int
commit 0bc03482f10d7bfe64a4199e9cd484ff1129d709
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Wed Jan 12 03:02:59 2011 -0500

    Add a test program, tri-test
    
    This program tests whether the new triangle support works.

diff --git a/demos/Makefile.am b/demos/Makefile.am
index 2dcdfd3..f08303b 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -3,7 +3,7 @@ if HAVE_GTK
 AM_CFLAGS = @OPENMP_CFLAGS@
 AM_LDFLAGS = @OPENMP_CFLAGS@
 
-LDADD = $(GTK_LIBS) $(top_builddir)/pixman/libpixman-1.la -lm 
+LDADD = $(top_builddir)/pixman/libpixman-1.la -lm $(GTK_LIBS)
 INCLUDES = -I$(top_srcdir)/pixman -I$(top_builddir)/pixman $(GTK_CFLAGS)
 
 GTK_UTILS = gtk-utils.c gtk-utils.h
@@ -17,7 +17,8 @@ DEMOS =				\
 	alpha-test		\
 	screen-test		\
 	convolution-test	\
-	trap-test
+	trap-test		\
+	tri-test
 
 gradient_test_SOURCES = gradient-test.c $(GTK_UTILS)
 alpha_test_SOURCES = alpha-test.c $(GTK_UTILS)
@@ -28,6 +29,7 @@ trap_test_SOURCES = trap-test.c $(GTK_UTILS)
 screen_test_SOURCES = screen-test.c $(GTK_UTILS)
 convolution_test_SOURCES = convolution-test.c $(GTK_UTILS)
 radial_test_SOURCES = radial-test.c ../test/utils.c ../test/utils.h $(GTK_UTILS)
+tri_test_SOURCES = tri-test.c ../test/utils.c ../test/utils.h $(GTK_UTILS)
 
 noinst_PROGRAMS = $(DEMOS)
 
diff --git a/demos/tri-test.c b/demos/tri-test.c
new file mode 100644
index 0000000..ff4779e
--- /dev/null
+++ b/demos/tri-test.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../test/utils.h"
+#include "gtk-utils.h"
+
+int
+main (int argc, char **argv)
+{
+#define WIDTH 200
+#define HEIGHT 200
+
+#define POINT(x,y)							\
+    { pixman_double_to_fixed ((x)), pixman_double_to_fixed ((y)) }
+    
+    pixman_image_t *src_img, *dest_img;
+    pixman_triangle_t tris[4] =
+    {
+	{ POINT (100, 100), POINT (10, 50), POINT (110, 10) },
+	{ POINT (100, 100), POINT (150, 10), POINT (200, 50) },
+	{ POINT (100, 100), POINT (10, 170), POINT (90, 175) },
+	{ POINT (100, 100), POINT (170, 150), POINT (120, 190) },
+    };
+    pixman_color_t color = { 0x4444, 0x4444, 0xffff, 0xffff };
+    uint32_t *bits = malloc (WIDTH * HEIGHT * 4);
+    int i;
+
+    for (i = 0; i < WIDTH * HEIGHT; ++i)
+	bits[i] = (i / HEIGHT) * 0x01010000;
+    
+    src_img = pixman_image_create_solid_fill (&color);
+    dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, WIDTH, HEIGHT, bits, WIDTH * 4);
+    
+    pixman_composite_triangles (PIXMAN_OP_ATOP_REVERSE,
+				src_img,
+				dest_img,
+				PIXMAN_a8,
+				200, 200,
+				35, 5,
+				ARRAY_LENGTH (tris), tris);
+    show_image (dest_img);
+    
+    pixman_image_unref (src_img);
+    pixman_image_unref (dest_img);
+    free (bits);
+    
+    return 0;
+}
commit 79e69aac8cfe7d45707098735376a6e6c2dcfa06
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Tue Jan 11 10:15:21 2011 -0500

    Add support for triangles to pixman.
    
    The Render X extension can draw triangles as well as trapezoids, but
    the implementation has always converted them to trapezoids. This patch
    moves the X server's triangle conversion code into pixman, where we
    can reuse the pixman_composite_trapezoid() code.

diff --git a/pixman/pixman-trap.c b/pixman/pixman-trap.c
index ecec5d4..2675773 100644
--- a/pixman/pixman-trap.c
+++ b/pixman/pixman-trap.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
  * Copyright © 2004 Keith Packard
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
@@ -25,6 +26,7 @@
 #endif
 
 #include <stdio.h>
+#include <stdlib.h>
 #include "pixman-private.h"
 
 /*
@@ -471,3 +473,137 @@ pixman_composite_trapezoids (pixman_op_t		op,
 
     pixman_image_unref (tmp);
 }
+
+static int
+greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b)
+{
+    if (a->y == b->y)
+	return a->x > b->x;
+    return a->y > b->y;
+}
+
+/*
+ * Note that the definition of this function is a bit odd because
+ * of the X coordinate space (y increasing downwards).
+ */
+static int
+clockwise (const pixman_point_fixed_t *ref,
+	   const pixman_point_fixed_t *a,
+	   const pixman_point_fixed_t *b)
+{
+    pixman_point_fixed_t	ad, bd;
+
+    ad.x = a->x - ref->x;
+    ad.y = a->y - ref->y;
+    bd.x = b->x - ref->x;
+    bd.y = b->y - ref->y;
+
+    return ((pixman_fixed_32_32_t) bd.y * ad.x -
+	    (pixman_fixed_32_32_t) ad.y * bd.x) < 0;
+}
+
+static void
+triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps)
+{
+    const pixman_point_fixed_t *top, *left, *right, *tmp;
+
+    top = &tri->p1;
+    left = &tri->p2;
+    right = &tri->p3;
+
+    if (greater_y (top, left))
+    {
+	tmp = left;
+	left = top;
+	top = tmp;
+    }
+
+    if (greater_y (top, right))
+    {
+	tmp = right;
+	right = top;
+	top = tmp;
+    }
+
+    if (clockwise (top, right, left))
+    {
+	tmp = right;
+	right = left;
+	left = tmp;
+    }
+    
+    /*
+     * Two cases:
+     *
+     *		+		+
+     *	       / \             / \
+     *	      /   \           /	  \
+     *	     /     +         +	   \
+     *      /    --           --    \
+     *     /   --               --   \
+     *    / ---                   --- \
+     *	 +--                         --+
+     */
+
+    traps->top = top->y;
+    traps->left.p1 = *top;
+    traps->left.p2 = *left;
+    traps->right.p1 = *top;
+    traps->right.p2 = *right;
+
+    if (right->y < left->y)
+	traps->bottom = right->y;
+    else
+	traps->bottom = left->y;
+
+    traps++;
+
+    *traps = *(traps - 1);
+    
+    if (right->y < left->y)
+    {
+	traps->top = right->y;
+	traps->bottom = left->y;
+	traps->right.p1 = *right;
+	traps->right.p2 = *left;
+    }
+    else
+    {
+	traps->top = left->y;
+	traps->bottom = right->y;
+	traps->left.p1 = *left;
+	traps->left.p2 = *right;
+    }
+}
+
+PIXMAN_EXPORT void
+pixman_composite_triangles (pixman_op_t			op,
+			    pixman_image_t *		src,
+			    pixman_image_t *		dst,
+			    pixman_format_code_t	mask_format,
+			    int				x_src,
+			    int				y_src,
+			    int				x_dst,
+			    int				y_dst,
+			    int				n_tris,
+			    const pixman_triangle_t *	tris)
+{
+    pixman_trapezoid_t *trapezoids;
+    int i;
+
+    if (n_tris <= 0)
+	return;
+    
+    trapezoids = malloc (2 * n_tris * sizeof (pixman_trapezoid_t));
+    if (!trapezoids)
+	return;
+
+    for (i = 0; i < n_tris; ++i)
+	triangle_to_trapezoids (&(tris[i]), trapezoids + 2 * i);
+    
+    pixman_composite_trapezoids (op, src, dst, mask_format,
+				 x_src, y_src, x_dst, y_dst,
+				 n_tris * 2, trapezoids);
+	    
+    free (trapezoids);
+}
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 52ab8a5..7d28e78 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -868,6 +868,7 @@ typedef struct pixman_edge pixman_edge_t;
 typedef struct pixman_trapezoid pixman_trapezoid_t;
 typedef struct pixman_trap pixman_trap_t;
 typedef struct pixman_span_fix pixman_span_fix_t;
+typedef struct pixman_triangle pixman_triangle_t;
 
 /*
  * An edge structure.  This represents a single polygon edge
@@ -895,6 +896,10 @@ struct pixman_trapezoid
     pixman_line_fixed_t	left, right;
 };
 
+struct pixman_triangle
+{
+    pixman_point_fixed_t p1, p2, p3;
+};
 
 /* whether 't' is a well defined not obviously empty trapezoid */
 #define pixman_trapezoid_valid(t)				   \
@@ -960,6 +965,16 @@ void          pixman_composite_trapezoids (pixman_op_t		       op,
 					   int			       y_dst,
 					   int			       n_traps,
 					   const pixman_trapezoid_t *  traps);
+void          pixman_composite_triangles (pixman_op_t		       op,
+					  pixman_image_t *	       src,
+					  pixman_image_t *	       dst,
+					  pixman_format_code_t	       mask_format,
+					  int			       x_src,
+					  int			       y_src,
+					  int			       x_dst,
+					  int			       y_dst,
+					  int			       n_tris,
+					  const pixman_triangle_t *    tris);
     
 PIXMAN_END_DECLS
 
commit 4e6dd4928d817338ae406a620f5658bbddb66df1
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Thu Feb 10 10:37:08 2011 -0500

    Add a test program for pixman_composite_trapezoids().
    
    A CRC32 based test program to check that pixman_composite_trapezoids()
    actually works.

diff --git a/test/Makefile.am b/test/Makefile.am
index 3ce466e..057e9ce 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -16,6 +16,7 @@ TESTPROGRAMS =			\
 	gradient-crash-test	\
 	alphamap		\
 	stress-test		\
+	composite-traps-test	\
 	blitters-test		\
 	scaling-test		\
 	affine-test		\
@@ -24,6 +25,7 @@ TESTPROGRAMS =			\
 pdf_op_test_SOURCES = pdf-op-test.c utils.c utils.h
 region_test_SOURCES = region-test.c utils.c utils.h
 blitters_test_SOURCES = blitters-test.c utils.c utils.h
+composite_traps_test_SOURCES = composite-traps-test.c utils.c utils.h
 scaling_test_SOURCES = scaling-test.c utils.c utils.h
 affine_test_SOURCES = affine-test.c utils.c utils.h
 alphamap_SOURCES = alphamap.c utils.c utils.h
diff --git a/test/composite-traps-test.c b/test/composite-traps-test.c
new file mode 100644
index 0000000..8f32778
--- /dev/null
+++ b/test/composite-traps-test.c
@@ -0,0 +1,253 @@
+/* Based loosely on scaling-test */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "utils.h"
+
+#define MAX_SRC_WIDTH  48
+#define MAX_SRC_HEIGHT 48
+#define MAX_DST_WIDTH  48
+#define MAX_DST_HEIGHT 48
+#define MAX_STRIDE     4
+
+static pixman_format_code_t formats[] =
+{
+    PIXMAN_a8r8g8b8, PIXMAN_a8, PIXMAN_r5g6b5, PIXMAN_a1, PIXMAN_a4
+};
+
+static pixman_format_code_t mask_formats[] =
+{
+    PIXMAN_a1, PIXMAN_a4, PIXMAN_a8,
+};
+
+static pixman_op_t operators[] =
+{
+    PIXMAN_OP_OVER, PIXMAN_OP_ADD, PIXMAN_OP_SRC, PIXMAN_OP_IN
+};
+
+#define RANDOM_ELT(array)						\
+    ((array)[lcg_rand_n(ARRAY_LENGTH((array)))])
+
+static void
+destroy_bits (pixman_image_t *image, void *data)
+{
+    fence_free (data);
+}
+
+static pixman_fixed_t
+random_fixed (int n)
+{
+    return lcg_rand_N (n << 16);
+}
+
+/*
+ * Composite operation with pseudorandom images
+ */
+uint32_t
+test_composite (int      testnum,
+		int      verbose)
+{
+    int                i;
+    pixman_image_t *   src_img;
+    pixman_image_t *   dst_img;
+    pixman_region16_t  clip;
+    int                dst_width, dst_height;
+    int                dst_stride;
+    int                dst_x, dst_y;
+    int                dst_bpp;
+    pixman_op_t        op;
+    uint32_t *         dst_bits;
+    uint32_t           crc32;
+    pixman_format_code_t mask_format, dst_format;
+    pixman_trapezoid_t *traps;
+    int src_x, src_y;
+    int n_traps;
+
+    static pixman_color_t colors[] =
+    {
+	{ 0xffff, 0xffff, 0xffff, 0xffff },
+	{ 0x0000, 0x0000, 0x0000, 0x0000 },
+	{ 0xabcd, 0xabcd, 0x0000, 0xabcd },
+	{ 0x0000, 0x0000, 0x0000, 0xffff },
+	{ 0x0101, 0x0101, 0x0101, 0x0101 },
+	{ 0x7777, 0x6666, 0x5555, 0x9999 },
+    };
+    
+    FLOAT_REGS_CORRUPTION_DETECTOR_START ();
+
+    lcg_srand (testnum);
+
+    op = RANDOM_ELT (operators);
+    mask_format = RANDOM_ELT (mask_formats);
+
+    /* Create source image */
+    
+    if (lcg_rand_n (4) == 0)
+    {
+	src_img = pixman_image_create_solid_fill (
+	    &(colors[lcg_rand_n (ARRAY_LENGTH (colors))]));
+
+	src_x = 10;
+	src_y = 234;
+    }
+    else
+    {
+	pixman_format_code_t src_format = RANDOM_ELT(formats);
+	int src_bpp = (PIXMAN_FORMAT_BPP (src_format) + 7) / 8;
+	int src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1;
+	int src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1;
+	int src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp;
+	uint32_t *bits;
+
+	src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2);
+	src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2);
+
+	src_stride = (src_stride + 3) & ~3;
+	
+	bits = (uint32_t *)make_random_bytes (src_stride * src_height);
+
+	src_img = pixman_image_create_bits (
+	    src_format, src_width, src_height, bits, src_stride);
+
+	pixman_image_set_destroy_function (src_img, destroy_bits, bits);
+
+	if (lcg_rand_n (8) == 0)
+	{
+	    pixman_box16_t clip_boxes[2];
+	    int            n = lcg_rand_n (2) + 1;
+	    
+	    for (i = 0; i < n; i++)
+	    {
+		clip_boxes[i].x1 = lcg_rand_n (src_width);
+		clip_boxes[i].y1 = lcg_rand_n (src_height);
+		clip_boxes[i].x2 =
+		    clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1);
+		clip_boxes[i].y2 =
+		    clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1);
+		
+		if (verbose)
+		{
+		    printf ("source clip box: [%d,%d-%d,%d]\n",
+			    clip_boxes[i].x1, clip_boxes[i].y1,
+			    clip_boxes[i].x2, clip_boxes[i].y2);
+		}
+	    }
+	    
+	    pixman_region_init_rects (&clip, clip_boxes, n);
+	    pixman_image_set_clip_region (src_img, &clip);
+	    pixman_image_set_source_clipping (src_img, 1);
+	    pixman_region_fini (&clip);
+	}
+    }
+
+    /* Create destination image */
+    {
+	dst_format = RANDOM_ELT(formats);
+	dst_bpp = (PIXMAN_FORMAT_BPP (dst_format) + 7) / 8;
+	dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1;
+	dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1;
+	dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp;
+	dst_stride = (dst_stride + 3) & ~3;
+	
+	dst_bits = (uint32_t *)make_random_bytes (dst_stride * dst_height);
+
+	dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2);
+	dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2);
+	
+	dst_img = pixman_image_create_bits (
+	    dst_format, dst_width, dst_height, dst_bits, dst_stride);
+    }
+
+    /* Create traps */
+    {
+	int i;
+
+	n_traps = lcg_rand_n (25);
+	traps = fence_malloc (n_traps * sizeof (pixman_trapezoid_t));
+
+	for (i = 0; i < n_traps; ++i)
+	{
+	    pixman_trapezoid_t *t = &(traps[i]);
+	    
+	    t->top = random_fixed (MAX_DST_HEIGHT) - MAX_DST_HEIGHT / 2;
+	    t->bottom = t->top + random_fixed (MAX_DST_HEIGHT);
+	    t->left.p1.x = random_fixed (MAX_DST_WIDTH) - MAX_DST_WIDTH / 2;
+	    t->left.p1.y = t->top - random_fixed (50);
+	    t->left.p2.x = random_fixed (MAX_DST_WIDTH) - MAX_DST_WIDTH / 2;
+	    t->left.p2.y = t->bottom + random_fixed (50);
+	    t->right.p1.x = t->left.p1.x + random_fixed (MAX_DST_WIDTH);
+	    t->right.p1.y = t->top - random_fixed (50);
+	    t->right.p2.x = t->left.p2.x + random_fixed (MAX_DST_WIDTH);
+	    t->right.p2.y = t->bottom - random_fixed (50);
+	}
+    }
+    
+    if (lcg_rand_n (8) == 0)
+    {
+	pixman_box16_t clip_boxes[2];
+	int            n = lcg_rand_n (2) + 1;
+	for (i = 0; i < n; i++)
+	{
+	    clip_boxes[i].x1 = lcg_rand_n (dst_width);
+	    clip_boxes[i].y1 = lcg_rand_n (dst_height);
+	    clip_boxes[i].x2 =
+		clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1);
+	    clip_boxes[i].y2 =
+		clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1);
+
+	    if (verbose)
+	    {
+		printf ("destination clip box: [%d,%d-%d,%d]\n",
+		        clip_boxes[i].x1, clip_boxes[i].y1,
+		        clip_boxes[i].x2, clip_boxes[i].y2);
+	    }
+	}
+	pixman_region_init_rects (&clip, clip_boxes, n);
+	pixman_image_set_clip_region (dst_img, &clip);
+	pixman_region_fini (&clip);
+    }
+
+    pixman_composite_trapezoids (op, src_img, dst_img, mask_format,
+				 src_x, src_y, dst_x, dst_y, n_traps, traps);
+
+    if (dst_format == PIXMAN_x8r8g8b8)
+    {
+	/* ignore unused part */
+	for (i = 0; i < dst_stride * dst_height / 4; i++)
+	    dst_bits[i] &= 0xFFFFFF;
+    }
+
+    image_endian_swap (dst_img, dst_bpp * 8);
+
+    if (verbose)
+    {
+	int j;
+	
+	for (i = 0; i < dst_height; i++)
+	{
+	    for (j = 0; j < dst_stride; j++)
+		printf ("%02X ", *((uint8_t *)dst_bits + i * dst_stride + j));
+
+	    printf ("\n");
+	}
+    }
+
+    crc32 = compute_crc32 (0, dst_bits, dst_stride * dst_height);
+
+    fence_free (dst_bits);
+    
+    pixman_image_unref (src_img);
+    pixman_image_unref (dst_img);
+    fence_free (traps);
+
+    FLOAT_REGS_CORRUPTION_DETECTOR_FINISH ();
+    return crc32;
+}
+
+int
+main (int argc, const char *argv[])
+{
+    return fuzzer_test_main("composite traps", 40000, 0xA34F95C7,
+			    test_composite, argc, argv);
+}
commit 803272e38c5b9b9abe347390c2ecd2ac4be7b9be
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Tue Jan 11 09:23:43 2011 -0500

    Add pixman_composite_trapezoids().
    
    This function is an implementation of the X server request
    Trapezoids. That request is what the X backend of cairo is using all
    the time; by moving it into pixman we can hopefully make it faster.

diff --git a/pixman/pixman-trap.c b/pixman/pixman-trap.c
index 742911c..ecec5d4 100644
--- a/pixman/pixman-trap.c
+++ b/pixman/pixman-trap.c
@@ -384,3 +384,90 @@ pixman_rasterize_trapezoid (pixman_image_t *          image,
 	pixman_rasterize_edges (image, &l, &r, t, b);
     }
 }
+
+PIXMAN_EXPORT void
+pixman_composite_trapezoids (pixman_op_t		op,
+			     pixman_image_t *		src,
+			     pixman_image_t *		dst,
+			     pixman_format_code_t	mask_format,
+			     int			x_src,
+			     int			y_src,
+			     int			x_dst,
+			     int			y_dst,
+			     int			n_traps,
+			     const pixman_trapezoid_t *	traps)
+{
+    pixman_image_t *tmp;
+    pixman_box32_t box;
+    int i;
+    int x_rel, y_rel;
+
+    if (n_traps <= 0)
+	return;
+
+    _pixman_image_validate (src);
+    _pixman_image_validate (dst);
+
+    box.x1 = INT32_MAX;
+    box.y1 = INT32_MAX;
+    box.x2 = INT32_MIN;
+    box.y2 = INT32_MIN;
+    
+    for (i = 0; i < n_traps; ++i)
+    {
+	const pixman_trapezoid_t *trap = &(traps[i]);
+	int y1, y2;
+
+	if (!pixman_trapezoid_valid (trap))
+	    continue;
+	
+	y1 = pixman_fixed_to_int (trap->top);
+	if (y1 < box.y1)
+	    box.y1 = y1;
+	
+	y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
+	if (y2 > box.y2)
+	    box.y2 = y2;
+
+#define EXTEND_MIN(x)							\
+	if (pixman_fixed_to_int ((x)) < box.x1)				\
+	    box.x1 = pixman_fixed_to_int ((x));
+#define EXTEND_MAX(x)							\
+	if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box.x2)	\
+	    box.x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
+
+#define EXTEND(x)							\
+	EXTEND_MIN(x);							\
+	EXTEND_MAX(x);
+
+	EXTEND(trap->left.p1.x);
+	EXTEND(trap->left.p2.x);
+	EXTEND(trap->right.p1.x);
+	EXTEND(trap->right.p2.x);
+    }
+
+    if (box.x1 >= box.x2 || box.y1 >= box.y2)
+	return;
+    
+    tmp = pixman_image_create_bits (
+	mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1);
+	
+    for (i = 0; i < n_traps; ++i)
+    {
+	const pixman_trapezoid_t *trap = &(traps[i]);
+
+	if (!pixman_trapezoid_valid (trap))
+	    continue;
+
+	pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
+    }
+
+    x_rel = box.x1 + x_src - x_dst;
+    y_rel = box.y1 + y_src - y_dst;
+
+    pixman_image_composite (op, src, tmp, dst,
+			    x_rel, y_rel, 0, 0, box.x1, box.y1,
+			    box.x2 - box.x1, box.y2 - box.y1);
+
+    pixman_image_unref (tmp);
+}
diff --git a/pixman/pixman.h b/pixman/pixman.h
index b95d0e9..52ab8a5 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -950,7 +950,17 @@ void           pixman_rasterize_trapezoid  (pixman_image_t            *image,
 					    const pixman_trapezoid_t  *trap,
 					    int                        x_off,
 					    int                        y_off);
-
+void          pixman_composite_trapezoids (pixman_op_t		       op,
+					   pixman_image_t *	       src,
+					   pixman_image_t *	       dst,
+					   pixman_format_code_t	       mask_format,
+					   int			       x_src,
+					   int			       y_src,
+					   int			       x_dst,
+					   int			       y_dst,
+					   int			       n_traps,
+					   const pixman_trapezoid_t *  traps);
+    
 PIXMAN_END_DECLS
 
 #endif /* PIXMAN_H__ */


More information about the xorg-commit mailing list