diff options
author | Benjamin Otte <otte@redhat.com> | 2010-03-05 15:24:41 +0100 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2010-07-07 10:24:26 -0400 |
commit | 9b335d50cd5e0ac22281c7b8e2aaca4cb9c1f3b3 (patch) | |
tree | b6673200cd0e916a5cf19fa07cb249fbfbcc5876 | |
parent | 1e4f710f204f95bf2c654395ab155ed71650ee87 (diff) |
Add PIXMAN_y420planar
Contains code to make PIXMAN_yv12 fall back to PIXMAN_i420.
Also introduces the idea of an intermediate rendering target. This is
used by the y420 code to make subsampled rendering not look bad.
-rw-r--r-- | pixman/Makefile.am | 2 | ||||
-rw-r--r-- | pixman/pixman-access.c | 46 | ||||
-rw-r--r-- | pixman/pixman-bits-image.c | 20 | ||||
-rw-r--r-- | pixman/pixman-format.c | 38 | ||||
-rw-r--r-- | pixman/pixman-general.c | 1 | ||||
-rw-r--r-- | pixman/pixman-intermediate-private.h | 39 | ||||
-rw-r--r-- | pixman/pixman-intermediate.c | 167 | ||||
-rw-r--r-- | pixman/pixman-private.h | 29 | ||||
-rw-r--r-- | pixman/pixman.c | 11 | ||||
-rw-r--r-- | pixman/pixman.h | 1 |
10 files changed, 339 insertions, 15 deletions
diff --git a/pixman/Makefile.am b/pixman/Makefile.am index 0b3e40db..dc026d33 100644 --- a/pixman/Makefile.am +++ b/pixman/Makefile.am @@ -24,6 +24,8 @@ libpixman_1_la_SOURCES = \ pixman-general.c \ pixman.c \ pixman-fast-path.c \ + pixman-intermediate.c \ + pixman-intermediate-private.h \ pixman-solid-fill.c \ pixman-conical-gradient.c \ pixman-linear-gradient.c \ diff --git a/pixman/pixman-access.c b/pixman/pixman-access.c index cba64147..d4cc4a11 100644 --- a/pixman/pixman-access.c +++ b/pixman/pixman-access.c @@ -1119,6 +1119,30 @@ fetch_scanline_y422 (pixman_image_t *image, } static void +fetch_scanline_y420 (pixman_image_t *image, + int x, + int line, + int width, + uint32_t * buffer, + const uint32_t *mask) +{ + const uint8_t *y, *u, *v; + int i; + + y = (const uint8_t *) (image->bits.planes[0].bits + line * image->bits.planes[0].rowstride); + u = (const uint8_t *) (image->bits.planes[1].bits + (line >> 1) * image->bits.planes[1].rowstride); + v = (const uint8_t *) (image->bits.planes[2].bits + (line >> 1) * image->bits.planes[2].rowstride); + + for (i = x; i < x + width; i ++) + { + *buffer++ = 0xff000000 | + (y[i] << 16) | + (u[i >> 1] << 8) | + (v[i >> 1] ); + } +} + +static void fetch_scanline_yuy2 (pixman_image_t *image, int x, int line, @@ -1902,6 +1926,17 @@ fetch_pixel_y422 (bits_image_t *image, } static uint32_t +fetch_pixel_y420 (bits_image_t *image, + int offset, + int line) +{ + return 0xff000000 | + (((const uint8_t *) (image->planes[0].bits + line * image->planes[0].rowstride))[offset ] << 16) | + (((const uint8_t *) (image->planes[1].bits + (line >> 1) * image->planes[1].rowstride))[offset >> 1] << 8) | + ((const uint8_t *) (image->planes[2].bits + (line >> 1) * image->planes[2].rowstride))[offset >> 1]; +} + +static uint32_t fetch_pixel_yuy2 (bits_image_t *image, int offset, int line) @@ -2945,6 +2980,16 @@ store_scanline_y422 (bits_image_t * image, } } +static void +store_scanline_y420 (bits_image_t * image, + int x, + int y, + int width, + const uint32_t *values) +{ + store_scanline_a8r8g8b8 ((bits_image_t *) image->intermediate, x, y, width, values); +} + #define SUBSAMPLED(name,Y1,U,Y2,V) \ static void \ store_scanline_ ## name (bits_image_t * image, \ @@ -3199,6 +3244,7 @@ static const format_info_t accessors[] = /* planar formats */ FORMAT_INFO (y444), FORMAT_INFO (y422), + FORMAT_INFO (y420), /* packed formats */ FORMAT_INFO (yuy2), diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c index 04ff9549..73e27f3d 100644 --- a/pixman/pixman-bits-image.c +++ b/pixman/pixman-bits-image.c @@ -958,13 +958,29 @@ pixman_image_create_bits (pixman_format_code_t format, num_planes = pixman_format_num_planes (format); if (!bits && width && height) { + /* backwards compat */ + if (format == PIXMAN_yv12) + format = PIXMAN_y420; + free_me = bits = _pixman_format_alloc_bits (format, width, height, planes, rowstrides); if (!bits) return NULL; } else { - return_val_if_fail (num_planes == 1, NULL); + /* backwards compat */ + if (format == PIXMAN_yv12) + { + format = PIXMAN_y420; + planes[1] = bits + rowstride_bytes * ROUND_UP_2 (height); + planes[2] = planes[1] + ROUND_UP_8 (rowstride_bytes) * ROUND_UP_2 (height) / 4; + rowstrides[1] = ROUND_UP_8 (rowstride_bytes) / 2; + rowstrides[2] = ROUND_UP_8 (rowstride_bytes) / 2; + } + else + { + return_val_if_fail (num_planes == 1, NULL); + } planes[0] = bits; rowstrides[0] = rowstride_bytes; } @@ -1011,6 +1027,8 @@ pixman_image_create_planar (pixman_format_code_t format, return_val_if_fail (bits != NULL && rowstrides_bytes != NULL, NULL); return_val_if_fail (num_planes == pixman_format_num_planes (format), NULL); + return_val_if_fail (format != PIXMAN_yv12, NULL); + if (width && height) { for (plane = 0; plane < num_planes; plane++) { diff --git a/pixman/pixman-format.c b/pixman/pixman-format.c index 7d4b4c65..1bc634cd 100644 --- a/pixman/pixman-format.c +++ b/pixman/pixman-format.c @@ -131,6 +131,43 @@ alloc_y422 (pixman_format_code_t format, return bits[0]; } +static uint32_t * +alloc_y420 (pixman_format_code_t format, + int width, + int height, + uint32_t ** bits, + int * rowstrides_bytes) +{ + int y_stride, uv_stride, y_height, uv_height, y_size, uv_size; + + if (pixman_addition_overflows_int (width, 7) || + pixman_addition_overflows_int (height, 1)) + return NULL; + + y_stride = ROUND_UP_4 (width); + uv_stride = ROUND_UP_8 (width) / 2; + y_height = ROUND_UP_2 (height); + uv_height = ROUND_UP_2 (height) / 2; + + if (pixman_multiply_overflows_int (y_stride, y_height)) + return NULL; + + y_size = y_stride * y_height; + uv_size = uv_stride * uv_height; + + if (pixman_addition_overflows_int (y_size, 2 * uv_size)) + return NULL; + + bits[0] = calloc (y_size + 2 * uv_size, 1); + bits[1] = bits[0] + y_size; + bits[2] = bits[1] + uv_size; + rowstrides_bytes[0] = y_stride; + rowstrides_bytes[1] = uv_stride; + rowstrides_bytes[2] = uv_stride; + + return bits[0]; +} + typedef struct { pixman_format_code_t format; pixman_bool_t supported_source; @@ -200,6 +237,7 @@ static const format_info_t format_infos[] = { /* planar formats */ { PIXMAN_y444, TRUE, TRUE, FALSE, 3, PIXMAN_COLOR_SPACE_YCBCR_SD, alloc_y444 }, { PIXMAN_y422, TRUE, TRUE, FALSE, 3, PIXMAN_COLOR_SPACE_YCBCR_SD, alloc_y422 }, + { PIXMAN_y420, TRUE, TRUE, FALSE, 3, PIXMAN_COLOR_SPACE_YCBCR_SD, alloc_y420 }, /* packed formats */ { PIXMAN_yuy2, TRUE, TRUE, FALSE, 1, PIXMAN_COLOR_SPACE_YCBCR_SD, alloc_bits }, { PIXMAN_yvyu, TRUE, TRUE, FALSE, 1, PIXMAN_COLOR_SPACE_YCBCR_SD, alloc_bits }, diff --git a/pixman/pixman-general.c b/pixman/pixman-general.c index ac48990c..e8c95cab 100644 --- a/pixman/pixman-general.c +++ b/pixman/pixman-general.c @@ -38,6 +38,7 @@ #include "pixman-private.h" #include "pixman-color-space-private.h" #include "pixman-combine32.h" +#include "pixman-intermediate-private.h" #define SCANLINE_BUFFER_LENGTH 8192 diff --git a/pixman/pixman-intermediate-private.h b/pixman/pixman-intermediate-private.h new file mode 100644 index 00000000..2968efc8 --- /dev/null +++ b/pixman/pixman-intermediate-private.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2010 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef PIXMAN_INTERMEDIATE_PRIVATE_H +#define PIXMAN_INTERMEDIATE_PRIVATE_H + +#include "pixman-private.h" + +pixman_bool_t +_pixman_format_requires_intermediate (pixman_format_code_t format); + +pixman_bool_t +_pixman_intermediate_setup (bits_image_t *bits); + +void +_pixman_intermediate_finish (bits_image_t *bits); + +#endif /* PIXMAN_INTERMEDIATE_PRIVATE_H */ diff --git a/pixman/pixman-intermediate.c b/pixman/pixman-intermediate.c new file mode 100644 index 00000000..6bb404da --- /dev/null +++ b/pixman/pixman-intermediate.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2010 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Author: Benjamin Otte <otte@gnome.org> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "pixman-intermediate-private.h" + +#include <stdlib.h> + +static void +composite_src_x888_y420 (pixman_implementation_t *imp, + pixman_op_t op, + pixman_image_t * src_image, + pixman_image_t * mask_image, + pixman_image_t * dst_image, + int32_t src_x, + int32_t src_y, + int32_t mask_x, + int32_t mask_y, + int32_t dest_x, + int32_t dest_y, + int32_t width, + int32_t height) +{ + uint8_t *ydst, *udst, *vdst; + uint32_t *src; + int ydst_stride, udst_stride, vdst_stride, src_stride; + int x, y; + pixman_bool_t last_row, last_column; + + last_row = (dest_y + height == dst_image->bits.height) && (height & 1); + last_column = (dest_x + width == dst_image->bits.width) && (width & 1); + + /* don't treat odd offsets or sizes */ + if ((dest_x & 1) || + (dest_y & 1) || + (!last_column && (width & 1)) || + (!last_row && (height & 1))) + return; + + /* Y plane */ + PIXMAN_IMAGE_GET_PLANE (src_image, 0, src_x, src_y, uint32_t, src_stride, src, 1); + PIXMAN_IMAGE_GET_PLANE (dst_image, 0, dest_x, dest_y, uint8_t, ydst_stride, ydst, 1); + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + ydst[x] = src[x] >> 16; + } + ydst += ydst_stride; + src += src_stride; + } + + /* U and V plane */ + PIXMAN_IMAGE_GET_PLANE (src_image, 0, src_x, src_y, uint32_t, src_stride, src, 1); + PIXMAN_IMAGE_GET_PLANE (dst_image, 1, dest_x / 2, dest_y / 2, uint8_t, udst_stride, udst, 1); + PIXMAN_IMAGE_GET_PLANE (dst_image, 2, dest_x / 2, dest_y / 2, uint8_t, vdst_stride, vdst, 1); + for (y = 1; y < height; y += 2) + { + for (x = 1; x < width; x += 2) + { + udst[x >> 1] = ((src[x - 1] >> 8) + (src[x] >> 8) + (src[x + src_stride - 1] >> 8) + (src[x + src_stride] >> 8)) >> 2; + vdst[x >> 1] = ( src[x - 1] + src[x] + src[x + src_stride - 1] + src[x + src_stride] ) >> 2; + } + if (last_column) + { + udst[width >> 1] = ((src[width - 1] >> 8) + (src[width + src_stride - 1] >> 8)) >> 1; + vdst[width >> 1] = ( src[width - 1] + src[width + src_stride - 1] ) >> 1; + } + udst += udst_stride; + vdst += vdst_stride; + src += 2 * src_stride; + } + + if (last_row) + { + for (x = 1; x < width; x += 2) + { + udst[x >> 1] = ((src[x - 1] >> 8) + (src[x] >> 8)) >> 1; + vdst[x >> 1] = ( src[x - 1] + src[x] ) >> 1; + } + if (last_column) + { + udst[x >> 1] = src[x - 1] >> 8; + vdst[x >> 1] = src[x - 1]; + } + } +} + + +pixman_bool_t +_pixman_format_requires_intermediate (pixman_format_code_t format) +{ + return format == PIXMAN_y420; +} + +pixman_bool_t +_pixman_intermediate_setup (bits_image_t *bits) +{ + uint32_t *planes[PIXMAN_MAX_PLANES], *data; + int rowstrides[PIXMAN_MAX_PLANES]; + int y; + + data = _pixman_format_alloc_bits (PIXMAN_x8r8g8b8, + bits->width, bits->height, + planes, rowstrides); + if (data == NULL) + return FALSE; + + bits->intermediate = pixman_image_create_planar (PIXMAN_x8r8g8b8, + bits->color_space, + bits->width, bits->height, + 1, planes, rowstrides); + if (bits->intermediate == NULL) + { + free (data); + return FALSE; + } + + bits->bits = data; + bits->rowstride = rowstrides[0] / sizeof (uint32_t); + + for (y = 0; y < bits->height; y++) + { + bits->fetch_scanline_raw_32 ((pixman_image_t *) bits, 0, y, bits->width, data, NULL); + data += rowstrides[0] / sizeof (uint32_t); + } + + return TRUE; +} + +void +_pixman_intermediate_finish (bits_image_t *bits) +{ + composite_src_x888_y420 (NULL, PIXMAN_OP_SRC, + bits->intermediate, NULL, (pixman_image_t *) bits, + 0, 0, 0, 0, 0, 0, bits->width, bits->height); + + pixman_image_unref (bits->intermediate); + free (bits->bits); +} + diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index ad878f40..8a656430 100644 --- a/pixman/pixman-private.h +++ b/pixman/pixman-private.h @@ -202,7 +202,8 @@ struct bits_image pixman_read_memory_func_t read_func; pixman_write_memory_func_t write_func; - pixman_color_space_t color_space; + pixman_color_space_t color_space; + pixman_image_t * intermediate; struct { uint32_t * bits; @@ -305,20 +306,22 @@ uint32_t _pixman_image_get_solid (pixman_image_t * image, pixman_format_code_t format); -#define PIXMAN_IMAGE_GET_LINE(image, x, y, type, out_stride, line, mul) \ - do \ - { \ - uint32_t *__bits__; \ - int __stride__; \ - \ - __bits__ = image->bits.bits; \ - __stride__ = image->bits.rowstride; \ - (out_stride) = \ - __stride__ * (int) sizeof (uint32_t) / (int) sizeof (type); \ - (line) = \ - ((type *) __bits__) + (out_stride) * (y) + (mul) * (x); \ +#define PIXMAN_IMAGE_GET_PLANE(image, plane, x, y, type, out_stride, line, mul) \ + do \ + { \ + uint32_t *__bits__; \ + int __stride__; \ + \ + __bits__ = image->bits.planes[plane].bits; \ + __stride__ = image->bits.planes[plane].rowstride; \ + (out_stride) = \ + __stride__ * (int) sizeof (uint32_t) / (int) sizeof (type); \ + (line) = \ + ((type *) __bits__) + (out_stride) * (y) + (mul) * (x); \ } while (0) +#define PIXMAN_IMAGE_GET_LINE(image, x, y, type, out_stride, line, mul) \ + PIXMAN_IMAGE_GET_PLANE(image, 0, x, y, type, out_stride, line, mul) /* * Gradient walker */ diff --git a/pixman/pixman.c b/pixman/pixman.c index 543beaf5..32e21732 100644 --- a/pixman/pixman.c +++ b/pixman/pixman.c @@ -607,7 +607,13 @@ do_composite (pixman_implementation_t *imp, mask_flags = FAST_PATH_IS_OPAQUE; } - dest_format = dest->common.extended_format_code; + if (_pixman_format_requires_intermediate (dest->bits.format)) + { + _pixman_intermediate_setup ((bits_image_t *) dest); + dest_format = PIXMAN_x8r8g8b8; + } else { + dest_format = dest->common.extended_format_code; + } dest_flags = dest->common.flags; /* Check for pixbufs */ @@ -746,6 +752,9 @@ found: (mask_flags & FAST_PATH_SIMPLE_REPEAT), ®ion, info->func); + if (_pixman_format_requires_intermediate (dest->bits.format)) + _pixman_intermediate_finish ((bits_image_t *) dest); + if (i) { /* Make a copy of info->func, because info->func may change when diff --git a/pixman/pixman.h b/pixman/pixman.h index 1d7c1cf2..55a35757 100644 --- a/pixman/pixman.h +++ b/pixman/pixman.h @@ -726,6 +726,7 @@ typedef enum { /* planar formats */ PIXMAN_y444 = PIXMAN_FORMAT(12,PIXMAN_TYPE_PLANAR,0,0,0,1), PIXMAN_y422 = PIXMAN_FORMAT(12,PIXMAN_TYPE_PLANAR,0,0,0,2), + PIXMAN_y420 = PIXMAN_FORMAT(12,PIXMAN_TYPE_PLANAR,0,0,0,3), /* packed formats */ PIXMAN_yuy2 = PIXMAN_FORMAT(16,PIXMAN_TYPE_PACKED,0,0,0,0), |