diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2010-10-05 05:54:42 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2010-10-05 06:17:53 -0400 |
commit | 14b85e8bf9c2ac770d17f0e6bf1d3af6a0c76819 (patch) | |
tree | 28b0a5d445574a239fdd2061369da8a820da1c0a | |
parent | 284fd281fbf5df00f2628547fe830ac44c283863 (diff) |
Beginning of gradient accuracy testgradient-test
This test uses 128 bit floating point math to evaluate gradients.
Just use newton iteration for the square root (we don't care about
numbers outside the range of double precision).
FIXME: need to add configure time check for __float128.
-rw-r--r-- | test/Makefile.am | 4 | ||||
-rw-r--r-- | test/gradient-accuracy-test.c | 692 |
2 files changed, 696 insertions, 0 deletions
diff --git a/test/Makefile.am b/test/Makefile.am index 119ba15a..e8060336 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -12,6 +12,7 @@ TESTPROGRAMS = \ oob-test \ window-test \ gradient-crash-test \ + gradient-accuracy-test \ trap-crasher \ alpha-loop \ scaling-crash-test \ @@ -49,6 +50,9 @@ alphamap_SOURCES = alphamap.c utils.c utils.h alpha_loop_LDADD = $(TEST_LDADD) alpha_loop_SOURCES = alpha-loop.c utils.c utils.h +gradient_accuracy_test_LDADD = $(TEST_LDADD) +gradient_accuracy_test_SOURCES = gradient-accuracy-test.c utils.c utils.h + # GTK using test programs if HAVE_GTK diff --git a/test/gradient-accuracy-test.c b/test/gradient-accuracy-test.c new file mode 100644 index 00000000..d3570e76 --- /dev/null +++ b/test/gradient-accuracy-test.c @@ -0,0 +1,692 @@ +/* + * 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 (including the next + * paragraph) 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. + */ + +/* + * Test program that evaluates gradients at extremely high precision + * and compares the output to that of pixman gradients. + */ +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <config.h> +#include "utils.h" +#include <math.h> + +typedef __float128 quad; + +typedef struct radial_t radial_t; +typedef struct linear_t linear_t; + +typedef struct point_t point_t; +typedef struct qcircle_t qcircle_t; +typedef struct stop_t stop_t; +typedef struct common_t common_t; +typedef struct color_t color_t; + +struct qcircle_t +{ + quad x; + quad y; + quad r; +}; + +struct color_t +{ + quad a; + quad r; + quad g; + quad b; +}; + +struct stop_t +{ + quad position; + color_t color; +}; + +struct common_t +{ + int n_stops; + stop_t stops[128]; + + pixman_repeat_t repeat; +}; + +struct point_t +{ + quad x; + quad y; +}; + +struct linear_gradient_t +{ + common_t common; + + point_t p1; + point_t p2; +}; + +struct radial_t +{ + common_t common; + + qcircle_t c1; + qcircle_t c2; +}; + +static pixman_repeat_t +random_repeat (void) +{ + return lcg_rand_n (4); +} + +static void +channel_init_random (quad *channel) +{ + switch (lcg_rand_n (3)) + { + case 0: + *channel = 0.0q; + break; + + case 1: + *channel = 1.0q; + break; + + case 2: + *channel = (quad)drand48(); + break; + } +} + +static void +color_init_random (color_t *color) +{ + channel_init_random (&color->a); + channel_init_random (&color->r); + channel_init_random (&color->g); + channel_init_random (&color->b); +} + +static void +common_init_random (common_t *common) +{ + int i; + + common->n_stops = lcg_rand_n (128); + + for (i = 0; i < common->n_stops; ++i) + { + stop_t *stop = &(common->stops[i]); + + color_init_random (&stop->color); + } + + common->repeat = random_repeat(); +} + +static void +radial_init_random (radial_t *radial) +{ + common_init_random (&(radial->common)); +} + +static color_t +walk_gradient (common_t *common, quad t) +{ + color_t result; + + /* FIXME */ + + result.a = 0; + result.r = 0; + result.g = 0; + result.b = 0; + + return result; +} + +static color_t +black (void) +{ + color_t b; + + b.a = 0.0q; + b.r = 0.0q; + b.g = 0.0q; + b.b = 0.0q; + + return b; +} + +static quad +sqrtq (quad x) +{ + quad y; + int i; + + y = sqrt (x); + + /* Eight Newton iterations */ + for (i = 0; i < 8; ++i) + y -= 0.5q * (y - x / y); + + return y; +} + +static color_t +evaluate_radial (radial_t *radial, quad x, quad y) +{ + quad r1 = radial->c1.r; + quad r2 = radial->c2.r; + quad cdx = radial->c1.x - radial->c2.x; + quad cdy = radial->c1.y - radial->c2.y; + quad dr = r1 - r2; + quad pdx = x - radial->c1.x; + quad pdy = y - radial->c1.y; + + quad A = cdx * cdx + cdy * cdy - dr * dr; + quad B = pdx * cdx + pdy * cdy + r1 * dr; + quad C = pdx * pdx + pdy * pdy - r1 * r1; + + quad dis = B * B - A * C; + quad t; + + if (A == 0.0q || dis < 0) + { + return black(); + } + else + { + quad s = sqrtq (dis); + quad t1, t2; + + t1 = (B + s) / A; + t2 = (B - s) / A; + + if (t1 > t2) + t = t1; + else + t = t2; + } + + return walk_gradient (&radial->common, t); +}; + +static pixman_indexed_t rgb_palette[9]; +static pixman_indexed_t y_palette[9]; + +/* Create random image for testing purposes */ +static pixman_image_t * +create_random_image (pixman_format_code_t *allowed_formats, + int max_width, + int max_height, + int max_extra_stride, + pixman_format_code_t *used_fmt) +{ + int n = 0, i, width, height, stride; + pixman_format_code_t fmt; + uint32_t *buf; + pixman_image_t *img; + + while (allowed_formats[n] != -1) + n++; + fmt = allowed_formats[lcg_rand_n (n)]; + + width = lcg_rand_n (max_width) + 1; + height = lcg_rand_n (max_height) + 1; + stride = (width * PIXMAN_FORMAT_BPP (fmt) + 7) / 8 + + lcg_rand_n (max_extra_stride + 1); + stride = (stride + 3) & ~3; + + /* do the allocation */ + buf = aligned_malloc (64, stride * height); + + /* initialize image with random data */ + for (i = 0; i < stride * height; i++) + { + /* generation is biased to having more 0 or 255 bytes as + * they are more likely to be special-cased in code + */ + *((uint8_t *)buf + i) = lcg_rand_n (4) ? lcg_rand_n (256) : + (lcg_rand_n (2) ? 0 : 255); + } + + img = pixman_image_create_bits (fmt, width, height, buf, stride); + + if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_COLOR) + { + pixman_image_set_indexed (img, &(rgb_palette[PIXMAN_FORMAT_BPP (fmt)])); + } + else if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_GRAY) + { + pixman_image_set_indexed (img, &(y_palette[PIXMAN_FORMAT_BPP (fmt)])); + } + + image_endian_swap (img, PIXMAN_FORMAT_BPP (fmt)); + + if (used_fmt) *used_fmt = fmt; + return img; +} + +/* Free random image, and optionally update crc32 based on its data */ +static uint32_t +free_random_image (uint32_t initcrc, + pixman_image_t *img, + pixman_format_code_t fmt) +{ + uint32_t crc32 = 0; + int stride = pixman_image_get_stride (img); + uint32_t *data = pixman_image_get_data (img); + int height = pixman_image_get_height (img); + + if (fmt != -1) + { + /* mask unused 'x' part */ + if (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt) && + PIXMAN_FORMAT_DEPTH (fmt) != 0) + { + int i; + uint32_t *data = pixman_image_get_data (img); + uint32_t mask = (1 << PIXMAN_FORMAT_DEPTH (fmt)) - 1; + + if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA) + mask <<= (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt)); + + for (i = 0; i < 32; i++) + mask |= mask << (i * PIXMAN_FORMAT_BPP (fmt)); + + for (i = 0; i < stride * height / 4; i++) + data[i] &= mask; + } + + /* swap endiannes in order to provide identical results on both big + * and litte endian systems + */ + image_endian_swap (img, PIXMAN_FORMAT_BPP (fmt)); + crc32 = compute_crc32 (initcrc, data, stride * height); + } + + pixman_image_unref (img); + free (data); + + return crc32; +} + +static pixman_op_t op_list[] = { + PIXMAN_OP_SRC, + PIXMAN_OP_OVER, + PIXMAN_OP_ADD, + PIXMAN_OP_CLEAR, + PIXMAN_OP_SRC, + PIXMAN_OP_DST, + PIXMAN_OP_OVER, + PIXMAN_OP_OVER_REVERSE, + PIXMAN_OP_IN, + PIXMAN_OP_IN_REVERSE, + PIXMAN_OP_OUT, + PIXMAN_OP_OUT_REVERSE, + PIXMAN_OP_ATOP, + PIXMAN_OP_ATOP_REVERSE, + PIXMAN_OP_XOR, + PIXMAN_OP_ADD, + PIXMAN_OP_SATURATE, + PIXMAN_OP_DISJOINT_CLEAR, + PIXMAN_OP_DISJOINT_SRC, + PIXMAN_OP_DISJOINT_DST, + PIXMAN_OP_DISJOINT_OVER, + PIXMAN_OP_DISJOINT_OVER_REVERSE, + PIXMAN_OP_DISJOINT_IN, + PIXMAN_OP_DISJOINT_IN_REVERSE, + PIXMAN_OP_DISJOINT_OUT, + PIXMAN_OP_DISJOINT_OUT_REVERSE, + PIXMAN_OP_DISJOINT_ATOP, + PIXMAN_OP_DISJOINT_ATOP_REVERSE, + PIXMAN_OP_DISJOINT_XOR, + PIXMAN_OP_CONJOINT_CLEAR, + PIXMAN_OP_CONJOINT_SRC, + PIXMAN_OP_CONJOINT_DST, + PIXMAN_OP_CONJOINT_OVER, + PIXMAN_OP_CONJOINT_OVER_REVERSE, + PIXMAN_OP_CONJOINT_IN, + PIXMAN_OP_CONJOINT_IN_REVERSE, + PIXMAN_OP_CONJOINT_OUT, + PIXMAN_OP_CONJOINT_OUT_REVERSE, + PIXMAN_OP_CONJOINT_ATOP, + PIXMAN_OP_CONJOINT_ATOP_REVERSE, + PIXMAN_OP_CONJOINT_XOR, + PIXMAN_OP_MULTIPLY, + PIXMAN_OP_SCREEN, + PIXMAN_OP_OVERLAY, + PIXMAN_OP_DARKEN, + PIXMAN_OP_LIGHTEN, + PIXMAN_OP_COLOR_DODGE, + PIXMAN_OP_COLOR_BURN, + PIXMAN_OP_HARD_LIGHT, + PIXMAN_OP_DIFFERENCE, + PIXMAN_OP_EXCLUSION, +#if 0 /* these use floating point math and are not always bitexact on different platforms */ + PIXMAN_OP_SOFT_LIGHT, + PIXMAN_OP_HSL_HUE, + PIXMAN_OP_HSL_SATURATION, + PIXMAN_OP_HSL_COLOR, + PIXMAN_OP_HSL_LUMINOSITY, +#endif +}; + +static pixman_format_code_t img_fmt_list[] = { + PIXMAN_a8r8g8b8, + PIXMAN_x8r8g8b8, + PIXMAN_r5g6b5, + PIXMAN_r3g3b2, + PIXMAN_a8, + PIXMAN_a8b8g8r8, + PIXMAN_x8b8g8r8, + PIXMAN_b8g8r8a8, + PIXMAN_b8g8r8x8, + PIXMAN_x14r6g6b6, + PIXMAN_r8g8b8, + PIXMAN_b8g8r8, + PIXMAN_r5g6b5, + PIXMAN_b5g6r5, + PIXMAN_x2r10g10b10, + PIXMAN_a2r10g10b10, + PIXMAN_x2b10g10r10, + PIXMAN_a2b10g10r10, + PIXMAN_a1r5g5b5, + PIXMAN_x1r5g5b5, + PIXMAN_a1b5g5r5, + PIXMAN_x1b5g5r5, + PIXMAN_a4r4g4b4, + PIXMAN_x4r4g4b4, + PIXMAN_a4b4g4r4, + PIXMAN_x4b4g4r4, + PIXMAN_a8, + PIXMAN_r3g3b2, + PIXMAN_b2g3r3, + PIXMAN_a2r2g2b2, + PIXMAN_a2b2g2r2, + PIXMAN_c8, + PIXMAN_g8, + PIXMAN_x4c4, + PIXMAN_x4g4, + PIXMAN_c4, + PIXMAN_g4, + PIXMAN_g1, + PIXMAN_x4a4, + PIXMAN_a4, + PIXMAN_r1g2b1, + PIXMAN_b1g2r1, + PIXMAN_a1r1g1b1, + PIXMAN_a1b1g1r1, + PIXMAN_a1, + -1 +}; + +static pixman_format_code_t mask_fmt_list[] = { + PIXMAN_a8r8g8b8, + PIXMAN_a8, + PIXMAN_a4, + PIXMAN_a1, + -1 +}; + + +/* + * Composite operation with pseudorandom images + */ +uint32_t +test_composite (int testnum, int verbose) +{ + int i; + pixman_image_t *src_img = NULL; + pixman_image_t *dst_img = NULL; + pixman_image_t *mask_img = NULL; + int src_width, src_height; + int dst_width, dst_height; + int src_stride, dst_stride; + int src_x, src_y; + int dst_x, dst_y; + int mask_x, mask_y; + int w, h; + int op; + pixman_format_code_t src_fmt, dst_fmt, mask_fmt; + uint32_t *dstbuf, *srcbuf, *maskbuf; + uint32_t crc32; + int max_width, max_height, max_extra_stride; + FLOAT_REGS_CORRUPTION_DETECTOR_START (); + + max_width = max_height = 24 + testnum / 10000; + max_extra_stride = 4 + testnum / 1000000; + + if (max_width > 256) + max_width = 256; + + if (max_height > 16) + max_height = 16; + + if (max_extra_stride > 8) + max_extra_stride = 8; + + lcg_srand (testnum); + + op = op_list[lcg_rand_n (sizeof (op_list) / sizeof (op_list[0]))]; + + if (lcg_rand_n (8)) + { + /* normal image */ + src_img = create_random_image (img_fmt_list, max_width, max_height, + max_extra_stride, &src_fmt); + } + else + { + /* solid case */ + src_img = create_random_image (img_fmt_list, 1, 1, + max_extra_stride, &src_fmt); + + pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NORMAL); + } + + dst_img = create_random_image (img_fmt_list, max_width, max_height, + max_extra_stride, &dst_fmt); + + src_width = pixman_image_get_width (src_img); + src_height = pixman_image_get_height (src_img); + src_stride = pixman_image_get_stride (src_img); + + dst_width = pixman_image_get_width (dst_img); + dst_height = pixman_image_get_height (dst_img); + dst_stride = pixman_image_get_stride (dst_img); + + dstbuf = pixman_image_get_data (dst_img); + srcbuf = pixman_image_get_data (src_img); + + src_x = lcg_rand_n (src_width); + src_y = lcg_rand_n (src_height); + dst_x = lcg_rand_n (dst_width); + dst_y = lcg_rand_n (dst_height); + + mask_img = NULL; + mask_fmt = -1; + mask_x = 0; + mask_y = 0; + maskbuf = NULL; + + if ((src_fmt == PIXMAN_x8r8g8b8 || src_fmt == PIXMAN_x8b8g8r8) && + (lcg_rand_n (4) == 0)) + { + /* PIXBUF */ + mask_fmt = lcg_rand_n (2) ? PIXMAN_a8r8g8b8 : PIXMAN_a8b8g8r8; + mask_img = pixman_image_create_bits (mask_fmt, + src_width, + src_height, + srcbuf, + src_stride); + mask_x = src_x; + mask_y = src_y; + maskbuf = srcbuf; + } + else if (lcg_rand_n (2)) + { + if (lcg_rand_n (2)) + { + mask_img = create_random_image (mask_fmt_list, max_width, max_height, + max_extra_stride, &mask_fmt); + } + else + { + /* solid case */ + mask_img = create_random_image (mask_fmt_list, 1, 1, + max_extra_stride, &mask_fmt); + pixman_image_set_repeat (mask_img, PIXMAN_REPEAT_NORMAL); + } + + if (lcg_rand_n (2)) + pixman_image_set_component_alpha (mask_img, 1); + + mask_x = lcg_rand_n (pixman_image_get_width (mask_img)); + mask_y = lcg_rand_n (pixman_image_get_height (mask_img)); + } + + + w = lcg_rand_n (dst_width - dst_x + 1); + h = lcg_rand_n (dst_height - dst_y + 1); + + if (verbose) + { + printf ("op=%d, src_fmt=%08X, dst_fmt=%08X, mask_fmt=%08X\n", + op, src_fmt, dst_fmt, mask_fmt); + printf ("src_width=%d, src_height=%d, dst_width=%d, dst_height=%d\n", + src_width, src_height, dst_width, dst_height); + printf ("src_x=%d, src_y=%d, dst_x=%d, dst_y=%d\n", + src_x, src_y, dst_x, dst_y); + printf ("src_stride=%d, dst_stride=%d\n", + src_stride, dst_stride); + printf ("w=%d, h=%d\n", w, h); + } + + pixman_image_composite (op, src_img, mask_img, dst_img, + src_x, src_y, mask_x, mask_y, dst_x, dst_y, w, h); + + if (verbose) + { + int j; + + printf ("---\n"); + for (i = 0; i < dst_height; i++) + { + for (j = 0; j < dst_stride; j++) + { + if (j == (dst_width * PIXMAN_FORMAT_BPP (dst_fmt) + 7) / 8) + printf ("| "); + + printf ("%02X ", *((uint8_t *)dstbuf + i * dst_stride + j)); + } + printf ("\n"); + } + printf ("---\n"); + } + + free_random_image (0, src_img, -1); + crc32 = free_random_image (0, dst_img, dst_fmt); + + if (mask_img) + { + if (srcbuf == maskbuf) + pixman_image_unref(mask_img); + else + free_random_image (0, mask_img, -1); + } + + FLOAT_REGS_CORRUPTION_DETECTOR_FINISH (); + return crc32; +} + +#define CONVERT_15(c, is_rgb) \ + (is_rgb? \ + ((((c) >> 3) & 0x001f) | \ + (((c) >> 6) & 0x03e0) | \ + (((c) >> 9) & 0x7c00)) : \ + (((((c) >> 16) & 0xff) * 153 + \ + (((c) >> 8) & 0xff) * 301 + \ + (((c) ) & 0xff) * 58) >> 2)) + +static void +initialize_palette (pixman_indexed_t *palette, uint32_t mask, int is_rgb) +{ + int i; + + for (i = 0; i < 32768; ++i) + palette->ent[i] = lcg_rand() & mask; + + for (i = 0; i < mask + 1; ++i) + { + uint32_t rgba24; + pixman_bool_t retry; + uint32_t i15; + + /* We filled the rgb->index map with random numbers, but we + * do need the ability to round trip, that is if some indexed + * color expands to an argb24, then the 15 bit version of that + * color must map back to the index. Anything else, we don't + * care about too much. + */ + do + { + uint32_t old_idx; + + rgba24 = lcg_rand(); + i15 = CONVERT_15 (rgba24, is_rgb); + + old_idx = palette->ent[i15]; + if (CONVERT_15 (palette->rgba[old_idx], is_rgb) == i15) + retry = 1; + else + retry = 0; + } while (retry); + + palette->rgba[i] = rgba24; + palette->ent[i15] = i; + } + + for (i = 0; i < mask + 1; ++i) + { + assert (palette->ent[CONVERT_15 (palette->rgba[i], is_rgb)] == i); + } +} + +int +main (int argc, const char *argv[]) +{ + int i; + + for (i = 1; i <= 8; i++) + { + initialize_palette (&(rgb_palette[i]), (1 << i) - 1, TRUE); + initialize_palette (&(y_palette[i]), (1 << i) - 1, FALSE); + } + + return fuzzer_test_main("blitters", 2000000, + 0x217CF14A, + test_composite, argc, argv); +} |