PATCH: Minor performance improvements to Bentley-Ottman algorithm

Mikko Strandborg <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <CD54CE37.C868%[email protected]>
Hi,

Attached patch improves the performance of Bentley-Ottman algorithm implementation.

--Mikko

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
0001-perf-Small-optimizations-to-bentley-ottman-implement.patch (application/octet-stream, 4.9 KB)
From b2768f5561a63b1867b58a660c6f6c0f1062d792 Mon Sep 17 00:00:00 2001
From: Marko Kuukkanen <[email protected]>
Date: Thu, 21 Feb 2013 13:30:22 +0200
Subject: [PATCH] [perf] Small optimizations to bentley-ottman implementation

---
 src/cairo-bentley-ottmann.c |   85 ++++++++++++++++++++++++++++++++++++-------
 src/cairo-combsort-inline.h |    2 +-
 2 files changed, 72 insertions(+), 15 deletions(-)

diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index 0e1a3f5..b2d7015 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -569,15 +569,17 @@ _cairo_bo_sweep_line_compare_edges (const cairo_bo_sweep_line_t	*sweep_line,
 {
     int cmp;
 
+    /* Most of the time the edges are not identical and we fall into
+     * either of these cases. */
+    if (MAX (a->edge.line.p1.x, a->edge.line.p2.x) <
+	MIN (b->edge.line.p1.x, b->edge.line.p2.x))
+	return -1;
+    else if (MIN (a->edge.line.p1.x, a->edge.line.p2.x) >
+	     MAX (b->edge.line.p1.x, b->edge.line.p2.x))
+	return 1;
+
     /* compare the edges if not identical */
     if (! _line_equal (&a->edge.line, &b->edge.line)) {
-	if (MAX (a->edge.line.p1.x, a->edge.line.p2.x) <
-	    MIN (b->edge.line.p1.x, b->edge.line.p2.x))
-	    return -1;
-	else if (MIN (a->edge.line.p1.x, a->edge.line.p2.x) >
-		 MAX (b->edge.line.p1.x, b->edge.line.p2.x))
-	    return 1;
-
 	cmp = edges_compare_x_for_y (a, b, sweep_line->current_y);
 	if (cmp)
 	    return cmp;
@@ -876,7 +878,13 @@ cairo_bo_event_compare (const cairo_bo_event_t *a,
 {
     int cmp;
 
-    cmp = _cairo_bo_point32_compare (&a->point, &b->point);
+    /* At least in gcc ARM compiler this is faster than calling
+     * inlined _cairo_bo_point32_compare */
+    cmp = a->point.y - b->point.y;
+    if (cmp)
+	return cmp;
+
+    cmp = a->point.x - b->point.x;
     if (cmp)
 	return cmp;
 
@@ -1040,11 +1048,59 @@ _cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue)
     return event;
 }
 
-CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
+CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_comb_sort,
 			cairo_bo_event_t *,
 			cairo_bo_event_compare)
 
 static void
+_cairo_bo_event_queue_sort (cairo_bo_event_t **base,
+			    unsigned int nmemb)
+{
+#define SWAP(x,y) if (cairo_bo_event_compare (base[x], base[y]) > 0) { \
+  tmp = base[x]; \
+  base[x] = base[y]; \
+  base[y] = tmp; \
+}
+    cairo_bo_event_t *tmp;
+    /* For small lists, use optimal sorting networks (Bose-Nelson) */
+    switch (nmemb) {
+	case 2:
+	    SWAP (0, 1);
+	    break;
+	case 3:
+	    SWAP (1, 2); SWAP (0, 2); SWAP (0, 1);
+	    break;
+	case 4:
+	    SWAP (0, 1); SWAP (2, 3); SWAP (0, 2); SWAP (1, 3); SWAP (1, 2);
+	    break;
+	case 5:
+	    SWAP (0, 1); SWAP (3, 4); SWAP (2, 4); SWAP (2, 3); SWAP(0, 3);
+	    SWAP (0, 2); SWAP (1, 4); SWAP (1, 3); SWAP (1, 2);
+	    break;
+	case 6:
+	    SWAP (1, 2); SWAP (0, 2); SWAP (0, 1); SWAP (4, 5); SWAP (3, 5);
+	    SWAP (3, 4); SWAP (0, 3); SWAP (1, 4); SWAP (2, 5); SWAP (2, 4);
+	    SWAP (1, 3); SWAP (2, 3);
+	    break;
+	case 7:
+	    SWAP (1, 2); SWAP (0, 2); SWAP (0, 1); SWAP (3, 4); SWAP (5, 6);
+	    SWAP (3, 5); SWAP (4, 6); SWAP (4, 5); SWAP (0, 4); SWAP (0, 3);
+	    SWAP (1, 5); SWAP (2, 6); SWAP (2, 5); SWAP (1, 3); SWAP (2, 4);
+	    SWAP(2, 3);
+	    break;
+	case 8:
+	    SWAP (0, 1); SWAP (2, 3); SWAP (0, 2); SWAP (1, 3); SWAP (1, 2);
+	    SWAP (4, 5); SWAP (6, 7); SWAP (4, 6); SWAP (5, 7); SWAP (5, 6);
+	    SWAP (0, 4); SWAP (1, 5); SWAP (1, 4); SWAP (2, 6); SWAP (3, 7);
+	    SWAP (3, 6); SWAP (2, 4); SWAP (3, 5); SWAP (3, 4);
+	    break;
+	default:
+	    _cairo_bo_event_queue_comb_sort (base, nmemb);
+    }
+#undef SWAP
+}
+
+static void
 _cairo_bo_event_queue_init (cairo_bo_event_queue_t	 *event_queue,
 			    cairo_bo_event_t		**start_events,
 			    int				  num_events)
@@ -1327,6 +1383,12 @@ edges_colinear (cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
 	return p;
     }
 
+    /* Most of the time slopes are not identical, so check this first */
+    if (_slope_compare (a, b)) {
+	a->colinear = MARK_COLINEAR(b, 0);
+	return FALSE;
+    }
+
     p = 0;
     p |= (a->edge.line.p1.x == b->edge.line.p1.x) << 0;
     p |= (a->edge.line.p1.y == b->edge.line.p1.y) << 1;
@@ -1337,11 +1399,6 @@ edges_colinear (cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
 	return TRUE;
     }
 
-    if (_slope_compare (a, b)) {
-	a->colinear = MARK_COLINEAR(b, 0);
-	return FALSE;
-    }
-
     /* The choice of y is not truly arbitrary since we must guarantee that it
      * is greater than the start of either line.
      */
diff --git a/src/cairo-combsort-inline.h b/src/cairo-combsort-inline.h
index d359fae..1d9456b 100644
--- a/src/cairo-combsort-inline.h
+++ b/src/cairo-combsort-inline.h
@@ -41,7 +41,7 @@ _cairo_combsort_newgap (unsigned int gap)
   gap = 10 * gap / 13;
   if (gap == 9 || gap == 10)
     gap = 11;
-  if (gap < 1)
+  else if (gap < 1)
     gap = 1;
   return gap;
 }
-- 
1.7.9.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.