diff options
| author | Benjamin Otte <otte@redhat.com> | 2010-02-16 00:07:15 +0100 |
|---|---|---|
| committer | Benjamin Otte <otte@redhat.com> | 2010-04-07 10:38:42 +0200 |
| commit | fc5f665b6543adcbda6ff2e517f9f2177c75b397 (patch) | |
| tree | 3fea2f835c7074146d61ef619aca10ccce5f699d | |
| parent | 97a71697cd7c08901df985acba08fa4931331bf2 (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.h | 29 | ||||
| -rw-r--r-- | pixman/pixman-color-space.c | 293 | ||||
| -rw-r--r-- | pixman/pixman-general.c | 77 | ||||
| -rw-r--r-- | pixman/pixman-image.c | 28 | ||||
| -rw-r--r-- | pixman/pixman-private.h | 18 |
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, |
