[Pixman] [PATCH 05/10] pixman-utils.c, pixman-private.h: Add floating point conversion routines

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


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

A new struct argb_t containing a floating point pixel is added to
pixman-private.h, and conversion routines are added to pixman-utils.c
to convert normalized integers to and from that struct.

New functions:

  - pixman_expand_to_float()
    Expands a buffer of integer pixels to a buffer of argb_t pixels

  - pixman_contract_from_float()
    Converts a buffer of argb_t pixels to a buffer integer pixels

  - pixman_float_to_unorm()
    Converts a floating point number to an unsigned normalized integer

  - pixman_unorm_to_float()
    Converts an unsigned normalized integer to a floating point number
---
 pixman/pixman-private.h |   35 +++++++++++++++
 pixman/pixman-utils.c   |  107 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 142 insertions(+), 0 deletions(-)

diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index c82316f..91f35ed 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -45,6 +45,16 @@ typedef struct radial_gradient radial_gradient_t;
 typedef struct bits_image bits_image_t;
 typedef struct circle circle_t;
 
+typedef struct argb_t argb_t;
+
+struct argb_t
+{
+    float a;
+    float r;
+    float g;
+    float b;
+};
+
 typedef void (*fetch_scanline_t) (pixman_image_t *image,
 				  int             x,
 				  int             y,
@@ -792,12 +802,34 @@ pixman_expand (uint64_t *           dst,
                const uint32_t *     src,
                pixman_format_code_t format,
                int                  width);
+void
+pixman_expand_to_float (argb_t               *dst,
+			const uint32_t       *src,
+			pixman_format_code_t  format,
+			int                   width);
 
 void
 pixman_contract (uint32_t *      dst,
                  const uint64_t *src,
                  int             width);
 
+void
+pixman_contract_from_float (uint32_t     *dst,
+			    const argb_t *src,
+			    int           width);
+
+pixman_bool_t
+_pixman_lookup_composite_function (pixman_implementation_t     *toplevel,
+				   pixman_op_t			op,
+				   pixman_format_code_t		src_format,
+				   uint32_t			src_flags,
+				   pixman_format_code_t		mask_format,
+				   uint32_t			mask_flags,
+				   pixman_format_code_t		dest_format,
+				   uint32_t			dest_flags,
+				   pixman_implementation_t    **out_imp,
+				   pixman_composite_func_t     *out_func);
+
 /* Region Helpers */
 pixman_bool_t
 pixman_region32_copy_from_region16 (pixman_region32_t *dst,
@@ -957,6 +989,9 @@ unorm_to_unorm (uint32_t val, int from_bits, int to_bits)
     return result;
 }
 
+uint16_t pixman_float_to_unorm (float f, int n_bits);
+float pixman_unorm_to_float (uint16_t u, int n_bits);
+
 /*
  * Various debugging code
  */
diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c
index e4a9730..4f9db29 100644
--- a/pixman/pixman-utils.c
+++ b/pixman/pixman-utils.c
@@ -162,6 +162,113 @@ pixman_expand (uint64_t *           dst,
     }
 }
 
+static force_inline uint16_t
+float_to_unorm (float f, int n_bits)
+{
+    uint32_t u;
+
+    if (f > 1.0)
+	f = 1.0;
+    if (f < 0.0)
+	f = 0.0;
+
+    u = f * (1 << n_bits);
+    u -= (u >> n_bits);
+
+    return u;
+}
+
+static force_inline float
+unorm_to_float (uint16_t u, int n_bits)
+{
+    uint32_t m = ((1 << n_bits) - 1);
+
+    return (u & m) * (1.f / (float)m);
+}
+
+/*
+ * This function expands images from a8r8g8b8 to argb_t.  To preserve
+ * precision, it needs to know from which source format the a8r8g8b8 pixels
+ * originally came.
+ *
+ * For example, if the source was PIXMAN_x1r5g5b5 and the red component
+ * contained bits 12345, then the 8-bit value is 12345123.  To correctly
+ * expand this to floating point, it should be 12345 / 31.0 and not
+ * 12345123 / 255.0.
+ */
+void
+pixman_expand_to_float (argb_t               *dst,
+			const uint32_t       *src,
+			pixman_format_code_t  format,
+			int                   width)
+{
+    int a_size, r_size, g_size, b_size;
+    int a_shift, r_shift, g_shift, b_shift;
+    int i;
+
+    if (!PIXMAN_FORMAT_VIS (format))
+	format = PIXMAN_a8r8g8b8;
+
+    /*
+     * Determine the sizes of each component and the masks and shifts
+     * required to extract them from the source pixel.
+     */
+    a_size = PIXMAN_FORMAT_A (format);
+    r_size = PIXMAN_FORMAT_R (format);
+    g_size = PIXMAN_FORMAT_G (format);
+    b_size = PIXMAN_FORMAT_B (format);
+
+    a_shift = 32 - a_size;
+    r_shift = 24 - r_size;
+    g_shift = 16 - g_size;
+    b_shift =  8 - b_size;
+
+    /* Start at the end so that we can do the expansion in place
+     * when src == dst
+     */
+    for (i = width - 1; i >= 0; i--)
+    {
+	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;
+    }
+}
+
+uint16_t
+pixman_float_to_unorm (float f, int n_bits)
+{
+    return float_to_unorm (f, n_bits);
+}
+
+float
+pixman_unorm_to_float (uint16_t u, int n_bits)
+{
+    return unorm_to_float (u, n_bits);
+}
+
+void
+pixman_contract_from_float (uint32_t     *dst,
+			    const argb_t *src,
+			    int           width)
+{
+    int i;
+
+    for (i = 0; i < width; ++i)
+    {
+	uint8_t a, r, g, b;
+
+	a = float_to_unorm (src[i].a, 8);
+	r = float_to_unorm (src[i].r, 8);
+	g = float_to_unorm (src[i].g, 8);
+	b = float_to_unorm (src[i].b, 8);
+
+	dst[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
+    }
+}
+
 /*
  * Contracting is easier than expanding.  We just need to truncate the
  * components.
-- 
1.7.4



More information about the Pixman mailing list