aboutsummaryrefslogtreecommitdiff
path: root/pixman
diff options
context:
space:
mode:
Diffstat (limited to 'pixman')
-rw-r--r--pixman/RELEASING2
-rw-r--r--pixman/pixman/pixman-fast-path.c241
-rw-r--r--pixman/pixman/pixman-general.c7
-rw-r--r--pixman/pixman/pixman-image.c3
-rw-r--r--pixman/pixman/pixman-implementation.c1
-rw-r--r--pixman/pixman/pixman-private.h2
-rw-r--r--pixman/test/Makefile.sources1
-rw-r--r--pixman/test/alpha-loop.c7
-rw-r--r--pixman/test/matrix-test.c53
-rw-r--r--pixman/test/scaling-bench.c69
10 files changed, 381 insertions, 5 deletions
diff --git a/pixman/RELEASING b/pixman/RELEASING
index fbe15813d..657857de2 100644
--- a/pixman/RELEASING
+++ b/pixman/RELEASING
@@ -55,3 +55,5 @@ Here are the steps to follow to create a new pixman release:
You must use "--tags" here; otherwise the new tag will not
be pushed out.
+8) Change the topic of the #cairo IRC channel on freenode to advertise
+ the new version.
diff --git a/pixman/pixman/pixman-fast-path.c b/pixman/pixman/pixman-fast-path.c
index 3982dce8b..2608268d9 100644
--- a/pixman/pixman/pixman-fast-path.c
+++ b/pixman/pixman/pixman-fast-path.c
@@ -2261,6 +2261,237 @@ fast_write_back_r5g6b5 (pixman_iter_t *iter)
}
}
+typedef struct
+{
+ int y;
+ uint64_t * buffer;
+} line_t;
+
+typedef struct
+{
+ line_t line0;
+ line_t line1;
+ pixman_fixed_t y;
+ pixman_fixed_t x;
+ uint64_t data[1];
+} bilinear_info_t;
+
+static void
+fetch_horizontal (bits_image_t *image, line_t *line,
+ int y, pixman_fixed_t x, pixman_fixed_t ux, int n)
+{
+ uint32_t *bits = image->bits + y * image->rowstride;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ {
+ int x0 = pixman_fixed_to_int (x);
+ int x1 = x0 + 1;
+ int32_t dist_x;
+
+ uint32_t left = *(bits + x0);
+ uint32_t right = *(bits + x1);
+
+ dist_x = pixman_fixed_to_bilinear_weight (x);
+ dist_x <<= (8 - BILINEAR_INTERPOLATION_BITS);
+
+#if SIZEOF_LONG <= 4
+ {
+ uint32_t lag, rag, ag;
+ uint32_t lrb, rrb, rb;
+
+ lag = (left & 0xff00ff00) >> 8;
+ rag = (right & 0xff00ff00) >> 8;
+ ag = (lag << 8) + dist_x * (rag - lag);
+
+ lrb = (left & 0x00ff00ff);
+ rrb = (right & 0x00ff00ff);
+ rb = (lrb << 8) + dist_x * (rrb - lrb);
+
+ *((uint32_t *)(line->buffer + i)) = ag;
+ *((uint32_t *)(line->buffer + i) + 1) = rb;
+ }
+#else
+ {
+ uint64_t lagrb, ragrb;
+ uint32_t lag, rag;
+ uint32_t lrb, rrb;
+
+ lag = (left & 0xff00ff00);
+ lrb = (left & 0x00ff00ff);
+ rag = (right & 0xff00ff00);
+ rrb = (right & 0x00ff00ff);
+ lagrb = (((uint64_t)lag) << 24) | lrb;
+ ragrb = (((uint64_t)rag) << 24) | rrb;
+
+ line->buffer[i] = (lagrb << 8) + dist_x * (ragrb - lagrb);
+ }
+#endif
+
+ x += ux;
+ }
+
+ line->y = y;
+}
+
+static uint32_t *
+fast_fetch_bilinear_cover (pixman_iter_t *iter, const uint32_t *mask)
+{
+ pixman_fixed_t fx, ux;
+ bilinear_info_t *info = iter->data;
+ line_t *line0, *line1;
+ int y0, y1;
+ int32_t dist_y;
+ int i;
+
+ fx = info->x;
+ ux = iter->image->common.transform->matrix[0][0];
+
+ y0 = pixman_fixed_to_int (info->y);
+ y1 = y0 + 1;
+ dist_y = pixman_fixed_to_bilinear_weight (info->y);
+ dist_y <<= (8 - BILINEAR_INTERPOLATION_BITS);
+
+ line0 = &info->line0;
+ line1 = &info->line1;
+
+ if (line0->y != y0 || line1->y != y1)
+ {
+ if (line0->y == y1 || line1->y == y0)
+ {
+ line_t tmp = *line0;
+ *line0 = *line1;
+ *line1 = tmp;
+ }
+
+ if (line0->y != y0)
+ {
+ fetch_horizontal (
+ &iter->image->bits, line0, y0, fx, ux, iter->width);
+ }
+
+ if (line1->y != y1)
+ {
+ fetch_horizontal (
+ &iter->image->bits, line1, y1, fx, ux, iter->width);
+ }
+ }
+
+ for (i = 0; i < iter->width; ++i)
+ {
+#if SIZEOF_LONG <= 4
+ uint32_t ta, tr, tg, tb;
+ uint32_t ba, br, bg, bb;
+ uint32_t tag, trb;
+ uint32_t bag, brb;
+ uint32_t a, r, g, b;
+
+ tag = *((uint32_t *)(line0->buffer + i));
+ trb = *((uint32_t *)(line0->buffer + i) + 1);
+ bag = *((uint32_t *)(line1->buffer + i));
+ brb = *((uint32_t *)(line1->buffer + i) + 1);
+
+ ta = tag >> 16;
+ ba = bag >> 16;
+ a = (ta << 8) + dist_y * (ba - ta);
+
+ tr = trb >> 16;
+ br = brb >> 16;
+ r = (tr << 8) + dist_y * (br - tr);
+
+ tg = tag & 0xffff;
+ bg = bag & 0xffff;
+ g = (tg << 8) + dist_y * (bg - tg);
+
+ tb = trb & 0xffff;
+ bb = brb & 0xffff;
+ b = (tb << 8) + dist_y * (bb - tb);
+
+ a = (a << 8) & 0xff000000;
+ r = (r << 0) & 0x00ff0000;
+ g = (g >> 8) & 0x0000ff00;
+ b = (b >> 16) & 0x000000ff;
+#else
+ uint64_t top = line0->buffer[i];
+ uint64_t bot = line1->buffer[i];
+ uint64_t tar = (top & 0xffff0000ffff0000ULL) >> 16;
+ uint64_t bar = (bot & 0xffff0000ffff0000ULL) >> 16;
+ uint64_t tgb = (top & 0x0000ffff0000ffffULL);
+ uint64_t bgb = (bot & 0x0000ffff0000ffffULL);
+ uint64_t ar, gb;
+ uint32_t a, r, g, b;
+
+ ar = (tar << 8) + dist_y * (bar - tar);
+ gb = (tgb << 8) + dist_y * (bgb - tgb);
+
+ a = ((ar >> 24) & 0xff000000);
+ r = ((ar >> 0) & 0x00ff0000);
+ g = ((gb >> 40) & 0x0000ff00);
+ b = ((gb >> 16) & 0x000000ff);
+#endif
+
+ iter->buffer[i] = a | r | g | b;
+ }
+
+ info->y += iter->image->common.transform->matrix[1][1];
+
+ return iter->buffer;
+}
+
+static void
+bilinear_cover_iter_fini (pixman_iter_t *iter)
+{
+ free (iter->data);
+}
+
+static void
+fast_bilinear_cover_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *iter_info)
+{
+ int width = iter->width;
+ bilinear_info_t *info;
+ pixman_vector_t v;
+
+ /* Reference point is the center of the pixel */
+ v.vector[0] = pixman_int_to_fixed (iter->x) + pixman_fixed_1 / 2;
+ v.vector[1] = pixman_int_to_fixed (iter->y) + pixman_fixed_1 / 2;
+ v.vector[2] = pixman_fixed_1;
+
+ if (!pixman_transform_point_3d (iter->image->common.transform, &v))
+ goto fail;
+
+ info = malloc (sizeof (*info) + (2 * width - 1) * sizeof (uint64_t));
+ if (!info)
+ goto fail;
+
+ info->x = v.vector[0] - pixman_fixed_1 / 2;
+ info->y = v.vector[1] - pixman_fixed_1 / 2;
+
+ /* It is safe to set the y coordinates to -1 initially
+ * because COVER_CLIP_BILINEAR ensures that we will only
+ * be asked to fetch lines in the [0, height) interval
+ */
+ info->line0.y = -1;
+ info->line0.buffer = &(info->data[0]);
+ info->line1.y = -1;
+ info->line1.buffer = &(info->data[width]);
+
+ iter->get_scanline = fast_fetch_bilinear_cover;
+ iter->fini = bilinear_cover_iter_fini;
+
+ iter->data = info;
+ return;
+
+fail:
+ /* Something went wrong, either a bad matrix or OOM; in such cases,
+ * we don't guarantee any particular rendering.
+ */
+ _pixman_log_error (
+ FUNC, "Allocation failure or bad matrix, skipping rendering\n");
+
+ iter->get_scanline = _pixman_iter_get_scanline_noop;
+ iter->fini = bilinear_cover_iter_fini;
+}
+
#define IMAGE_FLAGS \
(FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \
FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST)
@@ -2280,6 +2511,16 @@ static const pixman_iter_info_t fast_iters[] =
_pixman_iter_init_bits_stride,
fast_dest_fetch_noop, fast_write_back_r5g6b5 },
+ { PIXMAN_a8r8g8b8,
+ (FAST_PATH_STANDARD_FLAGS |
+ FAST_PATH_SCALE_TRANSFORM |
+ FAST_PATH_BILINEAR_FILTER |
+ FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR),
+ ITER_NARROW | ITER_SRC,
+ fast_bilinear_cover_iter_init,
+ NULL, NULL
+ },
+
{ PIXMAN_null },
};
diff --git a/pixman/pixman/pixman-general.c b/pixman/pixman/pixman-general.c
index 4da5da5e2..6310bff9d 100644
--- a/pixman/pixman/pixman-general.c
+++ b/pixman/pixman/pixman-general.c
@@ -208,6 +208,13 @@ general_composite_rect (pixman_implementation_t *imp,
dest_iter.write_back (&dest_iter);
}
+ if (src_iter.fini)
+ src_iter.fini (&src_iter);
+ if (mask_iter.fini)
+ mask_iter.fini (&mask_iter);
+ if (dest_iter.fini)
+ dest_iter.fini (&dest_iter);
+
if (scanline_buffer != (uint8_t *) stack_scanline_buffer)
free (scanline_buffer);
}
diff --git a/pixman/pixman/pixman-image.c b/pixman/pixman/pixman-image.c
index 4f9c2f966..1ff1a4974 100644
--- a/pixman/pixman/pixman-image.c
+++ b/pixman/pixman/pixman-image.c
@@ -926,6 +926,9 @@ _pixman_image_get_solid (pixman_implementation_t *imp,
ITER_NARROW | ITER_SRC, image->common.flags);
result = *iter.get_scanline (&iter, NULL);
+
+ if (iter.fini)
+ iter.fini (&iter);
}
/* If necessary, convert RGB <--> BGR. */
diff --git a/pixman/pixman/pixman-implementation.c b/pixman/pixman/pixman-implementation.c
index 160847ad0..588405451 100644
--- a/pixman/pixman/pixman-implementation.c
+++ b/pixman/pixman/pixman-implementation.c
@@ -313,6 +313,7 @@ _pixman_implementation_iter_init (pixman_implementation_t *imp,
iter->height = height;
iter->iter_flags = iter_flags;
iter->image_flags = image_flags;
+ iter->fini = NULL;
if (!iter->image)
{
diff --git a/pixman/pixman/pixman-private.h b/pixman/pixman/pixman-private.h
index af4a0b6e0..964660508 100644
--- a/pixman/pixman/pixman-private.h
+++ b/pixman/pixman/pixman-private.h
@@ -209,6 +209,7 @@ union pixman_image
typedef struct pixman_iter_t pixman_iter_t;
typedef uint32_t *(* pixman_iter_get_scanline_t) (pixman_iter_t *iter, const uint32_t *mask);
typedef void (* pixman_iter_write_back_t) (pixman_iter_t *iter);
+typedef void (* pixman_iter_fini_t) (pixman_iter_t *iter);
typedef enum
{
@@ -255,6 +256,7 @@ struct pixman_iter_t
/* These function pointers are initialized by the implementation */
pixman_iter_get_scanline_t get_scanline;
pixman_iter_write_back_t write_back;
+ pixman_iter_fini_t fini;
/* These fields are scratch data that implementations can use */
void * data;
diff --git a/pixman/test/Makefile.sources b/pixman/test/Makefile.sources
index b5fc740f3..2fabdb574 100644
--- a/pixman/test/Makefile.sources
+++ b/pixman/test/Makefile.sources
@@ -33,6 +33,7 @@ OTHERPROGRAMS = \
lowlevel-blt-bench \
radial-perf-test \
check-formats \
+ scaling-bench \
$(NULL)
# Utility functions
diff --git a/pixman/test/alpha-loop.c b/pixman/test/alpha-loop.c
index eca761537..4d4384d00 100644
--- a/pixman/test/alpha-loop.c
+++ b/pixman/test/alpha-loop.c
@@ -8,6 +8,7 @@
int
main (int argc, char **argv)
{
+ pixman_image_t *a, *d, *s;
uint8_t *alpha;
uint32_t *src, *dest;
@@ -17,9 +18,9 @@ main (int argc, char **argv)
src = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * 4);
dest = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * 4);
- pixman_image_t *a = pixman_image_create_bits (PIXMAN_a8, WIDTH, HEIGHT, (uint32_t *)alpha, WIDTH);
- pixman_image_t *d = pixman_image_create_bits (PIXMAN_a8r8g8b8, WIDTH, HEIGHT, dest, WIDTH * 4);
- pixman_image_t *s = pixman_image_create_bits (PIXMAN_a2r10g10b10, WIDTH, HEIGHT, src, WIDTH * 4);
+ a = pixman_image_create_bits (PIXMAN_a8, WIDTH, HEIGHT, (uint32_t *)alpha, WIDTH);
+ d = pixman_image_create_bits (PIXMAN_a8r8g8b8, WIDTH, HEIGHT, dest, WIDTH * 4);
+ s = pixman_image_create_bits (PIXMAN_a2r10g10b10, WIDTH, HEIGHT, src, WIDTH * 4);
fail_after (5, "Infinite loop detected: 5 seconds without progress\n");
diff --git a/pixman/test/matrix-test.c b/pixman/test/matrix-test.c
index 8437dd291..0a5f203f5 100644
--- a/pixman/test/matrix-test.c
+++ b/pixman/test/matrix-test.c
@@ -70,6 +70,53 @@ pixman_bool_t does_it_fit_fixed_48_16 (__float128 x)
#endif
+static inline uint32_t
+byteswap32 (uint32_t x)
+{
+ return ((x & ((uint32_t)0xFF << 24)) >> 24) |
+ ((x & ((uint32_t)0xFF << 16)) >> 8) |
+ ((x & ((uint32_t)0xFF << 8)) << 8) |
+ ((x & ((uint32_t)0xFF << 0)) << 24);
+}
+
+static inline uint64_t
+byteswap64 (uint64_t x)
+{
+ return ((x & ((uint64_t)0xFF << 56)) >> 56) |
+ ((x & ((uint64_t)0xFF << 48)) >> 40) |
+ ((x & ((uint64_t)0xFF << 40)) >> 24) |
+ ((x & ((uint64_t)0xFF << 32)) >> 8) |
+ ((x & ((uint64_t)0xFF << 24)) << 8) |
+ ((x & ((uint64_t)0xFF << 16)) << 24) |
+ ((x & ((uint64_t)0xFF << 8)) << 40) |
+ ((x & ((uint64_t)0xFF << 0)) << 56);
+}
+
+static void
+byteswap_transform (pixman_transform_t *t)
+{
+ int i, j;
+
+ if (is_little_endian ())
+ return;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ t->matrix[i][j] = byteswap32 (t->matrix[i][j]);
+}
+
+static void
+byteswap_vector_48_16 (pixman_vector_48_16_t *v)
+{
+ int i;
+
+ if (is_little_endian ())
+ return;
+
+ for (i = 0; i < 3; i++)
+ v->v[i] = byteswap64 (v->v[i]);
+}
+
uint32_t
test_matrix (int testnum, int verbose)
{
@@ -90,6 +137,8 @@ test_matrix (int testnum, int verbose)
#endif
prng_randmemset (&ti, sizeof(ti), 0);
prng_randmemset (&vi, sizeof(vi), 0);
+ byteswap_transform (&ti);
+ byteswap_vector_48_16 (&vi);
for (j = 0; j < 3; j++)
{
@@ -132,8 +181,6 @@ test_matrix (int testnum, int verbose)
else
transform_ok = pixman_transform_point_31_16 (&ti, &vi, &result_i);
- crc32 = compute_crc32 (crc32, &result_i, sizeof(result_i));
-
#ifdef HAVE_FLOAT128
/* compare with a reference 128-bit floating point implementation */
for (j = 0; j < 3; j++)
@@ -173,6 +220,8 @@ test_matrix (int testnum, int verbose)
}
}
#endif
+ byteswap_vector_48_16 (&result_i);
+ crc32 = compute_crc32 (crc32, &result_i, sizeof (result_i));
}
return crc32;
}
diff --git a/pixman/test/scaling-bench.c b/pixman/test/scaling-bench.c
new file mode 100644
index 000000000..b39adeff5
--- /dev/null
+++ b/pixman/test/scaling-bench.c
@@ -0,0 +1,69 @@
+#include <stdlib.h>
+#include "utils.h"
+
+#define SOURCE_WIDTH 320
+#define SOURCE_HEIGHT 240
+
+static pixman_image_t *
+make_source (void)
+{
+ size_t n_bytes = (SOURCE_WIDTH + 2) * (SOURCE_HEIGHT + 2) * 4;
+ uint32_t *data = malloc (n_bytes);
+ pixman_image_t *source;
+
+ prng_randmemset (data, n_bytes, 0);
+
+ source = pixman_image_create_bits (
+ PIXMAN_a8r8g8b8, SOURCE_WIDTH + 2, SOURCE_HEIGHT + 2,
+ data,
+ (SOURCE_WIDTH + 2) * 4);
+
+ pixman_image_set_filter (source, PIXMAN_FILTER_BILINEAR, NULL, 0);
+
+ return source;
+}
+
+int
+main ()
+{
+ double scale;
+ pixman_image_t *src;
+
+ prng_srand (23874);
+
+ src = make_source ();
+ printf ("# %-6s %-22s %-14s %-12s\n",
+ "ratio",
+ "resolutions",
+ "time / ms",
+ "time per pixel / ns");
+ for (scale = 0.1; scale < 10.005; scale += 0.01)
+ {
+ int dest_width = SOURCE_WIDTH * scale + 0.5;
+ int dest_height = SOURCE_HEIGHT * scale + 0.5;
+ pixman_fixed_t s = (1 / scale) * 65536.0 + 0.5;
+ pixman_transform_t transform;
+ pixman_image_t *dest;
+ double t1, t2;
+
+ pixman_transform_init_scale (&transform, s, s);
+ pixman_image_set_transform (src, &transform);
+
+ dest = pixman_image_create_bits (
+ PIXMAN_a8r8g8b8, dest_width, dest_height, NULL, -1);
+
+ t1 = gettime();
+ pixman_image_composite (
+ PIXMAN_OP_OVER, src, NULL, dest,
+ scale, scale, 0, 0, 0, 0, dest_width, dest_height);
+ t2 = gettime();
+
+ printf ("%6.2f : %4dx%-4d => %4dx%-4d : %12.4f : %12.4f\n",
+ scale, SOURCE_WIDTH, SOURCE_HEIGHT, dest_width, dest_height,
+ (t2 - t1) * 1000, ((t2 - t1) / (dest_width * dest_height)) * 1000000000);
+
+ pixman_image_unref (dest);
+ }
+
+ return 0;
+}