summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2010-02-16 00:07:15 +0100
committerBenjamin Otte <otte@redhat.com>2010-04-07 10:38:42 +0200
commitfc5f665b6543adcbda6ff2e517f9f2177c75b397 (patch)
tree3fea2f835c7074146d61ef619aca10ccce5f699d
parent97a71697cd7c08901df985acba08fa4931331bf2 (diff)
Make color space handling more advanced
Code now does not only provide to/from_argb functions, but instead returns a converter function. This converter function converts from the given source color space to the given target color space. Includes an implementation for YUV HD and SD, JPEG is still missing.
-rw-r--r--pixman/pixman-color-space-private.h29
-rw-r--r--pixman/pixman-color-space.c293
-rw-r--r--pixman/pixman-general.c77
-rw-r--r--pixman/pixman-image.c28
-rw-r--r--pixman/pixman-private.h18
5 files changed, 298 insertions, 147 deletions
diff --git a/pixman/pixman-color-space-private.h b/pixman/pixman-color-space-private.h
index 383bebd..f283f69 100644
--- a/pixman/pixman-color-space-private.h
+++ b/pixman/pixman-color-space-private.h
@@ -27,24 +27,21 @@
#include "pixman-private.h"
-void
-_pixman_color_space_to_argb_32 (pixman_color_space_t color_space,
- uint32_t * values,
- int width);
-
-void
-_pixman_color_space_from_argb_32 (pixman_color_space_t color_space,
- uint32_t * values,
- int width);
+typedef struct _pixman_color_space pixman_color_space_matrix_t;
+struct _pixman_color_space {
+ int m[3][4];
+};
-void
-_pixman_color_space_to_argb_64 (pixman_color_space_t color_space,
- uint64_t * values,
- int width);
+typedef void (*color_space_convert_t) (void *closure,
+ uint32_t *values,
+ int width);
void
-_pixman_color_space_from_argb_64 (pixman_color_space_t color_space,
- uint64_t * values,
- int width);
+_pixman_color_space_get_converter (pixman_color_space_t source,
+ pixman_color_space_t target,
+ pixman_bool_t alpha,
+ pixman_bool_t wide,
+ color_space_convert_t *func,
+ void **data);
#endif /* PIXMAN_COLOR_SPACE_PRIVATE_H */
diff --git a/pixman/pixman-color-space.c b/pixman/pixman-color-space.c
index 1046978..5b3e4e1 100644
--- a/pixman/pixman-color-space.c
+++ b/pixman/pixman-color-space.c
@@ -30,8 +30,6 @@
#include "pixman-color-space-private.h"
-#include "pixman-private.h"
-
/* uint32_t versions */
static uint32_t
@@ -51,6 +49,8 @@ unpremultiply_32 (uint32_t value)
if (alpha == 0)
return 0;
+ if (alpha == 0xff)
+ return value;
return (value & 0xff000000) |
((((value & 0x00ff0000) * 255 + 127) / alpha) & 0x00ff0000) |
@@ -58,54 +58,68 @@ unpremultiply_32 (uint32_t value)
((((value & 0x000000ff) * 255 + 127) / alpha) & 0x000000ff);
}
-void
-_pixman_color_space_to_argb_32 (pixman_color_space_t color_space,
- uint32_t * values,
- int width)
+static void
+converter_premultiply_32 (void *unused, uint32_t *values, int width)
{
int i;
- switch (color_space)
- {
- case PIXMAN_COLOR_SPACE_ARGB:
- break;
- case PIXMAN_COLOR_SPACE_ARGB_UNMULTIPLIED:
- for (i = 0; i < width; i++)
- values[i] = premultiply_32 (values[i]);
- break;
- case PIXMAN_COLOR_SPACE_YCBCR_HD:
- case PIXMAN_COLOR_SPACE_YCBCR_SD:
- case PIXMAN_COLOR_SPACE_YCBCR_JPEG:
- /* XXX */
- break;
- default:
- break;
- }
+ for (i = 0; i < width; i++)
+ values[i] = premultiply_32 (values[i]);
}
-void
-_pixman_color_space_from_argb_32 (pixman_color_space_t color_space,
- uint32_t * values,
- int width)
+static void
+converter_unpremultiply_32 (void *unused, uint32_t *values, int width)
{
int i;
- switch (color_space)
- {
- case PIXMAN_COLOR_SPACE_ARGB:
- break;
- case PIXMAN_COLOR_SPACE_ARGB_UNMULTIPLIED:
- for (i = 0; i < width; i++)
- values[i] = unpremultiply_32 (values[i]);
- break;
- case PIXMAN_COLOR_SPACE_YCBCR_HD:
- case PIXMAN_COLOR_SPACE_YCBCR_SD:
- case PIXMAN_COLOR_SPACE_YCBCR_JPEG:
- /* XXX */
- break;
- default:
- break;
- }
+ for (i = 0; i < width; i++)
+ values[i] = unpremultiply_32 (values[i]);
+}
+
+static uint32_t
+apply_matrix_32 (const pixman_color_space_matrix_t *matrix, uint32_t value)
+{
+ int a, b, c, x, y, z;
+ x = (value >> 16) & 0xff;
+ y = (value >> 8) & 0xff;
+ z = value & 0xff;
+ a = x * matrix->m[0][0] + y * matrix->m[0][1] + z * matrix->m[0][2] + matrix->m[0][3];
+ b = x * matrix->m[1][0] + y * matrix->m[1][1] + z * matrix->m[1][2] + matrix->m[1][3];
+ c = x * matrix->m[2][0] + y * matrix->m[2][1] + z * matrix->m[2][2] + matrix->m[2][3];
+ return (value & 0xff000000) |
+ (a < 0 ? 0 : (a > 0xff00 ? 0xff0000 : (a & 0xff00) << 8)) |
+ (b < 0 ? 0 : (b > 0xff00 ? 0x00ff00 : b & 0xff00 )) |
+ (c < 0 ? 0 : (c > 0xff00 ? 0x0000ff : c >> 8));
+}
+
+static void
+converter_matrix_32 (void *data, uint32_t *values, int width)
+{
+ const pixman_color_space_matrix_t *matrix = (const pixman_color_space_matrix_t *) data;
+ int i;
+
+ for (i = 0; i < width; i++)
+ values[i] = apply_matrix_32 (matrix, values[i]);
+}
+
+static void
+converter_unpremultiply_matrix_32 (void *data, uint32_t *values, int width)
+{
+ const pixman_color_space_matrix_t *matrix = (const pixman_color_space_matrix_t *) data;
+ int i;
+
+ for (i = 0; i < width; i++)
+ values[i] = apply_matrix_32 (matrix, unpremultiply_32 (values[i]));
+}
+
+static void
+converter_matrix_premultiply_32 (void *data, uint32_t *values, int width)
+{
+ const pixman_color_space_matrix_t *matrix = (const pixman_color_space_matrix_t *) data;
+ int i;
+
+ for (i = 0; i < width; i++)
+ values[i] = premultiply_32 (apply_matrix_32 (matrix, values[i]));
}
/* uint64_t versions */
@@ -127,6 +141,8 @@ unpremultiply_64 (uint64_t value)
if (alpha == 0)
return 0;
+ if (alpha == 0xffff)
+ return value;
return (value & 0xffff000000000000ULL) |
((((value & 0x0000ffff00000000ULL) * 255 + 127) / alpha) & 0x0000ffff00000000ULL) |
@@ -134,52 +150,185 @@ unpremultiply_64 (uint64_t value)
((((value & 0x000000000000ffffULL) * 255 + 127) / alpha) & 0x000000000000ffffULL);
}
-void
-_pixman_color_space_to_argb_64 (pixman_color_space_t color_space,
- uint64_t * values,
- int width)
+static uint64_t
+apply_matrix_64 (const pixman_color_space_matrix_t *matrix, uint64_t value)
+{
+ int a, b, c, x, y, z;
+ x = (value >> 32) & 0xffff;
+ y = (value >> 16) & 0xffff;
+ z = value & 0xffff;
+ a = x * matrix->m[0][0] + y * matrix->m[0][1] + z * matrix->m[0][2] + matrix->m[0][3];
+ b = x * matrix->m[1][0] + y * matrix->m[1][1] + z * matrix->m[1][2] + matrix->m[1][3];
+ c = x * matrix->m[2][0] + y * matrix->m[2][1] + z * matrix->m[2][2] + matrix->m[2][3];
+ return (value & 0xffff000000000000) |
+ (a < 0 ? 0 : (a > 0xffff00 ? 0xffff00000000 : (a & 0xffff00) << 24)) |
+ (b < 0 ? 0 : (b > 0xffff00 ? 0x0000ffff0000 : (b & 0xffff00) << 8)) |
+ (c < 0 ? 0 : (c > 0xffff00 ? 0x00000000ffff : c >> 8));
+}
+
+static void
+converter_premultiply_64 (void *unused, uint32_t *values32, int width)
{
+ uint64_t *values = (uint64_t *) values32;
int i;
+ for (i = 0; i < width; i++)
+ values[i] = premultiply_64 (values[i]);
+}
+
+static void
+converter_unpremultiply_64 (void *unused, uint32_t *values32, int width)
+{
+ uint64_t *values = (uint64_t *) values32;
+ int i;
+
+ for (i = 0; i < width; i++)
+ values[i] = unpremultiply_64 (values[i]);
+}
+
+static void
+converter_matrix_64 (void *data, uint32_t *values32, int width)
+{
+ const pixman_color_space_matrix_t *matrix = (const pixman_color_space_matrix_t *) data;
+ uint64_t *values = (uint64_t *) values32;
+ int i;
+
+ for (i = 0; i < width; i++)
+ values[i] = apply_matrix_64 (matrix, values[i]);
+}
+
+static void
+converter_unpremultiply_matrix_64 (void *data, uint32_t *values32, int width)
+{
+ const pixman_color_space_matrix_t *matrix = (const pixman_color_space_matrix_t *) data;
+ uint64_t *values = (uint64_t *) values32;
+ int i;
+
+ for (i = 0; i < width; i++)
+ values[i] = apply_matrix_64 (matrix, unpremultiply_64 (values[i]));
+}
+
+static void
+converter_matrix_premultiply_64 (void *data, uint32_t *values32, int width)
+{
+ const pixman_color_space_matrix_t *matrix = (const pixman_color_space_matrix_t *) data;
+ uint64_t *values = (uint64_t *) values32;
+ int i;
+
+ for (i = 0; i < width; i++)
+ values[i] = premultiply_64 (apply_matrix_64 (matrix, values[i]));
+}
+
+/* matrices */
+
+static const pixman_color_space_matrix_t sd_to_rgb = { {
+ { 298, 0, 409, -57068 },
+ { 298, -100, -208, 34784 },
+ { 298, 516, 0, -70688 }
+} };
+static const pixman_color_space_matrix_t hd_to_rgb = { {
+ { 42, 0, 203, -63514 },
+ { 42, -55, -136, 19681 },
+ { 42, 29, 0, -73988 }
+} };
+static const pixman_color_space_matrix_t rgb_to_sd = { {
+ { 66, 129, 25, 4224 },
+ { -38, -74, 112, 32896 },
+ { 112, -94, -18, 32896 }
+} };
+static const pixman_color_space_matrix_t rgb_to_hd = { {
+ { 47, 157, 16, 4224 },
+ { -26, -87, 112, 32896 },
+ { 112, -102, -10, 32896 }
+} };
+/* FIXME */
+static const pixman_color_space_matrix_t rgb_to_jpeg = { { { 0, }, } };
+static const pixman_color_space_matrix_t jpeg_to_rgb = { { { 0, }, } };
+static const pixman_color_space_matrix_t sd_to_hd = { { { 0, }, } };
+static const pixman_color_space_matrix_t hd_to_sd = { { { 0, }, } };
+static const pixman_color_space_matrix_t sd_to_jpeg = { { { 0, }, } };
+static const pixman_color_space_matrix_t jpeg_to_sd = { { { 0, }, } };
+static const pixman_color_space_matrix_t jpeg_to_hd = { { { 0, }, } };
+static const pixman_color_space_matrix_t hd_to_jpeg = { { { 0, }, } };
+
+static const pixman_color_space_matrix_t *matrices[5][5] = {
+ { NULL, NULL, &rgb_to_hd, &rgb_to_sd, &rgb_to_jpeg },
+ { NULL, NULL, &rgb_to_hd, &rgb_to_sd, &rgb_to_jpeg },
+ { &hd_to_rgb, &hd_to_rgb, NULL, &hd_to_sd, &hd_to_jpeg },
+ { &sd_to_rgb, &hd_to_rgb, &sd_to_hd, NULL, &sd_to_jpeg },
+ { &jpeg_to_rgb, &jpeg_to_rgb, &jpeg_to_hd, &jpeg_to_sd, NULL }
+};
+
+/* public API */
+
+static pixman_bool_t
+_pixman_color_space_is_premultiplied (pixman_color_space_t color_space)
+{
switch (color_space)
{
- case PIXMAN_COLOR_SPACE_ARGB:
- break;
case PIXMAN_COLOR_SPACE_ARGB_UNMULTIPLIED:
- for (i = 0; i < width; i++)
- values[i] = premultiply_64 (values[i]);
- break;
case PIXMAN_COLOR_SPACE_YCBCR_HD:
case PIXMAN_COLOR_SPACE_YCBCR_SD:
case PIXMAN_COLOR_SPACE_YCBCR_JPEG:
- /* XXX */
- break;
+ return FALSE;
+ case PIXMAN_COLOR_SPACE_ARGB:
default:
- break;
+ return TRUE;
}
}
void
-_pixman_color_space_from_argb_64 (pixman_color_space_t color_space,
- uint64_t * values,
- int width)
+_pixman_color_space_get_converter (pixman_color_space_t source,
+ pixman_color_space_t target,
+ pixman_bool_t alpha,
+ pixman_bool_t wide,
+ color_space_convert_t *func,
+ void ** data)
{
- int i;
+ const pixman_color_space_matrix_t *matrix;
- switch (color_space)
+ if (source == target)
{
- case PIXMAN_COLOR_SPACE_ARGB:
- break;
- case PIXMAN_COLOR_SPACE_ARGB_UNMULTIPLIED:
- for (i = 0; i < width; i++)
- values[i] = unpremultiply_64 (values[i]);
- break;
- case PIXMAN_COLOR_SPACE_YCBCR_HD:
- case PIXMAN_COLOR_SPACE_YCBCR_SD:
- case PIXMAN_COLOR_SPACE_YCBCR_JPEG:
- /* XXX */
- break;
- default:
- break;
+ *func = NULL;
+ *data = NULL;
+ return;
}
+
+ matrix = matrices[source][target];
+
+ if (!alpha)
+ {
+ if (matrix)
+ *func = wide ? converter_matrix_64 : converter_matrix_32;
+ else
+ *func = NULL;
+ }
+ else
+ {
+ if (_pixman_color_space_is_premultiplied (source))
+ {
+ assert (!_pixman_color_space_is_premultiplied (target));
+
+ if (matrix)
+ *func = wide ? converter_unpremultiply_matrix_64 : converter_unpremultiply_matrix_32;
+ else
+ *func = wide ? converter_unpremultiply_64 : converter_unpremultiply_32;
+ }
+ else if (_pixman_color_space_is_premultiplied (target))
+ {
+ if (matrix)
+ *func = wide ? converter_matrix_premultiply_64 : converter_matrix_premultiply_32;
+ else
+ *func = wide ? converter_premultiply_64 : converter_premultiply_32;
+ }
+ else
+ {
+ if (matrix)
+ *func = wide ? converter_matrix_64 : converter_matrix_32;
+ else
+ *func = NULL;
+ }
+ }
+ *data = (void *) matrix;
}
+
diff --git a/pixman/pixman-general.c b/pixman/pixman-general.c
index 1d18133..321ff6b 100644
--- a/pixman/pixman-general.c
+++ b/pixman/pixman-general.c
@@ -70,6 +70,8 @@ general_composite_rect (pixman_implementation_t *imp,
const int Bpp = wide ? 8 : 4;
uint8_t *scanline_buffer = stack_scanline_buffer;
uint8_t *src_buffer, *mask_buffer, *dest_buffer;
+ color_space_convert_t convert_src, convert_mask, convert_dest, convert_dest_inv;
+ void *convert_src_data, *convert_mask_data, *convert_dest_data, *convert_dest_inv_data;
fetch_scanline_t fetch_src = NULL, fetch_mask = NULL, fetch_dest = NULL;
pixman_combine_32_func_t compose;
store_scanline_t store;
@@ -106,32 +108,75 @@ general_composite_rect (pixman_implementation_t *imp,
if (op == PIXMAN_OP_CLEAR)
fetch_src = NULL;
- else if (src->common.type == BITS &&
- src->bits.color_space != PIXMAN_COLOR_SPACE_ARGB)
- fetch_src = wide ? _pixman_image_get_scanline_64_argb : _pixman_image_get_scanline_32_argb;
else
fetch_src = wide ? _pixman_image_get_scanline_64 : _pixman_image_get_scanline_32;
+ if (fetch_src &&
+ src->common.type == BITS)
+ {
+ _pixman_color_space_get_converter (src->bits.color_space,
+ PIXMAN_COLOR_SPACE_ARGB,
+ PIXMAN_FORMAT_A (src->bits.format),
+ wide,
+ &convert_src,
+ &convert_src_data);
+ }
+ else
+ {
+ convert_src = NULL;
+ convert_src_data = NULL;
+ }
if (!mask || op == PIXMAN_OP_CLEAR)
fetch_mask = NULL;
- else if (mask->common.type == BITS &&
- mask->bits.color_space != PIXMAN_COLOR_SPACE_ARGB)
- fetch_mask = wide ? _pixman_image_get_scanline_64_argb : _pixman_image_get_scanline_32_argb;
else
fetch_mask = wide ? _pixman_image_get_scanline_64 : _pixman_image_get_scanline_32;
+ if (fetch_mask &&
+ mask->common.type == BITS)
+ {
+ _pixman_color_space_get_converter (mask->bits.color_space,
+ PIXMAN_COLOR_SPACE_ARGB,
+ PIXMAN_FORMAT_A (mask->bits.format),
+ wide,
+ &convert_mask,
+ &convert_mask_data);
+ }
+ else
+ {
+ convert_mask = NULL;
+ convert_mask_data = NULL;
+ }
if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC)
fetch_dest = NULL;
- else if (dest->common.type == BITS &&
- dest->bits.color_space != PIXMAN_COLOR_SPACE_ARGB)
- fetch_dest = wide ? _pixman_image_get_scanline_64_argb : _pixman_image_get_scanline_32_argb;
else
fetch_dest = wide ? _pixman_image_get_scanline_64 : _pixman_image_get_scanline_32;
+ if (fetch_dest &&
+ dest->common.type == BITS)
+ {
+ _pixman_color_space_get_converter (dest->bits.color_space,
+ PIXMAN_COLOR_SPACE_ARGB,
+ PIXMAN_FORMAT_A (dest->bits.format),
+ wide,
+ &convert_dest,
+ &convert_dest_data);
+ }
+ else
+ {
+ convert_dest = NULL;
+ convert_dest_data = NULL;
+ }
+
if (wide)
store = _pixman_image_store_scanline_64;
else
store = _pixman_image_store_scanline_32;
+ _pixman_color_space_get_converter (PIXMAN_COLOR_SPACE_ARGB,
+ dest->bits.color_space,
+ PIXMAN_FORMAT_A (dest->bits.format),
+ wide,
+ &convert_dest_inv,
+ &convert_dest_inv_data);
/* Skip the store step and composite directly into the
* destination if the output format of the compose func matches
@@ -211,6 +256,8 @@ general_composite_rect (pixman_implementation_t *imp,
source can be optimized */
fetch_mask (mask, mask_x, mask_y + i,
width, (void *)mask_buffer, 0, 0);
+ if (convert_mask)
+ convert_mask (convert_mask_data, (void *)mask_buffer, width);
if (mask_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
fetch_mask = NULL;
@@ -228,11 +275,15 @@ general_composite_rect (pixman_implementation_t *imp,
width, (void *)src_buffer, (void *)mask_buffer,
0xffffffff);
}
+ if (convert_src)
+ convert_src (convert_src_data, (void *)src_buffer, width);
}
else if (fetch_mask)
{
fetch_mask (mask, mask_x, mask_y + i,
width, (void *)mask_buffer, 0, 0);
+ if (convert_mask)
+ convert_mask (convert_mask_data, (void *)mask_buffer, width);
}
if (store)
@@ -242,6 +293,8 @@ general_composite_rect (pixman_implementation_t *imp,
{
fetch_dest (dest, dest_x, dest_y + i,
width, (void *)dest_buffer, 0, 0);
+ if (convert_dest)
+ convert_dest (convert_dest_data, (void *)dest_buffer, width);
}
/* blend */
@@ -251,10 +304,8 @@ general_composite_rect (pixman_implementation_t *imp,
(void *)mask_buffer,
width);
- if (wide)
- _pixman_color_space_from_argb_64 (dest->bits.color_space, (uint64_t *) dest_buffer, width);
- else
- _pixman_color_space_from_argb_32 (dest->bits.color_space, (uint32_t *) dest_buffer, width);
+ if (convert_dest_inv)
+ convert_dest_inv (convert_dest_inv_data, (void *)dest_buffer, width);
/* write back */
store (&(dest->bits), dest_x, dest_y + i, width,
diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index ca06acf..f21e83e 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -149,20 +149,6 @@ _pixman_image_get_scanline_32 (pixman_image_t *image,
image->common.get_scanline_32 (image, x, y, width, buffer, mask, mask_bits);
}
-void
-_pixman_image_get_scanline_32_argb (pixman_image_t *image,
- int x,
- int y,
- int width,
- uint32_t * buffer,
- const uint32_t *mask,
- uint32_t mask_bits)
-{
- image->common.get_scanline_32 (image, x, y, width, buffer, mask, mask_bits);
-
- _pixman_color_space_to_argb_32 (image->bits.color_space, buffer, width);
-}
-
/* Even thought the type of buffer is uint32_t *, the function actually expects
* a uint64_t *buffer.
*/
@@ -178,20 +164,6 @@ _pixman_image_get_scanline_64 (pixman_image_t *image,
image->common.get_scanline_64 (image, x, y, width, buffer, unused, unused2);
}
-void
-_pixman_image_get_scanline_64_argb (pixman_image_t *image,
- int x,
- int y,
- int width,
- uint32_t * buffer,
- const uint32_t *unused,
- uint32_t unused2)
-{
- image->common.get_scanline_64 (image, x, y, width, buffer, unused, unused2);
-
- _pixman_color_space_to_argb_64 (image->bits.color_space, (uint64_t *) buffer, width);
-}
-
static void
image_property_changed (pixman_image_t *image)
{
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 40ed9e3..282b25a 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -253,15 +253,6 @@ _pixman_image_get_scanline_32 (pixman_image_t *image,
const uint32_t *mask,
uint32_t mask_bits);
-void
-_pixman_image_get_scanline_32_argb (pixman_image_t *image,
- int x,
- int y,
- int width,
- uint32_t * buffer,
- const uint32_t *mask,
- uint32_t mask_bits);
-
/* Even thought the type of buffer is uint32_t *, the function actually expects
* a uint64_t *buffer.
*/
@@ -275,15 +266,6 @@ _pixman_image_get_scanline_64 (pixman_image_t *image,
uint32_t unused2);
void
-_pixman_image_get_scanline_64_argb (pixman_image_t *image,
- int x,
- int y,
- int width,
- uint32_t * buffer,
- const uint32_t *unused,
- uint32_t unused2);
-
-void
_pixman_image_store_scanline_32 (bits_image_t * image,
int x,
int y,