summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2010-03-05 15:24:41 +0100
committerBenjamin Otte <otte@redhat.com>2010-04-07 10:38:43 +0200
commit7144a24143223b331b619029a09452c7d2da6c23 (patch)
tree1188deb182cdeaa86d745bc6b416fab7a592ab1b
parent27f02c1c865dd48f5c6975e12e4fbf922e3c2752 (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.am2
-rw-r--r--pixman/pixman-access.c47
-rw-r--r--pixman/pixman-bits-image.c20
-rw-r--r--pixman/pixman-format.c38
-rw-r--r--pixman/pixman-general.c1
-rw-r--r--pixman/pixman-intermediate-private.h39
-rw-r--r--pixman/pixman-intermediate.c167
-rw-r--r--pixman/pixman-private.h29
-rw-r--r--pixman/pixman.c11
-rw-r--r--pixman/pixman.h1
10 files changed, 340 insertions, 15 deletions
diff --git a/pixman/Makefile.am b/pixman/Makefile.am
index 0b3e40d..dc026d3 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 253a2a6..a27296d 100644
--- a/pixman/pixman-access.c
+++ b/pixman/pixman-access.c
@@ -1160,6 +1160,31 @@ 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,
+ uint32_t mask_bits)
+{
+ 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,
@@ -1948,6 +1973,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)
@@ -2955,6 +2991,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, \
@@ -3212,6 +3258,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 5d5738a..e804efc 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -963,13 +963,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;
}
@@ -1016,6 +1032,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 f89c7cf..7a8a93c 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 cc00b0e..a1072fd 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 0000000..2968efc
--- /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 0000000..8b65599
--- /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, 0);
+ 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 06a3912..8d0bb57 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -203,7 +203,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;
@@ -309,20 +310,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 543beaf..32e2173 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),
&region, 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 03ea966..f164c8b 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -714,6 +714,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),