[cairo] _cairo_lround
Daniel Amelang
daniel.amelang at gmail.com
Tue Nov 21 11:27:44 PST 2006
Jorn's latest post made me realize that I've been sitting on a bunch
of potentially useful FP patches for too long. Time to send them off,
warts and all. First up:
My softfloat profiles show a lot of time spent in functions that have
code that looks like this:
i = (int) floor (d + 0.5);
Basically, this is a popular idiom for rounding a double to an int.
Unfortunately, it suffers from the same slowdown that
_cairo_fixed_from_double did, especially when there is no FPU.
Luckily, we can apply the same magic number approach and get a nice
speedup. So I created the function _cairo_lround and replaced all
instances of this idiom with a call to it. I called it _cairo_lround
because lround has the closest sematics to what we want, with the
difference being that _cairo_lround is much faster that lround, and
_cairo_lround uses banker's rounding.
This doesn't help _that_ much on systems with an FPU (although it
doesn't hurt), but it does provide a 1.5x speedup for the text cases
on my softfloat tests. Notice that I'm using a x86 softfloat library
(with a libm also compiled for softfloat) running on my x86 machine,
so someone with a Nokia 770 needs to post their results for us to get
something truly meaningful.
Dan
-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Daniel Amelang <dan at ereba.localdomain>
Date: Thu Nov 2 22:22:17 2006 -0800
Subject: [PATCH] Add _cairo_lround for much faster rounding
This function uses the same "magic number" approach as _cairo_fixed_from_double.
---
src/cairo.c | 25 +++++++++++++++++++++++++
src/cairoint.h | 3 +++
2 files changed, 28 insertions(+), 0 deletions(-)
63abc842eef797097cb5c5a382aa6f3e635f72ca
diff --git a/src/cairo.c b/src/cairo.c
index bd1fe8b..ecc5d01 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -3196,3 +3196,28 @@ _cairo_restrict_value (double *value, do
else if (*value > max)
*value = max;
}
+
+/* This function is identical to the C99 function lround, except that it
+ * uses banker's rounding instead of arithmetic rounding. This implementation
+ * is much faster (on the platforms we care about) than lround, round, rint,
+ * lrint or float (d + 0.5).
+ *
+ * For an explanation of the inner workings of this implemenation, see the
+ * documentation for _cairo_fixed_from_double.
+ */
+#define CAIRO_MAGIC_NUMBER_INT (6755399441055744.0)
+int
+_cairo_lround (double d)
+{
+ union {
+ double d;
+ int32_t i[2];
+ } u;
+
+ u.d = d + CAIRO_MAGIC_NUMBER_INT;
+#ifdef FLOAT_WORDS_BIGENDIAN
+ return u.i[1];
+#else
+ return u.i[0];
+#endif
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 06fc8d4..d5ecf7c 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1148,6 +1148,9 @@ typedef struct _cairo_stroke_face {
cairo_private void
_cairo_restrict_value (double *value, double min, double max);
+cairo_private int
+_cairo_lround (double d);
+
/* cairo_fixed.c */
cairo_private cairo_fixed_t
_cairo_fixed_from_int (int i);
--
1.2.6
-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Daniel Amelang <dan at ereba.localdomain>
Date: Thu Nov 2 22:24:34 2006 -0800
Subject: [PATCH] Replace existing rounding code with _cairo_lround
---
src/cairo-directfb-surface.c | 12 ++++++------
src/cairo-ft-font.c | 4 ++--
src/cairo-glitz-surface.c | 4 ++--
src/cairo-scaled-font.c | 14 ++++++--------
src/cairo-win32-font.c | 14 ++++++++------
src/cairo-win32-surface.c | 7 ++++---
src/cairo-xcb-surface.c | 28 ++++++++++++++--------------
src/cairo-xlib-surface.c | 16 ++++++++--------
8 files changed, 50 insertions(+), 49 deletions(-)
8bea703cb25c4905aa2b4496c1042eeed32c4c20
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index e724ed6..fc6cbef 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -889,10 +889,10 @@ _cairo_directfb_surface_composite (cairo
TRANSFORM_POINT (m, sr.x, sr.y, x1, y1);
TRANSFORM_POINT (m, sr.x+sr.w, sr.y+sr.h, x2, y2);
- dr.x = floor (x1+.5);
- dr.y = floor (y1+.5);
- dr.w = floor (x2-x1+.5);
- dr.h = floor (y2-y1+.5);
+ dr.x = _cairo_lround (x1);
+ dr.y = _cairo_lround (y1);
+ dr.w = _cairo_lround (x2-x1);
+ dr.h = _cairo_lround (y2-y1);
D_DEBUG_AT (Cairo_DirectFB, "Running StretchBlit().\n");
@@ -1283,8 +1283,8 @@ _directfb_acquire_font_cache (cairo_dire
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- points[n].x = floor (glyphs[i].x + img->base.device_transform.x0 + .5);
- points[n].y = floor (glyphs[i].y + img->base.device_transform.y0 + .5);
+ points[n].x = _cairo_lround (glyphs[i].x + img->base.device_transform.x0);
+ points[n].y = _cairo_lround (glyphs[i].y + img->base.device_transform.y0);
if (points[n].x >= surface->width ||
points[n].y >= surface->height ||
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 25fabc9..59a5acb 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -1178,8 +1178,8 @@ _transform_glyph_bitmap (cairo_matrix_t
cairo_surface_destroy (&old_image->base);
cairo_surface_set_device_offset (&(*surface)->base,
- - floor (origin_x + 0.5),
- - floor (origin_y + 0.5));
+ - _cairo_lround (origin_x),
+ - _cairo_lround (origin_y));
return status;
}
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 940802c..1e61f29 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -2013,8 +2013,8 @@ _cairo_glitz_surface_old_show_glyphs (ca
x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
- x1 = floor (glyphs[i].x + 0.5) + x_offset;
- y1 = floor (glyphs[i].y + 0.5) + y_offset;
+ x1 = _cairo_lround (glyphs[i].x) + x_offset;
+ y1 = _cairo_lround (glyphs[i].y) + y_offset;
x2 = x1 + glyph_private->area->width;
y2 = y1 + glyph_private->area->height;
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 0a96b9d..0b060fd 100755
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -855,8 +855,8 @@ _cairo_scaled_font_glyph_device_extents
}
/* glyph images are snapped to pixel locations */
- x = (int) floor (glyphs[i].x + 0.5);
- y = (int) floor (glyphs[i].y + 0.5);
+ x = _cairo_lround (glyphs[i].x);
+ y = _cairo_lround (glyphs[i].y);
left = x + _cairo_fixed_integer_floor(scaled_glyph->bbox.p1.x);
top = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
@@ -964,12 +964,10 @@ _cairo_scaled_font_show_glyphs (cairo_sc
/* round glyph locations to the nearest pixel */
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
- x = (int) floor (glyphs[i].x +
- glyph_surface->base.device_transform.x0 +
- 0.5);
- y = (int) floor (glyphs[i].y +
- glyph_surface->base.device_transform.y0 +
- 0.5);
+ x = _cairo_lround (glyphs[i].x +
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (glyphs[i].y +
+ glyph_surface->base.device_transform.y0);
_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index ee8cd3e..58b4dd1 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -151,7 +151,8 @@ _compute_transform (cairo_win32_scaled_f
scaled_font->y_scale = - scaled_font->y_scale;
scaled_font->logical_scale = WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale;
- scaled_font->logical_size = WIN32_FONT_LOGICAL_SCALE * floor (scaled_font->y_scale + 0.5);
+ scaled_font->logical_size = WIN32_FONT_LOGICAL_SCALE *
+ _cairo_lround (scaled_font->y_scale);
}
/* The font matrix has x and y "scale" components which we extract and
@@ -165,7 +166,8 @@ _compute_transform (cairo_win32_scaled_f
&scaled_font->x_scale, &scaled_font->y_scale,
TRUE); /* XXX: Handle vertical text */
- scaled_font->logical_size = floor (WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale + 0.5);
+ scaled_font->logical_size = _cairo_lround (WIN32_FONT_LOGICAL_SCALE *
+ scaled_font->y_scale);
scaled_font->logical_scale = WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale;
}
@@ -864,8 +866,8 @@ _cairo_win32_scaled_font_glyph_bbox (voi
glyph_index_option = 0;
for (i = 0; i < num_glyphs; i++) {
- int x = floor (0.5 + glyphs[i].x);
- int y = floor (0.5 + glyphs[i].y);
+ int x = _cairo_lround (glyphs[i].x);
+ int y = _cairo_lround (glyphs[i].y);
GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | glyph_index_option,
&metrics, 0, NULL, &matrix);
@@ -966,8 +968,8 @@ _add_glyph (cairo_glyph_state_t *state,
cairo_matrix_transform_point (&state->scaled_font->device_to_logical, &user_x, &user_y);
- logical_x = floor (user_x + 0.5);
- logical_y = floor (user_y + 0.5);
+ logical_x = _cairo_lround (user_x);
+ logical_y = _cairo_lround (user_y);
if (state->glyphs.num_elements > 0) {
int dx;
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 7aeb256..118c885 100755
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1299,7 +1299,8 @@ _cairo_win32_surface_show_glyphs (void
if (i == num_glyphs - 1)
dx_buf[i] = 0;
else
- dx_buf[i] = floor(((glyphs[i+1].x - glyphs[i].x) * WIN32_FONT_LOGICAL_SCALE) + 0.5);
+ dx_buf[i] = _cairo_lround ((glyphs[i+1].x - glyphs[i].x) *
+ WIN32_FONT_LOGICAL_SCALE);
if (i == num_glyphs - 1 || glyphs[i].y != glyphs[i+1].y) {
const int offset = (i - output_count) + 1;
@@ -1310,8 +1311,8 @@ _cairo_win32_surface_show_glyphs (void
cairo_matrix_transform_point(&device_to_logical,
&user_x, &user_y);
- logical_x = floor(user_x + 0.5);
- logical_y = floor(user_y + 0.5);
+ logical_x = _cairo_lround (user_x);
+ logical_y = _cairo_lround (user_y);
win_result = ExtTextOutW(dst->dc,
logical_x,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 046c620..9c34879 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -2039,8 +2039,8 @@ _cairo_xcb_surface_add_glyph (xcb_connec
*/
/* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
- glyph_info.x = - (int) floor(glyph_surface->base.device_transform.x0 + 0.5);
- glyph_info.y = - (int) floor(glyph_surface->base.device_transform.y0 + 0.5);
+ glyph_info.x = - _cairo_lround (glyph_surface->base.device_transform.x0);
+ glyph_info.y = - _cairo_lround (glyph_surface->base.device_transform.y0);
glyph_info.width = glyph_surface->width;
glyph_info.height = glyph_surface->height;
glyph_info.x_off = 0;
@@ -2148,8 +2148,8 @@ _cairo_xcb_surface_show_glyphs_8 (cairo
stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
for (i = 0; i < num_glyphs; ++i) {
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
+ thisX = _cairo_lround (glyphs[i].x);
+ thisY = _cairo_lround (glyphs[i].y);
glyph = glyphs[i].index;
xcb_render_util_glyphs_8 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
lastX = thisX;
@@ -2161,8 +2161,8 @@ _cairo_xcb_surface_show_glyphs_8 (cairo
src->src_picture,
dst->dst_picture,
font_private->xrender_format->id,
- src_x_offset + (int) floor (glyphs[0].x + 0.5),
- src_y_offset + (int) floor (glyphs[0].y + 0.5),
+ src_x_offset + _cairo_lround (glyphs[0].x),
+ src_y_offset + _cairo_lround (glyphs[0].y),
stream);
xcb_render_util_composite_text_free (stream);
@@ -2189,8 +2189,8 @@ _cairo_xcb_surface_show_glyphs_16 (cairo
stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
for (i = 0; i < num_glyphs; ++i) {
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
+ thisX = _cairo_lround (glyphs[i].x);
+ thisY = _cairo_lround (glyphs[i].y);
glyph = glyphs[i].index;
xcb_render_util_glyphs_16 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
lastX = thisX;
@@ -2202,8 +2202,8 @@ _cairo_xcb_surface_show_glyphs_16 (cairo
src->src_picture,
dst->dst_picture,
font_private->xrender_format->id,
- src_x_offset + (int) floor (glyphs[0].x + 0.5),
- src_y_offset + (int) floor (glyphs[0].y + 0.5),
+ src_x_offset + _cairo_lround (glyphs[0].x),
+ src_y_offset + _cairo_lround (glyphs[0].y),
stream);
xcb_render_util_composite_text_free (stream);
@@ -2230,8 +2230,8 @@ _cairo_xcb_surface_show_glyphs_32 (cairo
stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
for (i = 0; i < num_glyphs; ++i) {
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
+ thisX = _cairo_lround (glyphs[i].x);
+ thisY = _cairo_lround (glyphs[i].y);
glyph = glyphs[i].index;
xcb_render_util_glyphs_32 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
lastX = thisX;
@@ -2243,8 +2243,8 @@ _cairo_xcb_surface_show_glyphs_32 (cairo
src->src_picture,
dst->dst_picture,
font_private->xrender_format->id,
- src_x_offset + (int) floor (glyphs[0].x + 0.5),
- src_y_offset + (int) floor (glyphs[0].y + 0.5),
+ src_x_offset + _cairo_lround (glyphs[0].x),
+ src_y_offset + _cairo_lround (glyphs[0].y),
stream);
xcb_render_util_composite_text_free (stream);
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index aaf43e4..4e7f640 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2408,8 +2408,8 @@ _cairo_xlib_surface_add_glyph (Display *
*/
/* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
- glyph_info.x = - (int) floor(glyph_surface->base.device_transform.x0 + 0.5);
- glyph_info.y = - (int) floor(glyph_surface->base.device_transform.y0 + 0.5);
+ glyph_info.x = - _cairo_lround (glyph_surface->base.device_transform.x0);
+ glyph_info.y = - _cairo_lround (glyph_surface->base.device_transform.y0);
glyph_info.width = glyph_surface->width;
glyph_info.height = glyph_surface->height;
glyph_info.xOff = 0;
@@ -2536,8 +2536,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = font_private->glyphset;
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
+ thisX = _cairo_lround (glyphs[i].x);
+ thisY = _cairo_lround (glyphs[i].y);
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;
@@ -2597,8 +2597,8 @@ _cairo_xlib_surface_show_glyphs16 (cairo
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = font_private->glyphset;
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
+ thisX = _cairo_lround (glyphs[i].x);
+ thisY = _cairo_lround (glyphs[i].y);
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;
@@ -2658,8 +2658,8 @@ _cairo_xlib_surface_show_glyphs32 (cairo
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = font_private->glyphset;
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
+ thisX = _cairo_lround (glyphs[i].x);
+ thisY = _cairo_lround (glyphs[i].y);
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;
--
1.2.6
More information about the cairo
mailing list