diff options
Diffstat (limited to 'pixman')
-rw-r--r-- | pixman/RELEASING | 2 | ||||
-rw-r--r-- | pixman/pixman/pixman-fast-path.c | 241 | ||||
-rw-r--r-- | pixman/pixman/pixman-general.c | 7 | ||||
-rw-r--r-- | pixman/pixman/pixman-image.c | 3 | ||||
-rw-r--r-- | pixman/pixman/pixman-implementation.c | 1 | ||||
-rw-r--r-- | pixman/pixman/pixman-private.h | 2 | ||||
-rw-r--r-- | pixman/test/Makefile.sources | 1 | ||||
-rw-r--r-- | pixman/test/alpha-loop.c | 7 | ||||
-rw-r--r-- | pixman/test/matrix-test.c | 53 | ||||
-rw-r--r-- | pixman/test/scaling-bench.c | 69 |
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 7f1332abf..f82c915dc 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; +} |