[Pixman] [PATCH 4/8] pixman-utils.c, pixman-private.h: Add floating point conversion routines
Søren Sandmann Pedersen
sandmann at cs.au.dk
Sat Aug 25 18:45:13 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 | 23 ++++++++++++
pixman/pixman-utils.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+)
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 4abdc9f..6dc476e 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,
@@ -774,12 +784,22 @@ 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,
@@ -951,6 +971,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 93c061a..ad91ae9 100644
--- a/pixman/pixman-utils.c
+++ b/pixman/pixman-utils.c
@@ -274,6 +274,104 @@ 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 ARGB8 format to argb_t. To preserve
+ * precision, it needs to know the original source format. 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)
+{
+ /*
+ * Determine the sizes of each component and the masks and shifts
+ * required to extract them from the source pixel.
+ */
+ const int a_size = PIXMAN_FORMAT_A (format),
+ r_size = PIXMAN_FORMAT_R (format),
+ g_size = PIXMAN_FORMAT_G (format),
+ b_size = PIXMAN_FORMAT_B (format);
+ const int a_shift = 32 - a_size,
+ r_shift = 24 - r_size,
+ g_shift = 16 - g_size,
+ b_shift = 8 - b_size;
+ int i;
+
+ /* 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.11.4
More information about the Pixman
mailing list