[Pixman] [PATCH 10/10] Speed up pixman_expand_to_float()

Søren Sandmann sandmann at cs.au.dk
Wed Sep 26 13:44:03 PDT 2012


From: Søren Sandmann Pedersen <ssp at redhat.com>

GCC doesn't move the divisions out of the loop, so do it manually by
looking up the four (1.0f / mask) values in a table. Table lookups are
used under the theory that one L2 hit plus three L1 hits is preferable
to four floating point divisions.
---
 pixman/pixman-utils.c |   38 ++++++++++++++++++++++++++++++++++----
 1 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c
index 551f3f9..b1e9fb6 100644
--- a/pixman/pixman-utils.c
+++ b/pixman/pixman-utils.c
@@ -111,8 +111,28 @@ pixman_expand_to_float (argb_t               *dst,
 			pixman_format_code_t  format,
 			int                   width)
 {
+    static const float multipliers[16] = {
+	0.0f,
+	1.0f / ((1 <<  1) - 1),
+	1.0f / ((1 <<  2) - 1),
+	1.0f / ((1 <<  3) - 1),
+	1.0f / ((1 <<  4) - 1),
+	1.0f / ((1 <<  5) - 1),
+	1.0f / ((1 <<  6) - 1),
+	1.0f / ((1 <<  7) - 1),
+	1.0f / ((1 <<  8) - 1),
+	1.0f / ((1 <<  9) - 1),
+	1.0f / ((1 << 10) - 1),
+	1.0f / ((1 << 11) - 1),
+	1.0f / ((1 << 12) - 1),
+	1.0f / ((1 << 13) - 1),
+	1.0f / ((1 << 14) - 1),
+	1.0f / ((1 << 15) - 1),
+    };
     int a_size, r_size, g_size, b_size;
     int a_shift, r_shift, g_shift, b_shift;
+    float a_mul, r_mul, g_mul, b_mul;
+    uint32_t a_mask, r_mask, g_mask, b_mask;
     int i;
 
     if (!PIXMAN_FORMAT_VIS (format))
@@ -132,6 +152,16 @@ pixman_expand_to_float (argb_t               *dst,
     g_shift = 16 - g_size;
     b_shift =  8 - b_size;
 
+    a_mask = ((1 << a_size) - 1);
+    r_mask = ((1 << r_size) - 1);
+    g_mask = ((1 << g_size) - 1);
+    b_mask = ((1 << b_size) - 1);
+
+    a_mul = multipliers[a_size];
+    r_mul = multipliers[r_size];
+    g_mul = multipliers[g_size];
+    b_mul = multipliers[b_size];
+
     /* Start at the end so that we can do the expansion in place
      * when src == dst
      */
@@ -139,10 +169,10 @@ pixman_expand_to_float (argb_t               *dst,
     {
 	const uint32_t pixel = src[i];
 
-	dst[i].a = a_size? unorm_to_float (pixel >> a_shift, a_size) : 1.0;
-	dst[i].r = r_size? unorm_to_float (pixel >> r_shift, r_size) : 0.0;
-	dst[i].g = g_size? unorm_to_float (pixel >> g_shift, g_size) : 0.0;
-	dst[i].b = b_size? unorm_to_float (pixel >> b_shift, b_size) : 0.0;
+	dst[i].a = a_mask? ((pixel >> a_shift) & a_mask) * a_mul : 1.0f;
+	dst[i].r = ((pixel >> r_shift) & r_mask) * r_mul;
+	dst[i].g = ((pixel >> g_shift) & g_mask) * g_mul;
+	dst[i].b = ((pixel >> b_shift) & b_mask) * b_mul;
     }
 }
 
-- 
1.7.4



More information about the Pixman mailing list