diff options
Diffstat (limited to 'pixman')
36 files changed, 2618 insertions, 389 deletions
diff --git a/pixman/configure.ac b/pixman/configure.ac index 45b709dcf..81f068d9c 100644 --- a/pixman/configure.ac +++ b/pixman/configure.ac @@ -860,7 +860,7 @@ AC_CACHE_VAL(ac_cv_tls, [ #error OpenBSD has broken __thread support #endif -int $kw test;], [], ac_cv_tls=$kw) +int $kw test;], [], [ac_cv_tls=$kw; break]) done ]) AC_MSG_RESULT($ac_cv_tls) diff --git a/pixman/demos/Makefile.am b/pixman/demos/Makefile.am index f324f5f5b..3f2a3fad6 100644 --- a/pixman/demos/Makefile.am +++ b/pixman/demos/Makefile.am @@ -6,7 +6,8 @@ AM_LDFLAGS = $(OPENMP_CFLAGS) LDADD = $(top_builddir)/pixman/libpixman-1.la -lm $(GTK_LIBS) $(PNG_LIBS) INCLUDES = -I$(top_srcdir)/pixman -I$(top_builddir)/pixman $(GTK_CFLAGS) $(PNG_CFLAGS) -GTK_UTILS = gtk-utils.c gtk-utils.h ../test/utils.c ../test/utils.h +GTK_UTILS = gtk-utils.c gtk-utils.h ../test/utils.c ../test/utils.h \ + ../test/utils-prng.c ../test/utils-prng.h DEMOS = \ clip-test \ @@ -14,6 +15,7 @@ DEMOS = \ composite-test \ gradient-test \ radial-test \ + conical-test \ alpha-test \ screen-test \ convolution-test \ @@ -22,9 +24,10 @@ DEMOS = \ quad2quad \ checkerboard \ srgb-trap-test \ - srgb-test + srgb-test \ + scale -EXTRA_DIST = parrot.c parrot.jpg +EXTRA_DIST = parrot.c parrot.jpg scale.ui gradient_test_SOURCES = gradient-test.c $(GTK_UTILS) alpha_test_SOURCES = alpha-test.c $(GTK_UTILS) @@ -35,10 +38,12 @@ trap_test_SOURCES = trap-test.c $(GTK_UTILS) screen_test_SOURCES = screen-test.c $(GTK_UTILS) convolution_test_SOURCES = convolution-test.c $(GTK_UTILS) radial_test_SOURCES = radial-test.c $(GTK_UTILS) +conical_test_SOURCES = conical-test.c $(GTK_UTILS) tri_test_SOURCES = tri-test.c $(GTK_UTILS) checkerboard_SOURCES = checkerboard.c $(GTK_UTILS) srgb_test_SOURCES = srgb-test.c $(GTK_UTILS) srgb_trap_test_SOURCES = srgb-trap-test.c $(GTK_UTILS) +scale_SOURCES = scale.c $(GTK_UTILS) noinst_PROGRAMS = $(DEMOS) diff --git a/pixman/demos/conical-test.c b/pixman/demos/conical-test.c new file mode 100644 index 000000000..1e08e42f7 --- /dev/null +++ b/pixman/demos/conical-test.c @@ -0,0 +1,134 @@ +#include "../test/utils.h" +#include "gtk-utils.h" + +#define SIZE 128 +#define GRADIENTS_PER_ROW 7 +#define NUM_ROWS ((NUM_GRADIENTS + GRADIENTS_PER_ROW - 1) / GRADIENTS_PER_ROW) +#define WIDTH (SIZE * GRADIENTS_PER_ROW) +#define HEIGHT (SIZE * NUM_ROWS) +#define NUM_GRADIENTS 35 + +#define double_to_color(x) \ + (((uint32_t) ((x)*65536)) - (((uint32_t) ((x)*65536)) >> 16)) + +#define PIXMAN_STOP(offset,r,g,b,a) \ + { pixman_double_to_fixed (offset), \ + { \ + double_to_color (r), \ + double_to_color (g), \ + double_to_color (b), \ + double_to_color (a) \ + } \ + } + + +static const pixman_gradient_stop_t stops[] = { + PIXMAN_STOP (0.25, 1, 0, 0, 0.7), + PIXMAN_STOP (0.5, 1, 1, 0, 0.7), + PIXMAN_STOP (0.75, 0, 1, 0, 0.7), + PIXMAN_STOP (1.0, 0, 0, 1, 0.7) +}; + +#define NUM_STOPS (sizeof (stops) / sizeof (stops[0])) + +static pixman_image_t * +create_conical (int index) +{ + pixman_point_fixed_t c; + double angle; + + c.x = pixman_double_to_fixed (0); + c.y = pixman_double_to_fixed (0); + + angle = (0.5 / NUM_GRADIENTS + index / (double)NUM_GRADIENTS) * 720 - 180; + + return pixman_image_create_conical_gradient ( + &c, pixman_double_to_fixed (angle), stops, NUM_STOPS); +} + +#define CHECK_SIZE 25 + +static void +fill_checkerboard (pixman_image_t *image, int width, int height) +{ +#define C1 0xaaaa +#define C2 0x8888 + + pixman_color_t check1 = { C1, C1, C1, 0xffff }; + pixman_color_t check2 = { C2, C2, C2, 0xffff }; + pixman_image_t *c1, *c2; + int i, j; + + c1 = pixman_image_create_solid_fill (&check1); + c2 = pixman_image_create_solid_fill (&check2); + + for (j = 0; j < height; j += CHECK_SIZE) + { + for (i = 0; i < width; i += CHECK_SIZE) + { + pixman_image_t *src; + + if ((((i / CHECK_SIZE) ^ (j / CHECK_SIZE)) & 1) == 0) + src = c1; + else + src = c2; + + pixman_image_composite32 (PIXMAN_OP_SRC, src, NULL, image, + 0, 0, 0, 0, i, j, + CHECK_SIZE, CHECK_SIZE); + } + } +} + +int +main (int argc, char **argv) +{ + pixman_transform_t transform; + pixman_image_t *src_img, *dest_img; + int i; + + enable_divbyzero_exceptions (); + + dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, + WIDTH, HEIGHT, + NULL, 0); + + fill_checkerboard (dest_img, WIDTH, HEIGHT); + + pixman_transform_init_identity (&transform); + + pixman_transform_translate (NULL, &transform, + pixman_double_to_fixed (0.5), + pixman_double_to_fixed (0.5)); + + pixman_transform_scale (NULL, &transform, + pixman_double_to_fixed (SIZE), + pixman_double_to_fixed (SIZE)); + pixman_transform_translate (NULL, &transform, + pixman_double_to_fixed (0.5), + pixman_double_to_fixed (0.5)); + + for (i = 0; i < NUM_GRADIENTS; i++) + { + int column = i % GRADIENTS_PER_ROW; + int row = i / GRADIENTS_PER_ROW; + + src_img = create_conical (i); + pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NORMAL); + + pixman_image_set_transform (src_img, &transform); + + pixman_image_composite32 ( + PIXMAN_OP_OVER, src_img, NULL,dest_img, + 0, 0, 0, 0, column * SIZE, row * SIZE, + SIZE, SIZE); + + pixman_image_unref (src_img); + } + + show_image (dest_img); + + pixman_image_unref (dest_img); + + return 0; +} diff --git a/pixman/demos/gtk-utils.c b/pixman/demos/gtk-utils.c index 8291a1ed2..d7e946ded 100644 --- a/pixman/demos/gtk-utils.c +++ b/pixman/demos/gtk-utils.c @@ -3,6 +3,72 @@ #include "../test/utils.h" #include "gtk-utils.h" +pixman_image_t * +pixman_image_from_file (const char *filename, pixman_format_code_t format) +{ + GdkPixbuf *pixbuf; + pixman_image_t *image; + int width, height; + uint32_t *data, *d; + uint8_t *gdk_data; + int n_channels; + int j, i; + int stride; + + if (!(pixbuf = gdk_pixbuf_new_from_file (filename, NULL))) + return NULL; + + image = NULL; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + gdk_data = gdk_pixbuf_get_pixels (pixbuf); + stride = gdk_pixbuf_get_rowstride (pixbuf); + + if (!(data = malloc (width * height * sizeof (uint32_t)))) + goto out; + + d = data; + for (j = 0; j < height; ++j) + { + uint8_t *gdk_line = gdk_data; + + for (i = 0; i < width; ++i) + { + int r, g, b, a; + uint32_t pixel; + + r = gdk_line[0]; + g = gdk_line[1]; + b = gdk_line[2]; + + if (n_channels == 4) + a = gdk_line[3]; + else + a = 0xff; + + r = (r * a + 127) / 255; + g = (g * a + 127) / 255; + b = (b * a + 127) / 255; + + pixel = (a << 24) | (r << 16) | (g << 8) | b; + + *d++ = pixel; + gdk_line += n_channels; + } + + gdk_data += stride; + } + + image = pixman_image_create_bits ( + format, width, height, data, width * 4); + +out: + g_object_unref (pixbuf); + return image; +} + GdkPixbuf * pixbuf_from_argb32 (uint32_t *bits, int width, diff --git a/pixman/demos/gtk-utils.h b/pixman/demos/gtk-utils.h index 55cb7018a..36be4def6 100644 --- a/pixman/demos/gtk-utils.h +++ b/pixman/demos/gtk-utils.h @@ -6,6 +6,9 @@ void show_image (pixman_image_t *image); +pixman_image_t * +pixman_image_from_file (const char *filename, pixman_format_code_t format); + GdkPixbuf *pixbuf_from_argb32 (uint32_t *bits, int width, int height, diff --git a/pixman/demos/scale.c b/pixman/demos/scale.c new file mode 100644 index 000000000..9100ff72a --- /dev/null +++ b/pixman/demos/scale.c @@ -0,0 +1,431 @@ +/* + * Copyright 2012, Red Hat, Inc. + * Copyright 2012, Soren Sandmann + * + * 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. + * + * Author: Soren Sandmann <soren.sandmann@gmail.com> + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <math.h> +#include <gtk/gtk.h> +#include <pixman.h> +#include <stdlib.h> +#include "gtk-utils.h" + +typedef struct +{ + GtkBuilder * builder; + pixman_image_t * original; + GtkAdjustment * scale_x_adjustment; + GtkAdjustment * scale_y_adjustment; + GtkAdjustment * rotate_adjustment; + int scaled_width; + int scaled_height; +} app_t; + +static GtkWidget * +get_widget (app_t *app, const char *name) +{ + GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (app->builder, name)); + + if (!widget) + g_error ("Widget %s not found\n", name); + + return widget; +} + +static double +min4 (double a, double b, double c, double d) +{ + double m1, m2; + + m1 = MIN (a, b); + m2 = MIN (c, d); + return MIN (m1, m2); +} + +static double +max4 (double a, double b, double c, double d) +{ + double m1, m2; + + m1 = MAX (a, b); + m2 = MAX (c, d); + return MAX (m1, m2); +} + +static void +compute_extents (pixman_f_transform_t *trans, double *sx, double *sy) +{ + double min_x, max_x, min_y, max_y; + pixman_f_vector_t v[4] = + { + { { 1, 1, 1 } }, + { { -1, 1, 1 } }, + { { -1, -1, 1 } }, + { { 1, -1, 1 } }, + }; + + pixman_f_transform_point (trans, &v[0]); + pixman_f_transform_point (trans, &v[1]); + pixman_f_transform_point (trans, &v[2]); + pixman_f_transform_point (trans, &v[3]); + + min_x = min4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]); + max_x = max4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]); + min_y = min4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]); + max_y = max4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]); + + *sx = (max_x - min_x) / 2.0; + *sy = (max_y - min_y) / 2.0; +} + +typedef struct +{ + char name [20]; + pixman_kernel_t value; +} named_int_t; + +static const named_int_t filters[] = +{ + { "Box", PIXMAN_KERNEL_BOX }, + { "Impulse", PIXMAN_KERNEL_IMPULSE }, + { "Linear", PIXMAN_KERNEL_LINEAR }, + { "Cubic", PIXMAN_KERNEL_CUBIC }, + { "Lanczos2", PIXMAN_KERNEL_LANCZOS2 }, + { "Lanczos3", PIXMAN_KERNEL_LANCZOS3 }, + { "Lanczos3 Stretched", PIXMAN_KERNEL_LANCZOS3_STRETCHED }, + { "Gaussian", PIXMAN_KERNEL_GAUSSIAN }, +}; + +static const named_int_t repeats[] = +{ + { "None", PIXMAN_REPEAT_NONE }, + { "Normal", PIXMAN_REPEAT_NORMAL }, + { "Reflect", PIXMAN_REPEAT_REFLECT }, + { "Pad", PIXMAN_REPEAT_PAD }, +}; + +static pixman_kernel_t +get_value (app_t *app, const named_int_t table[], const char *box_name) +{ + GtkComboBox *box = GTK_COMBO_BOX (get_widget (app, box_name)); + + return table[gtk_combo_box_get_active (box)].value; +} + +static void +copy_to_counterpart (app_t *app, GObject *object) +{ + static const char *xy_map[] = + { + "reconstruct_x_combo_box", "reconstruct_y_combo_box", + "sample_x_combo_box", "sample_y_combo_box", + "scale_x_adjustment", "scale_y_adjustment", + }; + GObject *counterpart = NULL; + int i; + + for (i = 0; i < G_N_ELEMENTS (xy_map); i += 2) + { + GObject *x = gtk_builder_get_object (app->builder, xy_map[i]); + GObject *y = gtk_builder_get_object (app->builder, xy_map[i + 1]); + + if (object == x) + counterpart = y; + if (object == y) + counterpart = x; + } + + if (!counterpart) + return; + + if (GTK_IS_COMBO_BOX (counterpart)) + { + gtk_combo_box_set_active ( + GTK_COMBO_BOX (counterpart), + gtk_combo_box_get_active ( + GTK_COMBO_BOX (object))); + } + else if (GTK_IS_ADJUSTMENT (counterpart)) + { + gtk_adjustment_set_value ( + GTK_ADJUSTMENT (counterpart), + gtk_adjustment_get_value ( + GTK_ADJUSTMENT (object))); + } +} + +static double +to_scale (double v) +{ + return pow (1.15, v); +} + +static void +rescale (GtkWidget *may_be_null, app_t *app) +{ + pixman_f_transform_t ftransform; + pixman_transform_t transform; + double new_width, new_height; + double fscale_x, fscale_y; + double rotation; + pixman_fixed_t *params; + int n_params; + double sx, sy; + + pixman_f_transform_init_identity (&ftransform); + + if (may_be_null && gtk_toggle_button_get_active ( + GTK_TOGGLE_BUTTON (get_widget (app, "lock_checkbutton")))) + { + copy_to_counterpart (app, G_OBJECT (may_be_null)); + } + + fscale_x = gtk_adjustment_get_value (app->scale_x_adjustment); + fscale_y = gtk_adjustment_get_value (app->scale_y_adjustment); + rotation = gtk_adjustment_get_value (app->rotate_adjustment); + + fscale_x = to_scale (fscale_x); + fscale_y = to_scale (fscale_y); + + new_width = pixman_image_get_width (app->original) * fscale_x; + new_height = pixman_image_get_height (app->original) * fscale_y; + + pixman_f_transform_scale (&ftransform, NULL, fscale_x, fscale_y); + + pixman_f_transform_translate (&ftransform, NULL, - new_width / 2.0, - new_height / 2.0); + + rotation = (rotation / 360.0) * 2 * M_PI; + pixman_f_transform_rotate (&ftransform, NULL, cos (rotation), sin (rotation)); + + pixman_f_transform_translate (&ftransform, NULL, new_width / 2.0, new_height / 2.0); + + pixman_f_transform_invert (&ftransform, &ftransform); + + compute_extents (&ftransform, &sx, &sy); + + pixman_transform_from_pixman_f_transform (&transform, &ftransform); + pixman_image_set_transform (app->original, &transform); + + params = pixman_filter_create_separable_convolution ( + &n_params, + sx * 65536.0 + 0.5, + sy * 65536.0 + 0.5, + get_value (app, filters, "reconstruct_x_combo_box"), + get_value (app, filters, "reconstruct_y_combo_box"), + get_value (app, filters, "sample_x_combo_box"), + get_value (app, filters, "sample_y_combo_box"), + 4, 4); + + pixman_image_set_filter (app->original, PIXMAN_FILTER_SEPARABLE_CONVOLUTION, params, n_params); + + pixman_image_set_repeat ( + app->original, get_value (app, repeats, "repeat_combo_box")); + + free (params); + + app->scaled_width = ceil (new_width); + app->scaled_height = ceil (new_height); + + gtk_widget_set_size_request ( + get_widget (app, "drawing_area"), new_width + 0.5, new_height + 0.5); + + gtk_widget_queue_draw ( + get_widget (app, "drawing_area")); +} + +static gboolean +on_expose (GtkWidget *da, GdkEvent *event, gpointer data) +{ + app_t *app = data; + GdkRectangle *area = &event->expose.area; + cairo_surface_t *surface; + pixman_image_t *tmp; + cairo_t *cr; + uint32_t *pixels; + + pixels = calloc (1, area->width * area->height * 4); + tmp = pixman_image_create_bits ( + PIXMAN_a8r8g8b8, area->width, area->height, pixels, area->width * 4); + + if (area->x < app->scaled_width && area->y < app->scaled_height) + { + pixman_image_composite ( + PIXMAN_OP_SRC, + app->original, NULL, tmp, + area->x, area->y, 0, 0, 0, 0, + app->scaled_width - area->x, app->scaled_height - area->y); + } + + surface = cairo_image_surface_create_for_data ( + (uint8_t *)pixels, CAIRO_FORMAT_ARGB32, + area->width, area->height, area->width * 4); + + cr = gdk_cairo_create (da->window); + + cairo_set_source_surface (cr, surface, area->x, area->y); + + cairo_paint (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + free (pixels); + pixman_image_unref (tmp); + + return TRUE; +} + +static void +set_up_combo_box (app_t *app, const char *box_name, + int n_entries, const named_int_t table[]) +{ + GtkWidget *widget = get_widget (app, box_name); + GtkListStore *model; + GtkCellRenderer *cell; + int i; + + model = gtk_list_store_new (1, G_TYPE_STRING); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), cell, + "text", 0, + NULL); + + gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (model)); + + for (i = 0; i < n_entries; ++i) + { + const named_int_t *info = &(table[i]); + GtkTreeIter iter; + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, 0, info->name, -1); + } + + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + + g_signal_connect (widget, "changed", G_CALLBACK (rescale), app); +} + +static void +set_up_filter_box (app_t *app, const char *box_name) +{ + set_up_combo_box (app, box_name, G_N_ELEMENTS (filters), filters); +} + +static char * +format_value (GtkWidget *widget, double value) +{ + return g_strdup_printf ("%.4f", to_scale (value)); +} + +static app_t * +app_new (pixman_image_t *original) +{ + GtkWidget *widget; + app_t *app = g_malloc (sizeof *app); + GError *err = NULL; + + app->builder = gtk_builder_new (); + app->original = original; + + if (!gtk_builder_add_from_file (app->builder, "scale.ui", &err)) + g_error ("Could not read file scale.ui: %s", err->message); + + app->scale_x_adjustment = + GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "scale_x_adjustment")); + app->scale_y_adjustment = + GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "scale_y_adjustment")); + app->rotate_adjustment = + GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "rotate_adjustment")); + + g_signal_connect (app->scale_x_adjustment, "value_changed", G_CALLBACK (rescale), app); + g_signal_connect (app->scale_y_adjustment, "value_changed", G_CALLBACK (rescale), app); + g_signal_connect (app->rotate_adjustment, "value_changed", G_CALLBACK (rescale), app); + + widget = get_widget (app, "scale_x_scale"); + gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL); + g_signal_connect (widget, "format_value", G_CALLBACK (format_value), app); + widget = get_widget (app, "scale_y_scale"); + gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL); + g_signal_connect (widget, "format_value", G_CALLBACK (format_value), app); + widget = get_widget (app, "rotate_scale"); + gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL); + + widget = get_widget (app, "drawing_area"); + g_signal_connect (widget, "expose_event", G_CALLBACK (on_expose), app); + + set_up_filter_box (app, "reconstruct_x_combo_box"); + set_up_filter_box (app, "reconstruct_y_combo_box"); + set_up_filter_box (app, "sample_x_combo_box"); + set_up_filter_box (app, "sample_y_combo_box"); + + set_up_combo_box ( + app, "repeat_combo_box", G_N_ELEMENTS (repeats), repeats); + + g_signal_connect ( + gtk_builder_get_object (app->builder, "lock_checkbutton"), + "toggled", G_CALLBACK (rescale), app); + + rescale (NULL, app); + + return app; +} + +int +main (int argc, char **argv) +{ + GtkWidget *window; + pixman_image_t *image; + app_t *app; + + gtk_init (&argc, &argv); + + if (argc < 2) + { + printf ("%s <image file>\n", argv[0]); + return -1; + } + + if (!(image = pixman_image_from_file (argv[1], PIXMAN_a8r8g8b8))) + { + printf ("Could not load image \"%s\"\n", argv[1]); + return -1; + } + + app = app_new (image); + + window = get_widget (app, "main"); + + g_signal_connect (window, "delete_event", G_CALLBACK (gtk_main_quit), NULL); + + gtk_window_set_default_size (GTK_WINDOW (window), 1024, 768); + + gtk_widget_show_all (window); + + gtk_main (); + + return 0; +} diff --git a/pixman/demos/scale.ui b/pixman/demos/scale.ui new file mode 100644 index 000000000..f7c0c805f --- /dev/null +++ b/pixman/demos/scale.ui @@ -0,0 +1,302 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 2.12 --> + <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkAdjustment" id="rotate_adjustment"> + <property name="lower">-180</property> + <property name="upper">190</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> + <object class="GtkAdjustment" id="scale_y_adjustment"> + <property name="lower">-32</property> + <property name="upper">42</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> + <object class="GtkAdjustment" id="scale_x_adjustment"> + <property name="lower">-32</property> + <property name="upper">42</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> + <object class="GtkWindow" id="main"> + <child> + <object class="GtkHBox" id="u"> + <property name="visible">True</property> + <property name="spacing">12</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkViewport" id="viewport1"> + <property name="visible">True</property> + <child> + <object class="GtkDrawingArea" id="drawing_area"> + <property name="visible">True</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="box1"> + <property name="visible">True</property> + <child> + <object class="GtkHBox" id="box2"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkVBox" id="box3"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Scale X</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVScale" id="scale_x_scale"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">scale_x_adjustment</property> + <property name="fill_level">32</property> + <property name="value_pos">right</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="box4"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Scale Y</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVScale" id="scale_y_scale"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">scale_y_adjustment</property> + <property name="fill_level">32</property> + <property name="value_pos">right</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="box5"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Rotate</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVScale" id="rotate_scale"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">rotate_adjustment</property> + <property name="fill_level">180</property> + <property name="value_pos">right</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="padding">6</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="box6"> + <property name="visible">True</property> + <child> + <object class="GtkCheckButton" + id="lock_checkbutton"> + <property name="label" translatable="yes">Lock X and Y Dimensions</property> + <property name="xalign">0.0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkTable" id="grid1"> + <property name="visible">True</property> + <property name="column_spacing">8</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes"><b>Reconstruct X:</b></property> + <property name="use_markup">True</property> + </object> + </child> + <child> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes"><b>Reconstruct Y:</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes"><b>Sample X:</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label7"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes"><b>Sample Y:</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes"><b>Repeat:</b></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="reconstruct_x_combo_box"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="reconstruct_y_combo_box"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="sample_x_combo_box"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="sample_y_combo_box"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="repeat_combo_box"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">4</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/pixman/demos/zone_plate.png b/pixman/demos/zone_plate.png Binary files differnew file mode 100644 index 000000000..519291d6d --- /dev/null +++ b/pixman/demos/zone_plate.png diff --git a/pixman/pixman/Makefile.sources b/pixman/pixman/Makefile.sources index 5351fb03d..c624eb9a8 100644 --- a/pixman/pixman/Makefile.sources +++ b/pixman/pixman/Makefile.sources @@ -6,6 +6,7 @@ libpixman_sources = \ pixman-combine32.c \ pixman-combine-float.c \ pixman-conical-gradient.c \ + pixman-filter.c \ pixman-x86.c \ pixman-mips.c \ pixman-arm.c \ diff --git a/pixman/pixman/pixman-bits-image.c b/pixman/pixman/pixman-bits-image.c index 7787ef1b8..86d80c3f5 100644 --- a/pixman/pixman/pixman-bits-image.c +++ b/pixman/pixman/pixman-bits-image.c @@ -426,6 +426,104 @@ bits_image_fetch_pixel_convolution (bits_image_t *image, return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); } +static uint32_t +bits_image_fetch_pixel_separable_convolution (bits_image_t *image, + pixman_fixed_t x, + pixman_fixed_t y, + get_pixel_t get_pixel) +{ + pixman_fixed_t *params = image->common.filter_params; + pixman_repeat_t repeat_mode = image->common.repeat; + int width = image->width; + int height = image->height; + int cwidth = pixman_fixed_to_int (params[0]); + int cheight = pixman_fixed_to_int (params[1]); + int x_phase_bits = pixman_fixed_to_int (params[2]); + int y_phase_bits = pixman_fixed_to_int (params[3]); + int x_phase_shift = 16 - x_phase_bits; + int y_phase_shift = 16 - y_phase_bits; + int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; + int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; + pixman_fixed_t *y_params; + int srtot, sgtot, sbtot, satot; + int32_t x1, x2, y1, y2; + int32_t px, py; + int i, j; + + /* Round x and y to the middle of the closest phase before continuing. This + * ensures that the convolution matrix is aligned right, since it was + * positioned relative to a particular phase (and not relative to whatever + * exact fraction we happen to get here). + */ + x = ((x >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); + y = ((y >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); + + px = (x & 0xffff) >> x_phase_shift; + py = (y & 0xffff) >> y_phase_shift; + + y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; + + x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); + y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); + x2 = x1 + cwidth; + y2 = y1 + cheight; + + srtot = sgtot = sbtot = satot = 0; + + for (i = y1; i < y2; ++i) + { + pixman_fixed_48_16_t fy = *y_params++; + pixman_fixed_t *x_params = params + 4 + px * cwidth; + + if (fy) + { + for (j = x1; j < x2; ++j) + { + pixman_fixed_t fx = *x_params++; + int rx = j; + int ry = i; + + if (fx) + { + pixman_fixed_t f; + uint32_t pixel; + + if (repeat_mode != PIXMAN_REPEAT_NONE) + { + repeat (repeat_mode, &rx, width); + repeat (repeat_mode, &ry, height); + + pixel = get_pixel (image, rx, ry, FALSE); + } + else + { + pixel = get_pixel (image, rx, ry, TRUE); + } + + f = (fy * fx + 0x8000) >> 16; + + srtot += (int)RED_8 (pixel) * f; + sgtot += (int)GREEN_8 (pixel) * f; + sbtot += (int)BLUE_8 (pixel) * f; + satot += (int)ALPHA_8 (pixel) * f; + } + } + } + } + + satot = (satot + 0x8000) >> 16; + srtot = (srtot + 0x8000) >> 16; + sgtot = (sgtot + 0x8000) >> 16; + sbtot = (sbtot + 0x8000) >> 16; + + satot = CLIP (satot, 0, 0xff); + srtot = CLIP (srtot, 0, 0xff); + sgtot = CLIP (sgtot, 0, 0xff); + sbtot = CLIP (sbtot, 0, 0xff); + + return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); +} + static force_inline uint32_t bits_image_fetch_pixel_filtered (bits_image_t *image, pixman_fixed_t x, @@ -449,6 +547,10 @@ bits_image_fetch_pixel_filtered (bits_image_t *image, return bits_image_fetch_pixel_convolution (image, x, y, get_pixel); break; + case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: + return bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel); + break; + default: break; } @@ -618,11 +720,155 @@ bits_image_fetch_general (pixman_iter_t *iter, return buffer; } -static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x); static force_inline void +bits_image_fetch_separable_convolution_affine (pixman_image_t * image, + int offset, + int line, + int width, + uint32_t * buffer, + const uint32_t * mask, + + convert_pixel_t convert_pixel, + pixman_format_code_t format, + pixman_repeat_t repeat_mode) +{ + bits_image_t *bits = &image->bits; + pixman_fixed_t *params = image->common.filter_params; + int cwidth = pixman_fixed_to_int (params[0]); + int cheight = pixman_fixed_to_int (params[1]); + int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; + int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; + int x_phase_bits = pixman_fixed_to_int (params[2]); + int y_phase_bits = pixman_fixed_to_int (params[3]); + int x_phase_shift = 16 - x_phase_bits; + int y_phase_shift = 16 - y_phase_bits; + pixman_fixed_t vx, vy; + pixman_fixed_t ux, uy; + pixman_vector_t v; + int k; + + /* reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (image->common.transform, &v)) + return; + + ux = image->common.transform->matrix[0][0]; + uy = image->common.transform->matrix[1][0]; + + vx = v.vector[0]; + vy = v.vector[1]; + + for (k = 0; k < width; ++k) + { + pixman_fixed_t *y_params; + int satot, srtot, sgtot, sbtot; + pixman_fixed_t x, y; + int32_t x1, x2, y1, y2; + int32_t px, py; + int i, j; + + if (mask && !mask[k]) + goto next; + + /* Round x and y to the middle of the closest phase before continuing. This + * ensures that the convolution matrix is aligned right, since it was + * positioned relative to a particular phase (and not relative to whatever + * exact fraction we happen to get here). + */ + x = ((vx >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); + y = ((vy >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); + + px = (x & 0xffff) >> x_phase_shift; + py = (y & 0xffff) >> y_phase_shift; + + x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); + y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); + x2 = x1 + cwidth; + y2 = y1 + cheight; + + satot = srtot = sgtot = sbtot = 0; + + y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; + + for (i = y1; i < y2; ++i) + { + pixman_fixed_t fy = *y_params++; + + if (fy) + { + pixman_fixed_t *x_params = params + 4 + px * cwidth; + + for (j = x1; j < x2; ++j) + { + pixman_fixed_t fx = *x_params++; + int rx = j; + int ry = i; + + if (fx) + { + pixman_fixed_t f; + uint32_t pixel, mask; + uint8_t *row; + + mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; + + if (repeat_mode != PIXMAN_REPEAT_NONE) + { + repeat (repeat_mode, &rx, bits->width); + repeat (repeat_mode, &ry, bits->height); + + row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; + pixel = convert_pixel (row, rx) | mask; + } + else + { + if (rx < 0 || ry < 0 || rx >= bits->width || ry >= bits->height) + { + pixel = 0; + } + else + { + row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; + pixel = convert_pixel (row, rx) | mask; + } + } + + f = ((pixman_fixed_32_32_t)fx * fy + 0x8000) >> 16; + srtot += (int)RED_8 (pixel) * f; + sgtot += (int)GREEN_8 (pixel) * f; + sbtot += (int)BLUE_8 (pixel) * f; + satot += (int)ALPHA_8 (pixel) * f; + } + } + } + } + + satot = (satot + 0x8000) >> 16; + srtot = (srtot + 0x8000) >> 16; + sgtot = (sgtot + 0x8000) >> 16; + sbtot = (sbtot + 0x8000) >> 16; + + satot = CLIP (satot, 0, 0xff); + srtot = CLIP (srtot, 0, 0xff); + sgtot = CLIP (sgtot, 0, 0xff); + sbtot = CLIP (sbtot, 0, 0xff); + + buffer[k] = (satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot << 0); + + next: + vx += ux; + vy += uy; + } +} + +static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static force_inline void bits_image_fetch_bilinear_affine (pixman_image_t * image, int offset, int line, @@ -871,6 +1117,23 @@ convert_r5g6b5 (const uint8_t *row, int x) return CONVERT_0565_TO_0888 (*((uint16_t *)row + x)); } +#define MAKE_SEPARABLE_CONVOLUTION_FETCHER(name, format, repeat_mode) \ + static uint32_t * \ + bits_image_fetch_separable_convolution_affine_ ## name (pixman_iter_t *iter, \ + const uint32_t * mask) \ + { \ + bits_image_fetch_separable_convolution_affine ( \ + iter->image, \ + iter->x, iter->y++, \ + iter->width, \ + iter->buffer, mask, \ + convert_ ## format, \ + PIXMAN_ ## format, \ + repeat_mode); \ + \ + return iter->buffer; \ + } + #define MAKE_BILINEAR_FETCHER(name, format, repeat_mode) \ static uint32_t * \ bits_image_fetch_bilinear_affine_ ## name (pixman_iter_t *iter, \ @@ -903,7 +1166,8 @@ convert_r5g6b5 (const uint8_t *row, int x) #define MAKE_FETCHERS(name, format, repeat_mode) \ MAKE_NEAREST_FETCHER (name, format, repeat_mode) \ - MAKE_BILINEAR_FETCHER (name, format, repeat_mode) + MAKE_BILINEAR_FETCHER (name, format, repeat_mode) \ + MAKE_SEPARABLE_CONVOLUTION_FETCHER (name, format, repeat_mode) MAKE_FETCHERS (pad_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_PAD) MAKE_FETCHERS (none_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NONE) @@ -1153,6 +1417,20 @@ static const fetcher_info_t fetcher_info[] = FAST_PATH_AFFINE_TRANSFORM | \ FAST_PATH_NEAREST_FILTER) +#define GENERAL_SEPARABLE_CONVOLUTION_FLAGS \ + (FAST_PATH_NO_ALPHA_MAP | \ + FAST_PATH_NO_ACCESSORS | \ + FAST_PATH_HAS_TRANSFORM | \ + FAST_PATH_AFFINE_TRANSFORM | \ + FAST_PATH_SEPARABLE_CONVOLUTION_FILTER) + +#define SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ + { PIXMAN_ ## format, \ + GENERAL_SEPARABLE_CONVOLUTION_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ + bits_image_fetch_separable_convolution_affine_ ## name, \ + _pixman_image_get_scanline_generic_float \ + }, + #define BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ { PIXMAN_ ## format, \ GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ @@ -1168,6 +1446,7 @@ static const fetcher_info_t fetcher_info[] = }, #define AFFINE_FAST_PATHS(name, format, repeat) \ + SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ NEAREST_AFFINE_FAST_PATH(name, format, repeat) diff --git a/pixman/pixman/pixman-filter.c b/pixman/pixman/pixman-filter.c new file mode 100644 index 000000000..c9d2dc74c --- /dev/null +++ b/pixman/pixman/pixman-filter.c @@ -0,0 +1,340 @@ +/* + * Copyright 2012, Red Hat, Inc. + * Copyright 2012, Soren Sandmann + * + * 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. + * + * Author: Soren Sandmann <soren.sandmann@gmail.com> + */ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> +#include <config.h> +#include "pixman-private.h" + +typedef double (* kernel_func_t) (double x); + +typedef struct +{ + pixman_kernel_t kernel; + kernel_func_t func; + double width; +} filter_info_t; + +static double +impulse_kernel (double x) +{ + return (x == 0.0)? 1.0 : 0.0; +} + +static double +box_kernel (double x) +{ + return 1; +} + +static double +linear_kernel (double x) +{ + return 1 - fabs (x); +} + +static double +gaussian_kernel (double x) +{ +#define SQRT2 (1.4142135623730950488016887242096980785696718753769480) +#define SIGMA (SQRT2 / 2.0) + + return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI)); +} + +static double +sinc (double x) +{ + if (x == 0.0) + return 1.0; + else + return sin (M_PI * x) / (M_PI * x); +} + +static double +lanczos (double x, int n) +{ + return sinc (x) * sinc (x * (1.0 / n)); +} + +static double +lanczos2_kernel (double x) +{ + return lanczos (x, 2); +} + +static double +lanczos3_kernel (double x) +{ + return lanczos (x, 3); +} + +static double +nice_kernel (double x) +{ + return lanczos3_kernel (x * 0.75); +} + +static double +general_cubic (double x, double B, double C) +{ + double ax = fabs(x); + + if (ax < 1) + { + return ((12 - 9 * B - 6 * C) * ax * ax * ax + + (-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6; + } + else if (ax >= 1 && ax < 2) + { + return ((-B - 6 * C) * ax * ax * ax + + (6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) * + ax + (8 * B + 24 * C)) / 6; + } + else + { + return 0; + } +} + +static double +cubic_kernel (double x) +{ + /* This is the Mitchell-Netravali filter. + * + * (0.0, 0.5) would give us the Catmull-Rom spline, + * but that one seems to be indistinguishable from Lanczos2. + */ + return general_cubic (x, 1/3.0, 1/3.0); +} + +static const filter_info_t filters[] = +{ + { PIXMAN_KERNEL_IMPULSE, impulse_kernel, 0.0 }, + { PIXMAN_KERNEL_BOX, box_kernel, 1.0 }, + { PIXMAN_KERNEL_LINEAR, linear_kernel, 2.0 }, + { PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 }, + { PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 6 * SIGMA }, + { PIXMAN_KERNEL_LANCZOS2, lanczos2_kernel, 4.0 }, + { PIXMAN_KERNEL_LANCZOS3, lanczos3_kernel, 6.0 }, + { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 }, +}; + +/* This function scales @kernel2 by @scale, then + * aligns @x1 in @kernel1 with @x2 in @kernel2 and + * and integrates the product of the kernels across @width. + * + * This function assumes that the intervals are within + * the kernels in question. E.g., the caller must not + * try to integrate a linear kernel ouside of [-1:1] + */ +static double +integral (pixman_kernel_t kernel1, double x1, + pixman_kernel_t kernel2, double scale, double x2, + double width) +{ + /* If the integration interval crosses zero, break it into + * two separate integrals. This ensures that filters such + * as LINEAR that are not differentiable at 0 will still + * integrate properly. + */ + if (x1 < 0 && x1 + width > 0) + { + return + integral (kernel1, x1, kernel2, scale, x2, - x1) + + integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1); + } + else if (x2 < 0 && x2 + width > 0) + { + return + integral (kernel1, x1, kernel2, scale, x2, - x2) + + integral (kernel1, x1 - x2, kernel2, scale, 0, width + x2); + } + else if (kernel1 == PIXMAN_KERNEL_IMPULSE) + { + assert (width == 0.0); + return filters[kernel2].func (x2 * scale); + } + else if (kernel2 == PIXMAN_KERNEL_IMPULSE) + { + assert (width == 0.0); + return filters[kernel1].func (x1); + } + else + { + /* Integration via Simpson's rule */ +#define N_SEGMENTS 128 +#define SAMPLE(a1, a2) \ + (filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale)) + + double s = 0.0; + double h = width / (double)N_SEGMENTS; + int i; + + s = SAMPLE (x1, x2); + + for (i = 1; i < N_SEGMENTS; i += 2) + { + double a1 = x1 + h * i; + double a2 = x2 + h * i; + + s += 2 * SAMPLE (a1, a2); + + if (i >= 2 && i < N_SEGMENTS - 1) + s += 4 * SAMPLE (a1, a2); + } + + s += SAMPLE (x1 + width, x2 + width); + + return h * s * (1.0 / 3.0); + } +} + +static pixman_fixed_t * +create_1d_filter (int *width, + pixman_kernel_t reconstruct, + pixman_kernel_t sample, + double scale, + int n_phases) +{ + pixman_fixed_t *params, *p; + double step; + double size; + int i; + + size = scale * filters[sample].width + filters[reconstruct].width; + *width = ceil (size); + + p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t)); + + step = 1.0 / n_phases; + + for (i = 0; i < n_phases; ++i) + { + double frac = step / 2.0 + i * step; + pixman_fixed_t new_total; + int x, x1, x2; + double total; + + /* Sample convolution of reconstruction and sampling + * filter. See rounding.txt regarding the rounding + * and sample positions. + */ + + x1 = ceil (frac - *width / 2.0 - 0.5); + x2 = x1 + *width; + + total = 0; + for (x = x1; x < x2; ++x) + { + double pos = x + 0.5 - frac; + double rlow = - filters[reconstruct].width / 2.0; + double rhigh = rlow + filters[reconstruct].width; + double slow = pos - scale * filters[sample].width / 2.0; + double shigh = slow + scale * filters[sample].width; + double c = 0.0; + double ilow, ihigh; + + if (rhigh >= slow && rlow <= shigh) + { + ilow = MAX (slow, rlow); + ihigh = MIN (shigh, rhigh); + + c = integral (reconstruct, ilow, + sample, 1.0 / scale, ilow - pos, + ihigh - ilow); + } + + total += c; + *p++ = (pixman_fixed_t)(c * 65535.0 + 0.5); + } + + /* Normalize */ + p -= *width; + total = 1 / total; + new_total = 0; + for (x = x1; x < x2; ++x) + { + pixman_fixed_t t = (*p) * total + 0.5; + + new_total += t; + *p++ = t; + } + + if (new_total != pixman_fixed_1) + *(p - *width / 2) += (pixman_fixed_1 - new_total); + } + + return params; +} + +/* Create the parameter list for a SEPARABLE_CONVOLUTION filter + * with the given kernels and scale parameters + */ +PIXMAN_EXPORT pixman_fixed_t * +pixman_filter_create_separable_convolution (int *n_values, + pixman_fixed_t scale_x, + pixman_fixed_t scale_y, + pixman_kernel_t reconstruct_x, + pixman_kernel_t reconstruct_y, + pixman_kernel_t sample_x, + pixman_kernel_t sample_y, + int subsample_bits_x, + int subsample_bits_y) +{ + double sx = fabs (pixman_fixed_to_double (scale_x)); + double sy = fabs (pixman_fixed_to_double (scale_y)); + pixman_fixed_t *horz, *vert, *params; + int subsample_x, subsample_y; + int width, height; + + subsample_x = (1 << subsample_bits_x); + subsample_y = (1 << subsample_bits_y); + + horz = create_1d_filter (&width, reconstruct_x, sample_x, sx, subsample_x); + vert = create_1d_filter (&height, reconstruct_y, sample_y, sy, subsample_y); + + *n_values = 4 + width * subsample_x + height * subsample_y; + + params = malloc (*n_values * sizeof (pixman_fixed_t)); + + params[0] = pixman_int_to_fixed (width); + params[1] = pixman_int_to_fixed (height); + params[2] = pixman_int_to_fixed (subsample_bits_x); + params[3] = pixman_int_to_fixed (subsample_bits_y); + + memcpy (params + 4, horz, + width * subsample_x * sizeof (pixman_fixed_t)); + memcpy (params + 4 + width * subsample_x, vert, + height * subsample_y * sizeof (pixman_fixed_t)); + + free (horz); + free (vert); + + return params; +} diff --git a/pixman/pixman/pixman-image.c b/pixman/pixman/pixman-image.c index d9c303441..6f076d5c6 100644 --- a/pixman/pixman/pixman-image.c +++ b/pixman/pixman/pixman-image.c @@ -373,6 +373,10 @@ compute_image_info (pixman_image_t *image) case PIXMAN_FILTER_CONVOLUTION: break; + case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: + flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER; + break; + default: flags |= FAST_PATH_NO_CONVOLUTION_FILTER; break; @@ -515,8 +519,9 @@ compute_image_info (pixman_image_t *image) * if all channels are opaque, so we simply turn it off * unconditionally for those images. */ - if (image->common.alpha_map || - image->common.filter == PIXMAN_FILTER_CONVOLUTION || + if (image->common.alpha_map || + image->common.filter == PIXMAN_FILTER_CONVOLUTION || + image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION || image->common.component_alpha) { flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE); @@ -679,6 +684,19 @@ pixman_image_set_filter (pixman_image_t * image, if (params == common->filter_params && filter == common->filter) return TRUE; + if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION) + { + int width = pixman_fixed_to_int (params[0]); + int height = pixman_fixed_to_int (params[1]); + int x_phase_bits = pixman_fixed_to_int (params[2]); + int y_phase_bits = pixman_fixed_to_int (params[3]); + int n_x_phases = (1 << x_phase_bits); + int n_y_phases = (1 << y_phase_bits); + + return_val_if_fail ( + n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE); + } + new_params = NULL; if (params) { diff --git a/pixman/pixman/pixman-private.h b/pixman/pixman/pixman-private.h index c0a6bc0a5..99125a17e 100644 --- a/pixman/pixman/pixman-private.h +++ b/pixman/pixman/pixman-private.h @@ -687,6 +687,7 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask); #define FAST_PATH_SAMPLES_COVER_CLIP_NEAREST (1 << 23) #define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR (1 << 24) #define FAST_PATH_BITS_IMAGE (1 << 25) +#define FAST_PATH_SEPARABLE_CONVOLUTION_FILTER (1 << 26) #define FAST_PATH_PAD_REPEAT \ (FAST_PATH_NO_NONE_REPEAT | \ diff --git a/pixman/pixman/pixman.c b/pixman/pixman/pixman.c index e0ccd87d8..0661f41b0 100644 --- a/pixman/pixman/pixman.c +++ b/pixman/pixman/pixman.c @@ -455,6 +455,14 @@ analyze_extent (pixman_image_t *image, height = params[1]; break; + case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: + params = image->common.filter_params; + x_off = - pixman_fixed_e - ((params[0] - pixman_fixed_1) >> 1); + y_off = - pixman_fixed_e - ((params[1] - pixman_fixed_1) >> 1); + width = params[0]; + height = params[1]; + break; + case PIXMAN_FILTER_GOOD: case PIXMAN_FILTER_BEST: case PIXMAN_FILTER_BILINEAR: diff --git a/pixman/pixman/pixman.h b/pixman/pixman/pixman.h index 33ebf3f64..7ff9fb52a 100644 --- a/pixman/pixman/pixman.h +++ b/pixman/pixman/pixman.h @@ -292,7 +292,28 @@ typedef enum PIXMAN_FILTER_BEST, PIXMAN_FILTER_NEAREST, PIXMAN_FILTER_BILINEAR, - PIXMAN_FILTER_CONVOLUTION + PIXMAN_FILTER_CONVOLUTION, + + /* The SEPARABLE_CONVOLUTION filter takes the following parameters: + * + * width: integer given as 16.16 fixpoint number + * height: integer given as 16.16 fixpoint number + * x_phase_bits: integer given as 16.16 fixpoint + * y_phase_bits: integer given as 16.16 fixpoint + * xtables: (1 << x_phase_bits) tables of size width + * ytables: (1 << y_phase_bits) tables of size height + * + * When sampling at (x, y), the location is first rounded to one of + * n_x_phases * n_y_phases subpixel positions. These subpixel positions + * determine an xtable and a ytable to use. + * + * Conceptually a width x height matrix is then formed in which each entry + * is the product of the corresponding entries in the x and y tables. + * This matrix is then aligned with the image pixels such that its center + * is as close as possible to the subpixel location chosen earlier. Then + * the image is convolved with the matrix and the resulting pixel returned. + */ + PIXMAN_FILTER_SEPARABLE_CONVOLUTION } pixman_filter_t; typedef enum @@ -810,6 +831,33 @@ int pixman_image_get_height (pixman_image_t int pixman_image_get_stride (pixman_image_t *image); /* in bytes */ int pixman_image_get_depth (pixman_image_t *image); pixman_format_code_t pixman_image_get_format (pixman_image_t *image); + +typedef enum +{ + PIXMAN_KERNEL_IMPULSE, + PIXMAN_KERNEL_BOX, + PIXMAN_KERNEL_LINEAR, + PIXMAN_KERNEL_CUBIC, + PIXMAN_KERNEL_GAUSSIAN, + PIXMAN_KERNEL_LANCZOS2, + PIXMAN_KERNEL_LANCZOS3, + PIXMAN_KERNEL_LANCZOS3_STRETCHED /* Jim Blinn's 'nice' filter */ +} pixman_kernel_t; + +/* Create the parameter list for a SEPARABLE_CONVOLUTION filter + * with the given kernels and scale parameters. + */ +pixman_fixed_t * +pixman_filter_create_separable_convolution (int *n_values, + pixman_fixed_t scale_x, + pixman_fixed_t scale_y, + pixman_kernel_t reconstruct_x, + pixman_kernel_t reconstruct_y, + pixman_kernel_t sample_x, + pixman_kernel_t sample_y, + int subsample_bits_x, + int subsample_bits_y); + pixman_bool_t pixman_image_fill_rectangles (pixman_op_t op, pixman_image_t *image, const pixman_color_t *color, diff --git a/pixman/pixman/rounding.txt b/pixman/pixman/rounding.txt index 1a19f450f..b52b08439 100644 --- a/pixman/pixman/rounding.txt +++ b/pixman/pixman/rounding.txt @@ -132,3 +132,36 @@ And so the final formula for the index k of x0 in the image is: Computing the result is then simply a matter of convolving all the pixels starting at k with all the samples in the matrix. + + +--- SEPARABLE_CONVOLUTION + +For this filter, x is first rounded to one of n regularly spaced +subpixel positions. This subpixel position determines which of n +convolution matrices is being used. + +Then, as in a regular convolution filter, the first pixel to be used +is determined: + + k = floor (x - (width - 1) / 2.0 - e) + +and then the image pixels starting there are convolved with the chosen +matrix. If we write x = xi + frac, where xi is an integer, we get + + k = xi + floor (frac - (width - 1) / 2.0 - e) + +so the location of k relative to x is given by: + + (k + 0.5 - x) = xi + floor (frac - (width - 1) / 2.0 - e) + 0.5 - x + + = floor (frac - (width - 1) / 2.0 - e) + 0.5 - frac + +which means the contents of the matrix corresponding to (frac) should +contain width samplings of the function, with the first sample at: + + floor (frac - (width - 1) / 2.0 - e) + 0.5 - frac + +This filter is called separable because each of the k x k convolution +matrices is specified with two k-wide vectors, one for each dimension, +where each entry in the matrix is computed as the product of the +corresponding entries in the vectors. diff --git a/pixman/test/Makefile.sources b/pixman/test/Makefile.sources index 077897161..8c0b505df 100644 --- a/pixman/test/Makefile.sources +++ b/pixman/test/Makefile.sources @@ -1,5 +1,6 @@ # Tests (sorted by expected completion time) TESTPROGRAMS = \ + prng-test \ a1-trap-test \ pdf-op-test \ region-test \ @@ -33,8 +34,10 @@ BENCHMARKS = \ # Utility functions libutils_sources = \ utils.c \ + utils-prng.c \ $(NULL) libutils_headers = \ utils.h \ + utils-prng.h \ $(NULL) diff --git a/pixman/test/affine-test.c b/pixman/test/affine-test.c index daa86c81d..f60ec14eb 100644 --- a/pixman/test/affine-test.c +++ b/pixman/test/affine-test.c @@ -48,18 +48,18 @@ test_composite (int testnum, uint32_t crc32; FLOAT_REGS_CORRUPTION_DETECTOR_START (); - lcg_srand (testnum); + prng_srand (testnum); - src_bpp = (lcg_rand_n (2) == 0) ? 2 : 4; - dst_bpp = (lcg_rand_n (2) == 0) ? 2 : 4; - op = (lcg_rand_n (2) == 0) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER; + src_bpp = (prng_rand_n (2) == 0) ? 2 : 4; + dst_bpp = (prng_rand_n (2) == 0) ? 2 : 4; + op = (prng_rand_n (2) == 0) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER; - src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1; - src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1; - dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1; - dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1; - src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp; - dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp; + src_width = prng_rand_n (MAX_SRC_WIDTH) + 1; + src_height = prng_rand_n (MAX_SRC_HEIGHT) + 1; + dst_width = prng_rand_n (MAX_DST_WIDTH) + 1; + dst_height = prng_rand_n (MAX_DST_HEIGHT) + 1; + src_stride = src_width * src_bpp + prng_rand_n (MAX_STRIDE) * src_bpp; + dst_stride = dst_width * dst_bpp + prng_rand_n (MAX_STRIDE) * dst_bpp; if (src_stride & 3) src_stride += 2; @@ -67,26 +67,23 @@ test_composite (int testnum, if (dst_stride & 3) dst_stride += 2; - src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2); - src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2); - dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2); - dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2); - w = lcg_rand_n (dst_width * 3 / 2 - dst_x); - h = lcg_rand_n (dst_height * 3 / 2 - dst_y); + src_x = -(src_width / 4) + prng_rand_n (src_width * 3 / 2); + src_y = -(src_height / 4) + prng_rand_n (src_height * 3 / 2); + dst_x = -(dst_width / 4) + prng_rand_n (dst_width * 3 / 2); + dst_y = -(dst_height / 4) + prng_rand_n (dst_height * 3 / 2); + w = prng_rand_n (dst_width * 3 / 2 - dst_x); + h = prng_rand_n (dst_height * 3 / 2 - dst_y); srcbuf = (uint32_t *)malloc (src_stride * src_height); dstbuf = (uint32_t *)malloc (dst_stride * dst_height); - for (i = 0; i < src_stride * src_height; i++) - *((uint8_t *)srcbuf + i) = lcg_rand_n (256); + prng_randmemset (srcbuf, src_stride * src_height, 0); + prng_randmemset (dstbuf, dst_stride * dst_height, 0); - for (i = 0; i < dst_stride * dst_height; i++) - *((uint8_t *)dstbuf + i) = lcg_rand_n (256); - - src_fmt = src_bpp == 4 ? (lcg_rand_n (2) == 0 ? + src_fmt = src_bpp == 4 ? (prng_rand_n (2) == 0 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5; - dst_fmt = dst_bpp == 4 ? (lcg_rand_n (2) == 0 ? + dst_fmt = dst_bpp == 4 ? (prng_rand_n (2) == 0 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5; src_img = pixman_image_create_bits ( @@ -100,29 +97,29 @@ test_composite (int testnum, pixman_transform_init_identity (&transform); - if (lcg_rand_n (3) > 0) + if (prng_rand_n (3) > 0) { - scale_x = -65536 * 3 + lcg_rand_N (65536 * 6); - if (lcg_rand_n (2)) - scale_y = -65536 * 3 + lcg_rand_N (65536 * 6); + scale_x = -65536 * 3 + prng_rand_n (65536 * 6); + if (prng_rand_n (2)) + scale_y = -65536 * 3 + prng_rand_n (65536 * 6); else scale_y = scale_x; pixman_transform_init_scale (&transform, scale_x, scale_y); } - if (lcg_rand_n (3) > 0) + if (prng_rand_n (3) > 0) { - translate_x = -65536 * 3 + lcg_rand_N (6 * 65536); - if (lcg_rand_n (2)) - translate_y = -65536 * 3 + lcg_rand_N (6 * 65536); + translate_x = -65536 * 3 + prng_rand_n (6 * 65536); + if (prng_rand_n (2)) + translate_y = -65536 * 3 + prng_rand_n (6 * 65536); else translate_y = translate_x; pixman_transform_translate (&transform, NULL, translate_x, translate_y); } - if (lcg_rand_n (4) > 0) + if (prng_rand_n (4) > 0) { int c, s, tx = 0, ty = 0; - switch (lcg_rand_n (4)) + switch (prng_rand_n (4)) { case 0: /* 90 degrees */ @@ -145,32 +142,32 @@ test_composite (int testnum, break; default: /* arbitrary rotation */ - c = lcg_rand_N (2 * 65536) - 65536; - s = lcg_rand_N (2 * 65536) - 65536; + c = prng_rand_n (2 * 65536) - 65536; + s = prng_rand_n (2 * 65536) - 65536; break; } pixman_transform_rotate (&transform, NULL, c, s); pixman_transform_translate (&transform, NULL, tx, ty); } - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { /* Flip random bits */ int maxflipcount = 8; while (maxflipcount--) { - int i = lcg_rand_n (2); - int j = lcg_rand_n (3); - int bitnum = lcg_rand_n (32); + int i = prng_rand_n (2); + int j = prng_rand_n (3); + int bitnum = prng_rand_n (32); transform.matrix[i][j] ^= 1 << bitnum; - if (lcg_rand_n (2)) + if (prng_rand_n (2)) break; } } pixman_image_set_transform (src_img, &transform); - switch (lcg_rand_n (4)) + switch (prng_rand_n (4)) { case 0: repeat = PIXMAN_REPEAT_NONE; @@ -193,7 +190,7 @@ test_composite (int testnum, } pixman_image_set_repeat (src_img, repeat); - if (lcg_rand_n (2)) + if (prng_rand_n (2)) pixman_image_set_filter (src_img, PIXMAN_FILTER_NEAREST, NULL, 0); else pixman_image_set_filter (src_img, PIXMAN_FILTER_BILINEAR, NULL, 0); @@ -220,19 +217,19 @@ test_composite (int testnum, printf ("w=%d, h=%d\n", w, h); } - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[2]; - int n = lcg_rand_n (2) + 1; + int n = prng_rand_n (2) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (src_width); - clip_boxes[i].y1 = lcg_rand_n (src_height); + clip_boxes[i].x1 = prng_rand_n (src_width); + clip_boxes[i].y1 = prng_rand_n (src_height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (src_width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (src_height - clip_boxes[i].y1); if (verbose) { @@ -248,18 +245,18 @@ test_composite (int testnum, pixman_region_fini (&clip); } - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[2]; - int n = lcg_rand_n (2) + 1; + int n = prng_rand_n (2) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (dst_width); - clip_boxes[i].y1 = lcg_rand_n (dst_height); + clip_boxes[i].x1 = prng_rand_n (dst_width); + clip_boxes[i].y1 = prng_rand_n (dst_height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (dst_width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (dst_height - clip_boxes[i].y1); if (verbose) { @@ -310,11 +307,11 @@ test_composite (int testnum, } #if BILINEAR_INTERPOLATION_BITS == 8 -#define CHECKSUM 0x344413F0 +#define CHECKSUM 0x97097336 #elif BILINEAR_INTERPOLATION_BITS == 7 -#define CHECKSUM 0xC8181A76 +#define CHECKSUM 0x31D2DC21 #elif BILINEAR_INTERPOLATION_BITS == 4 -#define CHECKSUM 0xD672A457 +#define CHECKSUM 0x8B925154 #else #define CHECKSUM 0x00000000 #endif diff --git a/pixman/test/alpha-loop.c b/pixman/test/alpha-loop.c index e4d90a988..eca761537 100644 --- a/pixman/test/alpha-loop.c +++ b/pixman/test/alpha-loop.c @@ -8,9 +8,14 @@ int main (int argc, char **argv) { - uint8_t *alpha = make_random_bytes (WIDTH * HEIGHT); - uint32_t *src = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * 4); - uint32_t *dest = (uint32_t *)make_random_bytes (WIDTH * HEIGHT * 4); + uint8_t *alpha; + uint32_t *src, *dest; + + prng_srand (0); + + alpha = make_random_bytes (WIDTH * HEIGHT); + 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); diff --git a/pixman/test/alphamap.c b/pixman/test/alphamap.c index 0c5757ea3..1a6fca55a 100644 --- a/pixman/test/alphamap.c +++ b/pixman/test/alphamap.c @@ -307,6 +307,8 @@ main (int argc, char **argv) { int i, j, a, b, x, y; + prng_srand (0); + for (i = 0; i < ARRAY_LENGTH (formats); ++i) { for (j = 0; j < ARRAY_LENGTH (formats); ++j) diff --git a/pixman/test/blitters-test.c b/pixman/test/blitters-test.c index 30d69124c..9bde99c62 100644 --- a/pixman/test/blitters-test.c +++ b/pixman/test/blitters-test.c @@ -25,7 +25,7 @@ create_random_image (pixman_format_code_t *allowed_formats, int max_extra_stride, pixman_format_code_t *used_fmt) { - int n = 0, i, width, height, stride; + int n = 0, width, height, stride; pixman_format_code_t fmt; uint32_t *buf; pixman_image_t *img; @@ -33,28 +33,20 @@ create_random_image (pixman_format_code_t *allowed_formats, while (allowed_formats[n] != PIXMAN_null) n++; - if (n > N_MOST_LIKELY_FORMATS && lcg_rand_n (4) != 0) + if (n > N_MOST_LIKELY_FORMATS && prng_rand_n (4) != 0) n = N_MOST_LIKELY_FORMATS; - fmt = allowed_formats[lcg_rand_n (n)]; + fmt = allowed_formats[prng_rand_n (n)]; - width = lcg_rand_n (max_width) + 1; - height = lcg_rand_n (max_height) + 1; + width = prng_rand_n (max_width) + 1; + height = prng_rand_n (max_height) + 1; stride = (width * PIXMAN_FORMAT_BPP (fmt) + 7) / 8 + - lcg_rand_n (max_extra_stride + 1); + prng_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); - } + prng_randmemset (buf, stride * height, RANDMEMSET_MORE_00_AND_FF); img = pixman_image_create_bits (fmt, width, height, buf, stride); @@ -67,7 +59,7 @@ create_random_image (pixman_format_code_t *allowed_formats, pixman_image_set_indexed (img, &(y_palette[PIXMAN_FORMAT_BPP (fmt)])); } - if (lcg_rand_n (16) == 0) + if (prng_rand_n (16) == 0) pixman_image_set_filter (img, PIXMAN_FILTER_BILINEAR, NULL, 0); image_endian_swap (img); @@ -251,11 +243,11 @@ test_composite (int testnum, int verbose) if (max_extra_stride > 8) max_extra_stride = 8; - lcg_srand (testnum); + prng_srand (testnum); - op = op_list[lcg_rand_n (ARRAY_LENGTH (op_list))]; + op = op_list[prng_rand_n (ARRAY_LENGTH (op_list))]; - if (lcg_rand_n (8)) + if (prng_rand_n (8)) { /* normal image */ src_img = create_random_image (img_fmt_list, max_width, max_height, @@ -284,10 +276,10 @@ test_composite (int testnum, int verbose) 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); + src_x = prng_rand_n (src_width); + src_y = prng_rand_n (src_height); + dst_x = prng_rand_n (dst_width); + dst_y = prng_rand_n (dst_height); mask_img = NULL; mask_fmt = PIXMAN_null; @@ -296,10 +288,10 @@ test_composite (int testnum, int verbose) maskbuf = NULL; if ((src_fmt == PIXMAN_x8r8g8b8 || src_fmt == PIXMAN_x8b8g8r8) && - (lcg_rand_n (4) == 0)) + (prng_rand_n (4) == 0)) { /* PIXBUF */ - mask_fmt = lcg_rand_n (2) ? PIXMAN_a8r8g8b8 : PIXMAN_a8b8g8r8; + mask_fmt = prng_rand_n (2) ? PIXMAN_a8r8g8b8 : PIXMAN_a8b8g8r8; mask_img = pixman_image_create_bits (mask_fmt, src_width, src_height, @@ -309,9 +301,9 @@ test_composite (int testnum, int verbose) mask_y = src_y; maskbuf = srcbuf; } - else if (lcg_rand_n (2)) + else if (prng_rand_n (2)) { - if (lcg_rand_n (2)) + if (prng_rand_n (2)) { mask_img = create_random_image (mask_fmt_list, max_width, max_height, max_extra_stride, &mask_fmt); @@ -324,16 +316,16 @@ test_composite (int testnum, int verbose) pixman_image_set_repeat (mask_img, PIXMAN_REPEAT_NORMAL); } - if (lcg_rand_n (2)) + if (prng_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)); + mask_x = prng_rand_n (pixman_image_get_width (mask_img)); + mask_y = prng_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); + w = prng_rand_n (dst_width - dst_x + 1); + h = prng_rand_n (dst_height - dst_y + 1); if (verbose) { @@ -390,6 +382,8 @@ main (int argc, const char *argv[]) { int i; + prng_srand (0); + for (i = 1; i <= 8; i++) { initialize_palette (&(rgb_palette[i]), i, TRUE); @@ -397,6 +391,6 @@ main (int argc, const char *argv[]) } return fuzzer_test_main("blitters", 2000000, - 0x46136E0A, + 0xD8265D5E, test_composite, argc, argv); } diff --git a/pixman/test/combiner-test.c b/pixman/test/combiner-test.c index c438ae62e..01f63a56e 100644 --- a/pixman/test/combiner-test.c +++ b/pixman/test/combiner-test.c @@ -67,7 +67,7 @@ static const pixman_op_t op_list[] = static float rand_float (void) { - uint32_t u = lcg_rand_u32(); + uint32_t u = prng_rand(); return *(float *)&u; } @@ -123,7 +123,7 @@ main () impl = _pixman_internal_only_get_implementation(); - lcg_srand (0); + prng_srand (0); for (i = 0; i < ARRAY_LENGTH (op_list); ++i) { diff --git a/pixman/test/composite-traps-test.c b/pixman/test/composite-traps-test.c index 9fc94a4d6..2983eae83 100644 --- a/pixman/test/composite-traps-test.c +++ b/pixman/test/composite-traps-test.c @@ -26,7 +26,7 @@ static pixman_op_t operators[] = }; #define RANDOM_ELT(array) \ - ((array)[lcg_rand_n(ARRAY_LENGTH((array)))]) + ((array)[prng_rand_n(ARRAY_LENGTH((array)))]) static void destroy_bits (pixman_image_t *image, void *data) @@ -37,7 +37,7 @@ destroy_bits (pixman_image_t *image, void *data) static pixman_fixed_t random_fixed (int n) { - return lcg_rand_N (n << 16); + return prng_rand_n (n << 16); } /* @@ -75,17 +75,17 @@ test_composite (int testnum, FLOAT_REGS_CORRUPTION_DETECTOR_START (); - lcg_srand (testnum); + prng_srand (testnum); op = RANDOM_ELT (operators); mask_format = RANDOM_ELT (mask_formats); /* Create source image */ - if (lcg_rand_n (4) == 0) + if (prng_rand_n (4) == 0) { src_img = pixman_image_create_solid_fill ( - &(colors[lcg_rand_n (ARRAY_LENGTH (colors))])); + &(colors[prng_rand_n (ARRAY_LENGTH (colors))])); src_x = 10; src_y = 234; @@ -94,13 +94,13 @@ test_composite (int testnum, { pixman_format_code_t src_format = RANDOM_ELT(formats); int src_bpp = (PIXMAN_FORMAT_BPP (src_format) + 7) / 8; - int src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1; - int src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1; - int src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp; + int src_width = prng_rand_n (MAX_SRC_WIDTH) + 1; + int src_height = prng_rand_n (MAX_SRC_HEIGHT) + 1; + int src_stride = src_width * src_bpp + prng_rand_n (MAX_STRIDE) * src_bpp; uint32_t *bits; - src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2); - src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2); + src_x = -(src_width / 4) + prng_rand_n (src_width * 3 / 2); + src_y = -(src_height / 4) + prng_rand_n (src_height * 3 / 2); src_stride = (src_stride + 3) & ~3; @@ -111,19 +111,19 @@ test_composite (int testnum, pixman_image_set_destroy_function (src_img, destroy_bits, bits); - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[2]; - int n = lcg_rand_n (2) + 1; + int n = prng_rand_n (2) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (src_width); - clip_boxes[i].y1 = lcg_rand_n (src_height); + clip_boxes[i].x1 = prng_rand_n (src_width); + clip_boxes[i].y1 = prng_rand_n (src_height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (src_width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (src_height - clip_boxes[i].y1); if (verbose) { @@ -146,15 +146,15 @@ test_composite (int testnum, { dst_format = RANDOM_ELT(formats); dst_bpp = (PIXMAN_FORMAT_BPP (dst_format) + 7) / 8; - dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1; - dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1; - dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp; + dst_width = prng_rand_n (MAX_DST_WIDTH) + 1; + dst_height = prng_rand_n (MAX_DST_HEIGHT) + 1; + dst_stride = dst_width * dst_bpp + prng_rand_n (MAX_STRIDE) * dst_bpp; dst_stride = (dst_stride + 3) & ~3; dst_bits = (uint32_t *)make_random_bytes (dst_stride * dst_height); - dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2); - dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2); + dst_x = -(dst_width / 4) + prng_rand_n (dst_width * 3 / 2); + dst_y = -(dst_height / 4) + prng_rand_n (dst_height * 3 / 2); dst_img = pixman_image_create_bits ( dst_format, dst_width, dst_height, dst_bits, dst_stride); @@ -166,7 +166,7 @@ test_composite (int testnum, { int i; - n_traps = lcg_rand_n (25); + n_traps = prng_rand_n (25); traps = fence_malloc (n_traps * sizeof (pixman_trapezoid_t)); for (i = 0; i < n_traps; ++i) @@ -186,18 +186,18 @@ test_composite (int testnum, } } - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[2]; - int n = lcg_rand_n (2) + 1; + int n = prng_rand_n (2) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (dst_width); - clip_boxes[i].y1 = lcg_rand_n (dst_height); + clip_boxes[i].x1 = prng_rand_n (dst_width); + clip_boxes[i].y1 = prng_rand_n (dst_height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (dst_width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (dst_height - clip_boxes[i].y1); if (verbose) { @@ -251,6 +251,6 @@ test_composite (int testnum, int main (int argc, const char *argv[]) { - return fuzzer_test_main("composite traps", 40000, 0x33BFAA55, + return fuzzer_test_main("composite traps", 40000, 0x749BCC57, test_composite, argc, argv); } diff --git a/pixman/test/composite.c b/pixman/test/composite.c index 2930fb75b..09752c5c7 100644 --- a/pixman/test/composite.c +++ b/pixman/test/composite.c @@ -725,19 +725,19 @@ image_fini (image_t *info) static int random_size (void) { - return lcg_rand_n (ARRAY_LENGTH (sizes)); + return prng_rand_n (ARRAY_LENGTH (sizes)); } static int random_color (void) { - return lcg_rand_n (ARRAY_LENGTH (colors)); + return prng_rand_n (ARRAY_LENGTH (colors)); } static int random_format (void) { - return lcg_rand_n (ARRAY_LENGTH (formats)); + return prng_rand_n (ARRAY_LENGTH (formats)); } static pixman_bool_t @@ -748,15 +748,15 @@ run_test (uint32_t seed) int ca; int ok; - lcg_srand (seed); + prng_srand (seed); image_init (&dst, random_color(), random_format(), 1); image_init (&src, random_color(), random_format(), random_size()); image_init (&mask, random_color(), random_format(), random_size()); - op = &(operators [lcg_rand_n (ARRAY_LENGTH (operators))]); + op = &(operators [prng_rand_n (ARRAY_LENGTH (operators))]); - ca = lcg_rand_n (3); + ca = prng_rand_n (3); switch (ca) { diff --git a/pixman/test/glyph-test.c b/pixman/test/glyph-test.c index 501cc2e6f..1811add73 100644 --- a/pixman/test/glyph-test.c +++ b/pixman/test/glyph-test.c @@ -107,7 +107,7 @@ random_format (const pixman_format_code_t *formats) i = 0; while (formats[i] != PIXMAN_null) ++i; - return formats[lcg_rand_n (i)]; + return formats[prng_rand_n (i)]; } static pixman_image_t * @@ -122,27 +122,27 @@ create_image (int max_size, const pixman_format_code_t *formats, uint32_t flags) int i; pixman_image_destroy_func_t destroy; - if ((flags & ALLOW_SOLID) && lcg_rand_n (4) == 0) + if ((flags & ALLOW_SOLID) && prng_rand_n (4) == 0) { pixman_color_t color; - color.alpha = lcg_rand_u32(); - color.red = lcg_rand_u32(); - color.green = lcg_rand_u32(); - color.blue = lcg_rand_u32(); + color.alpha = prng_rand(); + color.red = prng_rand(); + color.green = prng_rand(); + color.blue = prng_rand(); return pixman_image_create_solid_fill (&color); } - width = lcg_rand_n (max_size) + 1; - height = lcg_rand_n (max_size) + 1; + width = prng_rand_n (max_size) + 1; + height = prng_rand_n (max_size) + 1; format = random_format (formats); bpp = PIXMAN_FORMAT_BPP (format); - stride = (width * bpp + 7) / 8 + lcg_rand_n (17); + stride = (width * bpp + 7) / 8 + prng_rand_n (17); stride = (stride + 3) & ~3; - if (lcg_rand_n (64) == 0) + if (prng_rand_n (64) == 0) { if (!(data = (uint32_t *)make_random_bytes (stride * height))) { @@ -153,34 +153,28 @@ create_image (int max_size, const pixman_format_code_t *formats, uint32_t flags) } else { - uint8_t *d8; - data = malloc (stride * height); - - d8 = (uint8_t *)data; - for (i = 0; i < height * stride; ++i) - d8[i] = lcg_rand_n (256); - + prng_randmemset (data, height * stride, 0); destroy = destroy_malloced; } image = pixman_image_create_bits (format, width, height, data, stride); pixman_image_set_destroy_function (image, destroy, data); - if ((flags & ALLOW_CLIPPED) && lcg_rand_n (8) == 0) + if ((flags & ALLOW_CLIPPED) && prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[8]; pixman_region16_t clip; - int n = lcg_rand_n (8) + 1; + int n = prng_rand_n (8) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (width); - clip_boxes[i].y1 = lcg_rand_n (height); + clip_boxes[i].x1 = prng_rand_n (width); + clip_boxes[i].y1 = prng_rand_n (height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (height - clip_boxes[i].y1); } pixman_region_init_rects (&clip, clip_boxes, n); @@ -188,27 +182,27 @@ create_image (int max_size, const pixman_format_code_t *formats, uint32_t flags) pixman_region_fini (&clip); } - if ((flags & ALLOW_SOURCE_CLIPPING) && lcg_rand_n (4) == 0) + if ((flags & ALLOW_SOURCE_CLIPPING) && prng_rand_n (4) == 0) { pixman_image_set_source_clipping (image, TRUE); pixman_image_set_has_client_clip (image, TRUE); } - if ((flags & ALLOW_ALPHA_MAP) && lcg_rand_n (16) == 0) + if ((flags & ALLOW_ALPHA_MAP) && prng_rand_n (16) == 0) { pixman_image_t *alpha_map; int alpha_x, alpha_y; - alpha_x = lcg_rand_n (width); - alpha_y = lcg_rand_n (height); + alpha_x = prng_rand_n (width); + alpha_y = prng_rand_n (height); alpha_map = create_image (max_size, formats, (flags & ~(ALLOW_ALPHA_MAP | ALLOW_SOLID))); pixman_image_set_alpha_map (image, alpha_map, alpha_x, alpha_y); pixman_image_unref (alpha_map); } - if ((flags & ALLOW_REPEAT) && lcg_rand_n (2) == 0) - pixman_image_set_repeat (image, lcg_rand_n (4)); + if ((flags & ALLOW_REPEAT) && prng_rand_n (2) == 0) + pixman_image_set_repeat (image, prng_rand_n (4)); image_endian_swap (image); @@ -230,7 +224,7 @@ test_glyphs (int testnum, int verbose) int n_glyphs, i; pixman_glyph_cache_t *cache; - lcg_srand (testnum); + prng_srand (testnum); cache = pixman_glyph_cache_create (); @@ -245,13 +239,13 @@ test_glyphs (int testnum, int verbose) pixman_glyph_cache_freeze (cache); - n_glyphs = lcg_rand_n (MAX_GLYPHS); + n_glyphs = prng_rand_n (MAX_GLYPHS); for (i = 0; i < n_glyphs; ++i) glyph_images[i] = create_image (32, glyph_formats, 0); for (i = 0; i < 4 * n_glyphs; ++i) { - int g = lcg_rand_n (n_glyphs); + int g = prng_rand_n (n_glyphs); pixman_image_t *glyph_img = glyph_images[g]; void *key1 = KEY1 (glyph_img); void *key2 = KEY2 (glyph_img); @@ -264,21 +258,21 @@ test_glyphs (int testnum, int verbose) } glyphs[i].glyph = glyph; - glyphs[i].x = lcg_rand_n (128); - glyphs[i].y = lcg_rand_n (128); + glyphs[i].x = prng_rand_n (128); + glyphs[i].y = prng_rand_n (128); } - if (lcg_rand_n (2) == 0) + if (prng_rand_n (2) == 0) { - int src_x = lcg_rand_n (300) - 150; - int src_y = lcg_rand_n (300) - 150; - int mask_x = lcg_rand_n (64) - 32; - int mask_y = lcg_rand_n (64) - 32; - int dest_x = lcg_rand_n (64) - 32; - int dest_y = lcg_rand_n (64) - 32; - int width = lcg_rand_n (64); - int height = lcg_rand_n (64); - pixman_op_t op = operators[lcg_rand_n (ARRAY_LENGTH (operators))]; + int src_x = prng_rand_n (300) - 150; + int src_y = prng_rand_n (300) - 150; + int mask_x = prng_rand_n (64) - 32; + int mask_y = prng_rand_n (64) - 32; + int dest_x = prng_rand_n (64) - 32; + int dest_y = prng_rand_n (64) - 32; + int width = prng_rand_n (64); + int height = prng_rand_n (64); + pixman_op_t op = operators[prng_rand_n (ARRAY_LENGTH (operators))]; pixman_format_code_t format = random_format (glyph_formats); pixman_composite_glyphs ( @@ -292,11 +286,11 @@ test_glyphs (int testnum, int verbose) } else { - pixman_op_t op = operators[lcg_rand_n (ARRAY_LENGTH (operators))]; - int src_x = lcg_rand_n (300) - 150; - int src_y = lcg_rand_n (300) - 150; - int dest_x = lcg_rand_n (64) - 32; - int dest_y = lcg_rand_n (64) - 32; + pixman_op_t op = operators[prng_rand_n (ARRAY_LENGTH (operators))]; + int src_x = prng_rand_n (300) - 150; + int src_y = prng_rand_n (300) - 150; + int dest_x = prng_rand_n (64) - 32; + int dest_y = prng_rand_n (64) - 32; pixman_composite_glyphs_no_mask ( op, source, dest, @@ -333,6 +327,6 @@ int main (int argc, const char *argv[]) { return fuzzer_test_main ("glyph", 30000, - 0x79E74996, + 0xFA478A79, test_glyphs, argc, argv); } diff --git a/pixman/test/prng-test.c b/pixman/test/prng-test.c new file mode 100644 index 000000000..0a3ad5e8f --- /dev/null +++ b/pixman/test/prng-test.c @@ -0,0 +1,172 @@ +/* + * Copyright © 2012 Siarhei Siamashka <siarhei.siamashka@gmail.com> + * + * Based on the public domain implementation of small noncryptographic PRNG + * authored by Bob Jenkins: http://burtleburtle.net/bob/rand/smallprng.html + * + * 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. + */ + +#include <assert.h> +#include <stdlib.h> +#include "utils-prng.h" +#include "utils.h" + +/* The original code from http://www.burtleburtle.net/bob/rand/smallprng.html */ + +typedef uint32_t u4; +typedef struct ranctx { u4 a; u4 b; u4 c; u4 d; } ranctx; + +#define rot(x,k) (((x)<<(k))|((x)>>(32-(k)))) +u4 ranval( ranctx *x ) { + u4 e = x->a - rot(x->b, 27); + x->a = x->b ^ rot(x->c, 17); + x->b = x->c + x->d; + x->c = x->d + e; + x->d = e + x->a; + return x->d; +} + +void raninit( ranctx *x, u4 seed ) { + u4 i; + x->a = 0xf1ea5eed, x->b = x->c = x->d = seed; + for (i=0; i<20; ++i) { + (void)ranval(x); + } +} + +/*****************************************************************************/ + +#define BUFSIZE (8 * 1024 * 1024) +#define N 50 + +void bench (void) +{ + double t1, t2; + int i; + prng_t prng; + uint8_t *buf = aligned_malloc (16, BUFSIZE + 1); + + prng_srand_r (&prng, 1234); + t1 = gettime(); + for (i = 0; i < N; i++) + prng_randmemset_r (&prng, buf, BUFSIZE, 0); + t2 = gettime(); + printf ("aligned randmemset : %.2f MB/s\n", + (double)BUFSIZE * N / 1000000. / (t2 - t1)); + + t1 = gettime(); + for (i = 0; i < N; i++) + prng_randmemset_r (&prng, buf + 1, BUFSIZE, 0); + t2 = gettime(); + printf ("unaligned randmemset : %.2f MB/s\n", + (double)BUFSIZE * N / 1000000. / (t2 - t1)); + + t1 = gettime(); + for (i = 0; i < N; i++) + { + prng_randmemset_r (&prng, buf, BUFSIZE, RANDMEMSET_MORE_00_AND_FF); + } + t2 = gettime (); + printf ("aligned randmemset (more 00 and FF) : %.2f MB/s\n", + (double)BUFSIZE * N / 1000000. / (t2 - t1)); + + t1 = gettime(); + for (i = 0; i < N; i++) + { + prng_randmemset_r (&prng, buf + 1, BUFSIZE, RANDMEMSET_MORE_00_AND_FF); + } + t2 = gettime (); + printf ("unaligned randmemset (more 00 and FF) : %.2f MB/s\n", + (double)BUFSIZE * N / 1000000. / (t2 - t1)); + + free (buf); +} + +#define SMALLBUFSIZE 100 + +int main (int argc, char *argv[]) +{ + const uint32_t ref_crc[RANDMEMSET_MORE_00_AND_FF + 1] = + { + 0xBA06763D, 0x103FC550, 0x8B59ABA5, 0xD82A0F39 + }; + uint32_t crc1, crc2; + uint32_t ref, seed, seed0, seed1, seed2, seed3; + prng_rand_128_data_t buf; + uint8_t *bytebuf = aligned_malloc(16, SMALLBUFSIZE + 1); + ranctx x; + prng_t prng; + prng_randmemset_flags_t flags; + + if (argc > 1 && strcmp(argv[1], "-bench") == 0) + { + bench (); + return 0; + } + + /* basic test */ + raninit (&x, 0); + prng_srand_r (&prng, 0); + assert (ranval (&x) == prng_rand_r (&prng)); + + /* test for simd code */ + seed = 0; + prng_srand_r (&prng, seed); + seed0 = (seed = seed * 1103515245 + 12345); + seed1 = (seed = seed * 1103515245 + 12345); + seed2 = (seed = seed * 1103515245 + 12345); + seed3 = (seed = seed * 1103515245 + 12345); + prng_rand_128_r (&prng, &buf); + + raninit (&x, seed0); + ref = ranval (&x); + assert (ref == buf.w[0]); + + raninit (&x, seed1); + ref = ranval (&x); + assert (ref == buf.w[1]); + + raninit (&x, seed2); + ref = ranval (&x); + assert (ref == buf.w[2]); + + raninit (&x, seed3); + ref = ranval (&x); + assert (ref == buf.w[3]); + + /* test for randmemset */ + for (flags = 0; flags <= RANDMEMSET_MORE_00_AND_FF; flags++) + { + prng_srand_r (&prng, 1234); + prng_randmemset_r (&prng, bytebuf, 16, flags); + prng_randmemset_r (&prng, bytebuf + 16, SMALLBUFSIZE - 17, flags); + crc1 = compute_crc32 (0, bytebuf, SMALLBUFSIZE - 1); + prng_srand_r (&prng, 1234); + prng_randmemset_r (&prng, bytebuf + 1, SMALLBUFSIZE - 1, flags); + crc2 = compute_crc32 (0, bytebuf + 1, SMALLBUFSIZE - 1); + assert (ref_crc[flags] == crc1); + assert (ref_crc[flags] == crc2); + } + + free (bytebuf); + + return 0; +} diff --git a/pixman/test/region-contains-test.c b/pixman/test/region-contains-test.c index 9524e2888..096e65179 100644 --- a/pixman/test/region-contains-test.c +++ b/pixman/test/region-contains-test.c @@ -9,16 +9,16 @@ make_random_region (pixman_region32_t *region) pixman_region32_init (region); - n_boxes = lcg_rand_n (64); + n_boxes = prng_rand_n (64); while (n_boxes--) { int32_t x, y; uint32_t w, h; - x = (int32_t)lcg_rand_u32() >> 2; - y = (int32_t)lcg_rand_u32() >> 2; - w = lcg_rand_u32() >> 2; - h = lcg_rand_u32() >> 2; + x = (int32_t)prng_rand() >> 2; + y = (int32_t)prng_rand() >> 2; + w = prng_rand() >> 2; + h = prng_rand() >> 2; pixman_region32_union_rect (region, region, x, y, w, h); } @@ -37,12 +37,12 @@ random_coord (pixman_region32_t *region, pixman_bool_t x) int n_boxes; int begin, end; - if (lcg_rand_n (14)) + if (prng_rand_n (14)) { bb = pixman_region32_rectangles (region, &n_boxes); if (n_boxes == 0) goto use_extent; - b = bb + lcg_rand_n (n_boxes); + b = bb + prng_rand_n (n_boxes); } else { @@ -62,12 +62,12 @@ random_coord (pixman_region32_t *region, pixman_bool_t x) end = b->y2; } - switch (lcg_rand_n (5)) + switch (prng_rand_n (5)) { case 0: - return begin - lcg_rand_u32(); + return begin - prng_rand(); case 1: - return end + lcg_rand_u32 (); + return end + prng_rand (); case 2: return end; case 3: @@ -111,14 +111,14 @@ test_region_contains_rectangle (int i, int verbose) pixman_region32_t region; uint32_t r, r1, r2, r3, r4, crc32; - lcg_srand (i); + prng_srand (i); make_random_region (®ion); box.x1 = random_coord (®ion, TRUE); - box.x2 = box.x1 + lcg_rand_u32 (); + box.x2 = box.x1 + prng_rand (); box.y1 = random_coord (®ion, FALSE); - box.y2 = box.y1 + lcg_rand_u32 (); + box.y2 = box.y1 + prng_rand (); if (verbose) { @@ -163,7 +163,7 @@ main (int argc, const char *argv[]) { return fuzzer_test_main ("region_contains", 1000000, - 0xD2BF8C73, + 0x548E0F3F, test_region_contains_rectangle, argc, argv); } diff --git a/pixman/test/region-test.c b/pixman/test/region-test.c index 9d5a41eb9..bfc219bc7 100644 --- a/pixman/test/region-test.c +++ b/pixman/test/region-test.c @@ -32,6 +32,8 @@ main () 0xffff }; + prng_srand (0); + /* This used to go into an infinite loop before pixman-region.c * was fixed to not use explict "short" variables */ @@ -91,10 +93,10 @@ main () /* Add some random rectangles */ for (j = 0; j < 64; j++) pixman_region32_union_rect (&r1, &r1, - lcg_rand_n (image_size), - lcg_rand_n (image_size), - lcg_rand_n (25), - lcg_rand_n (25)); + prng_rand_n (image_size), + prng_rand_n (image_size), + prng_rand_n (25), + prng_rand_n (25)); /* Clip to image size */ pixman_region32_init_rect (&r2, 0, 0, image_size, image_size); diff --git a/pixman/test/rotate-test.c b/pixman/test/rotate-test.c index a0488ef22..9d2a620cb 100644 --- a/pixman/test/rotate-test.c +++ b/pixman/test/rotate-test.c @@ -43,13 +43,13 @@ static const pixman_transform_t transforms[] = }; #define RANDOM_FORMAT() \ - (formats[lcg_rand_n (ARRAY_LENGTH (formats))]) + (formats[prng_rand_n (ARRAY_LENGTH (formats))]) #define RANDOM_OP() \ - (ops[lcg_rand_n (ARRAY_LENGTH (ops))]) + (ops[prng_rand_n (ARRAY_LENGTH (ops))]) #define RANDOM_TRANSFORM() \ - (&(transforms[lcg_rand_n (ARRAY_LENGTH (transforms))])) + (&(transforms[prng_rand_n (ARRAY_LENGTH (transforms))])) static void on_destroy (pixman_image_t *image, void *data) @@ -63,10 +63,8 @@ make_image (void) pixman_format_code_t format = RANDOM_FORMAT(); uint32_t *bytes = malloc (WIDTH * HEIGHT * 4); pixman_image_t *image; - int i; - for (i = 0; i < WIDTH * HEIGHT * 4; ++i) - ((uint8_t *)bytes)[i] = lcg_rand_n (256); + prng_randmemset (bytes, WIDTH * HEIGHT * 4, 0); image = pixman_image_create_bits ( format, WIDTH, HEIGHT, bytes, WIDTH * 4); @@ -86,7 +84,7 @@ test_transform (int testnum, int verbose) pixman_image_t *src, *dest; uint32_t crc; - lcg_srand (testnum); + prng_srand (testnum); src = make_image (); dest = make_image (); @@ -108,6 +106,6 @@ int main (int argc, const char *argv[]) { return fuzzer_test_main ("rotate", 15000, - 0x5236FD9F, + 0xECF5E426, test_transform, argc, argv); } diff --git a/pixman/test/scaling-helpers-test.c b/pixman/test/scaling-helpers-test.c index 33ec47c85..cd5ace0b2 100644 --- a/pixman/test/scaling-helpers-test.c +++ b/pixman/test/scaling-helpers-test.c @@ -52,14 +52,15 @@ int main (void) { int i; + prng_srand (0); for (i = 0; i < 10000; i++) { int32_t left_pad1, left_tz1, width1, right_tz1, right_pad1; int32_t left_pad2, left_tz2, width2, right_tz2, right_pad2; - pixman_fixed_t vx = lcg_rand_N(10000 << 16) - (3000 << 16); - int32_t width = lcg_rand_N(10000); - int32_t source_image_width = lcg_rand_N(10000) + 1; - pixman_fixed_t unit_x = lcg_rand_N(10 << 16) + 1; + pixman_fixed_t vx = prng_rand_n(10000 << 16) - (3000 << 16); + int32_t width = prng_rand_n(10000); + int32_t source_image_width = prng_rand_n(10000) + 1; + pixman_fixed_t unit_x = prng_rand_n(10 << 16) + 1; width1 = width2 = width; bilinear_pad_repeat_get_scanline_bounds_ref (source_image_width, diff --git a/pixman/test/scaling-test.c b/pixman/test/scaling-test.c index 035410333..64c12dd7c 100644 --- a/pixman/test/scaling-test.c +++ b/pixman/test/scaling-test.c @@ -26,7 +26,7 @@ get_format (int bpp) { if (bpp == 4) { - switch (lcg_rand_n (4)) + switch (prng_rand_n (4)) { default: case 0: @@ -80,11 +80,11 @@ test_composite (int testnum, uint32_t crc32; FLOAT_REGS_CORRUPTION_DETECTOR_START (); - lcg_srand (testnum); + prng_srand (testnum); - src_bpp = (lcg_rand_n (2) == 0) ? 2 : 4; - dst_bpp = (lcg_rand_n (2) == 0) ? 2 : 4; - switch (lcg_rand_n (3)) + src_bpp = (prng_rand_n (2) == 0) ? 2 : 4; + dst_bpp = (prng_rand_n (2) == 0) ? 2 : 4; + switch (prng_rand_n (3)) { case 0: op = PIXMAN_OP_SRC; @@ -97,24 +97,24 @@ test_composite (int testnum, break; } - src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1; - src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1; + src_width = prng_rand_n (MAX_SRC_WIDTH) + 1; + src_height = prng_rand_n (MAX_SRC_HEIGHT) + 1; - if (lcg_rand_n (2)) + if (prng_rand_n (2)) { - mask_width = lcg_rand_n (MAX_SRC_WIDTH) + 1; - mask_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1; + mask_width = prng_rand_n (MAX_SRC_WIDTH) + 1; + mask_height = prng_rand_n (MAX_SRC_HEIGHT) + 1; } else { mask_width = mask_height = 1; } - dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1; - dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1; - src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp; - mask_stride = mask_width * mask_bpp + lcg_rand_n (MAX_STRIDE) * mask_bpp; - dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp; + dst_width = prng_rand_n (MAX_DST_WIDTH) + 1; + dst_height = prng_rand_n (MAX_DST_HEIGHT) + 1; + src_stride = src_width * src_bpp + prng_rand_n (MAX_STRIDE) * src_bpp; + mask_stride = mask_width * mask_bpp + prng_rand_n (MAX_STRIDE) * mask_bpp; + dst_stride = dst_width * dst_bpp + prng_rand_n (MAX_STRIDE) * dst_bpp; if (src_stride & 3) src_stride += 2; @@ -127,27 +127,22 @@ test_composite (int testnum, if (dst_stride & 3) dst_stride += 2; - src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2); - src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2); - mask_x = -(mask_width / 4) + lcg_rand_n (mask_width * 3 / 2); - mask_y = -(mask_height / 4) + lcg_rand_n (mask_height * 3 / 2); - dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2); - dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2); - w = lcg_rand_n (dst_width * 3 / 2 - dst_x); - h = lcg_rand_n (dst_height * 3 / 2 - dst_y); + src_x = -(src_width / 4) + prng_rand_n (src_width * 3 / 2); + src_y = -(src_height / 4) + prng_rand_n (src_height * 3 / 2); + mask_x = -(mask_width / 4) + prng_rand_n (mask_width * 3 / 2); + mask_y = -(mask_height / 4) + prng_rand_n (mask_height * 3 / 2); + dst_x = -(dst_width / 4) + prng_rand_n (dst_width * 3 / 2); + dst_y = -(dst_height / 4) + prng_rand_n (dst_height * 3 / 2); + w = prng_rand_n (dst_width * 3 / 2 - dst_x); + h = prng_rand_n (dst_height * 3 / 2 - dst_y); srcbuf = (uint32_t *)malloc (src_stride * src_height); maskbuf = (uint32_t *)malloc (mask_stride * mask_height); dstbuf = (uint32_t *)malloc (dst_stride * dst_height); - for (i = 0; i < src_stride * src_height; i++) - *((uint8_t *)srcbuf + i) = lcg_rand_n (256); - - for (i = 0; i < mask_stride * mask_height; i++) - *((uint8_t *)maskbuf + i) = lcg_rand_n (256); - - for (i = 0; i < dst_stride * dst_height; i++) - *((uint8_t *)dstbuf + i) = lcg_rand_n (256); + prng_randmemset (srcbuf, src_stride * src_height, 0); + prng_randmemset (maskbuf, mask_stride * mask_height, 0); + prng_randmemset (dstbuf, dst_stride * dst_height, 0); src_fmt = get_format (src_bpp); dst_fmt = get_format (dst_bpp); @@ -164,29 +159,29 @@ test_composite (int testnum, image_endian_swap (src_img); image_endian_swap (dst_img); - if (lcg_rand_n (4) > 0) + if (prng_rand_n (4) > 0) { - scale_x = -32768 * 3 + lcg_rand_N (65536 * 5); - scale_y = -32768 * 3 + lcg_rand_N (65536 * 5); - translate_x = lcg_rand_N (65536); - translate_y = lcg_rand_N (65536); + scale_x = -32768 * 3 + prng_rand_n (65536 * 5); + scale_y = -32768 * 3 + prng_rand_n (65536 * 5); + translate_x = prng_rand_n (65536); + translate_y = prng_rand_n (65536); pixman_transform_init_scale (&transform, scale_x, scale_y); pixman_transform_translate (&transform, NULL, translate_x, translate_y); pixman_image_set_transform (src_img, &transform); } - if (lcg_rand_n (2) > 0) + if (prng_rand_n (2) > 0) { - mask_scale_x = -32768 * 3 + lcg_rand_N (65536 * 5); - mask_scale_y = -32768 * 3 + lcg_rand_N (65536 * 5); - mask_translate_x = lcg_rand_N (65536); - mask_translate_y = lcg_rand_N (65536); + mask_scale_x = -32768 * 3 + prng_rand_n (65536 * 5); + mask_scale_y = -32768 * 3 + prng_rand_n (65536 * 5); + mask_translate_x = prng_rand_n (65536); + mask_translate_y = prng_rand_n (65536); pixman_transform_init_scale (&transform, mask_scale_x, mask_scale_y); pixman_transform_translate (&transform, NULL, mask_translate_x, mask_translate_y); pixman_image_set_transform (mask_img, &transform); } - switch (lcg_rand_n (4)) + switch (prng_rand_n (4)) { case 0: mask_repeat = PIXMAN_REPEAT_NONE; @@ -209,7 +204,7 @@ test_composite (int testnum, } pixman_image_set_repeat (mask_img, mask_repeat); - switch (lcg_rand_n (4)) + switch (prng_rand_n (4)) { case 0: repeat = PIXMAN_REPEAT_NONE; @@ -232,12 +227,12 @@ test_composite (int testnum, } pixman_image_set_repeat (src_img, repeat); - if (lcg_rand_n (2)) + if (prng_rand_n (2)) pixman_image_set_filter (src_img, PIXMAN_FILTER_NEAREST, NULL, 0); else pixman_image_set_filter (src_img, PIXMAN_FILTER_BILINEAR, NULL, 0); - if (lcg_rand_n (2)) + if (prng_rand_n (2)) pixman_image_set_filter (mask_img, PIXMAN_FILTER_NEAREST, NULL, 0); else pixman_image_set_filter (mask_img, PIXMAN_FILTER_BILINEAR, NULL, 0); @@ -256,19 +251,19 @@ test_composite (int testnum, printf ("w=%d, h=%d\n", w, h); } - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[2]; - int n = lcg_rand_n (2) + 1; + int n = prng_rand_n (2) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (src_width); - clip_boxes[i].y1 = lcg_rand_n (src_height); + clip_boxes[i].x1 = prng_rand_n (src_width); + clip_boxes[i].y1 = prng_rand_n (src_height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (src_width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (src_height - clip_boxes[i].y1); if (verbose) { @@ -284,19 +279,19 @@ test_composite (int testnum, pixman_region_fini (&clip); } - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[2]; - int n = lcg_rand_n (2) + 1; + int n = prng_rand_n (2) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (mask_width); - clip_boxes[i].y1 = lcg_rand_n (mask_height); + clip_boxes[i].x1 = prng_rand_n (mask_width); + clip_boxes[i].y1 = prng_rand_n (mask_height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (mask_width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (mask_width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (mask_height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (mask_height - clip_boxes[i].y1); if (verbose) { @@ -312,18 +307,18 @@ test_composite (int testnum, pixman_region_fini (&clip); } - if (lcg_rand_n (8) == 0) + if (prng_rand_n (8) == 0) { pixman_box16_t clip_boxes[2]; - int n = lcg_rand_n (2) + 1; + int n = prng_rand_n (2) + 1; for (i = 0; i < n; i++) { - clip_boxes[i].x1 = lcg_rand_n (dst_width); - clip_boxes[i].y1 = lcg_rand_n (dst_height); + clip_boxes[i].x1 = prng_rand_n (dst_width); + clip_boxes[i].y1 = prng_rand_n (dst_height); clip_boxes[i].x2 = - clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1); + clip_boxes[i].x1 + prng_rand_n (dst_width - clip_boxes[i].x1); clip_boxes[i].y2 = - clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1); + clip_boxes[i].y1 + prng_rand_n (dst_height - clip_boxes[i].y1); if (verbose) { @@ -337,7 +332,7 @@ test_composite (int testnum, pixman_region_fini (&clip); } - if (lcg_rand_n (2) == 0) + if (prng_rand_n (2) == 0) pixman_image_composite (op, src_img, NULL, dst_img, src_x, src_y, 0, 0, dst_x, dst_y, w, h); else @@ -380,11 +375,11 @@ test_composite (int testnum, } #if BILINEAR_INTERPOLATION_BITS == 8 -#define CHECKSUM 0x107B67ED +#define CHECKSUM 0x9096E6B6 #elif BILINEAR_INTERPOLATION_BITS == 7 -#define CHECKSUM 0x30EC0CF0 +#define CHECKSUM 0xCE8EC6BA #elif BILINEAR_INTERPOLATION_BITS == 4 -#define CHECKSUM 0x87B496BC +#define CHECKSUM 0xAB1D39BE #else #define CHECKSUM 0x00000000 #endif diff --git a/pixman/test/stress-test.c b/pixman/test/stress-test.c index 059250dd4..ee55c21ea 100644 --- a/pixman/test/stress-test.c +++ b/pixman/test/stress-test.c @@ -74,7 +74,7 @@ static pixman_filter_t filters[] = static int get_size (void) { - switch (lcg_rand_n (28)) + switch (prng_rand_n (28)) { case 0: return 1; @@ -84,10 +84,10 @@ get_size (void) default: case 2: - return lcg_rand_n (100); + return prng_rand_n (100); case 4: - return lcg_rand_n (2000) + 1000; + return prng_rand_n (2000) + 1000; case 5: return 65535; @@ -96,7 +96,7 @@ get_size (void) return 65536; case 7: - return lcg_rand_N (64000) + 63000; + return prng_rand_n (64000) + 63000; } } @@ -164,7 +164,7 @@ real_writer (void *src, uint32_t value, int size) static uint32_t fake_reader (const void *src, int size) { - uint32_t r = lcg_rand_u32 (); + uint32_t r = prng_rand (); assert (size == 1 || size == 2 || size == 4); @@ -182,16 +182,16 @@ log_rand (void) { uint32_t mask; - mask = (1 << lcg_rand_n (10)) - 1; + mask = (1 << prng_rand_n (10)) - 1; - return (lcg_rand_u32 () & mask) - (mask >> 1); + return (prng_rand () & mask) - (mask >> 1); } static int32_t rand_x (pixman_image_t *image) { if (image->type == BITS) - return lcg_rand_n (image->bits.width); + return prng_rand_n (image->bits.width); else return log_rand (); } @@ -200,7 +200,7 @@ static int32_t rand_y (pixman_image_t *image) { if (image->type == BITS) - return lcg_rand_n (image->bits.height); + return prng_rand_n (image->bits.height); else return log_rand (); } @@ -220,7 +220,7 @@ create_random_bits_image (void) int n_coefficients = 0; /* format */ - format = image_formats[lcg_rand_n (ARRAY_LENGTH (image_formats))]; + format = image_formats[prng_rand_n (ARRAY_LENGTH (image_formats))]; indexed = NULL; if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_COLOR) @@ -246,7 +246,7 @@ create_random_bits_image (void) while ((uint64_t)width * height > 200000) { - if (lcg_rand_n(2) == 0) + if (prng_rand_n(2) == 0) height = 200000 / width; else width = 200000 / height; @@ -258,11 +258,11 @@ create_random_bits_image (void) width = 1; /* bits */ - switch (lcg_rand_n (7)) + switch (prng_rand_n (7)) { default: case 0: - stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17); + stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17); stride = (stride + 3) & (~3); bits = (uint32_t *)make_random_bytes (height * stride); break; @@ -273,7 +273,7 @@ create_random_bits_image (void) break; case 2: /* Zero-filled */ - stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17); + stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17); stride = (stride + 3) & (~3); bits = fence_malloc (height * stride); if (!bits) @@ -282,7 +282,7 @@ create_random_bits_image (void) break; case 3: /* Filled with 0xFF */ - stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17); + stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17); stride = (stride + 3) & (~3); bits = fence_malloc (height * stride); if (!bits) @@ -298,7 +298,7 @@ create_random_bits_image (void) break; case 5: /* bits is a real pointer, has read/write functions */ - stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17); + stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17); stride = (stride + 3) & (~3); bits = fence_malloc (height * stride); if (!bits) @@ -309,7 +309,7 @@ create_random_bits_image (void) break; case 6: /* bits is a real pointer, stride is negative */ - stride = (width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17)); + stride = (width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17)); stride = (stride + 3) & (~3); bits = (uint32_t *)make_random_bytes (height * stride); if (!bits) @@ -320,11 +320,11 @@ create_random_bits_image (void) } /* Filter */ - filter = filters[lcg_rand_n (ARRAY_LENGTH (filters))]; + filter = filters[prng_rand_n (ARRAY_LENGTH (filters))]; if (filter == PIXMAN_FILTER_CONVOLUTION) { - int width = lcg_rand_n (3); - int height = lcg_rand_n (4); + int width = prng_rand_n (3); + int height = prng_rand_n (4); n_coefficients = width * height + 2; coefficients = malloc (n_coefficients * sizeof (pixman_fixed_t)); @@ -334,7 +334,7 @@ create_random_bits_image (void) int i; for (i = 0; i < width * height; ++i) - coefficients[i + 2] = lcg_rand_u32(); + coefficients[i + 2] = prng_rand(); coefficients[0] = width << 16; coefficients[1] = height << 16; @@ -380,11 +380,11 @@ set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map) /* Set properties that are generic to all images */ /* Repeat */ - repeat = repeats[lcg_rand_n (ARRAY_LENGTH (repeats))]; + repeat = repeats[prng_rand_n (ARRAY_LENGTH (repeats))]; pixman_image_set_repeat (image, repeat); /* Alpha map */ - if (allow_alpha_map && lcg_rand_n (4) == 0) + if (allow_alpha_map && prng_rand_n (4) == 0) { pixman_image_t *alpha_map; int16_t x, y; @@ -405,17 +405,17 @@ set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map) } /* Component alpha */ - pixman_image_set_component_alpha (image, lcg_rand_n (3) == 0); + pixman_image_set_component_alpha (image, prng_rand_n (3) == 0); /* Clip region */ - if (lcg_rand_n (8) < 2) + if (prng_rand_n (8) < 2) { pixman_region32_t region; int i, n_rects; pixman_region32_init (®ion); - switch (lcg_rand_n (12)) + switch (prng_rand_n (12)) { case 0: n_rects = 0; @@ -434,7 +434,7 @@ set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map) break; default: - n_rects = lcg_rand_n (100); + n_rects = prng_rand_n (100); break; } @@ -452,7 +452,7 @@ set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map) ®ion, ®ion, x, y, width, height); } - if (image->type == BITS && lcg_rand_n (8) != 0) + if (image->type == BITS && prng_rand_n (8) != 0) { uint32_t width, height; int x, y; @@ -463,10 +463,10 @@ set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map) */ for (i = 0; i < 5; ++i) { - x = lcg_rand_n (2 * image->bits.width) - image->bits.width; - y = lcg_rand_n (2 * image->bits.height) - image->bits.height; - width = lcg_rand_n (image->bits.width) - x + 10; - height = lcg_rand_n (image->bits.height) - y + 10; + x = prng_rand_n (2 * image->bits.width) - image->bits.width; + y = prng_rand_n (2 * image->bits.height) - image->bits.height; + width = prng_rand_n (image->bits.width) - x + 10; + height = prng_rand_n (image->bits.height) - y + 10; if (width + x < x) width = INT32_MAX - x; @@ -484,13 +484,13 @@ set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map) } /* Whether source clipping is enabled */ - pixman_image_set_source_clipping (image, !!lcg_rand_n (2)); + pixman_image_set_source_clipping (image, !!prng_rand_n (2)); /* Client clip */ - pixman_image_set_has_client_clip (image, !!lcg_rand_n (2)); + pixman_image_set_has_client_clip (image, !!prng_rand_n (2)); /* Transform */ - if (lcg_rand_n (5) < 2) + if (prng_rand_n (5) < 2) { pixman_transform_t xform; int i, j, k; @@ -504,39 +504,39 @@ set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map) for (k = 0; k < 3; ++k) { - switch (lcg_rand_n (4)) + switch (prng_rand_n (4)) { case 0: /* rotation */ - c = lcg_rand_N (2 * 65536) - 65536; - s = lcg_rand_N (2 * 65536) - 65536; + c = prng_rand_n (2 * 65536) - 65536; + s = prng_rand_n (2 * 65536) - 65536; pixman_transform_rotate (&xform, NULL, c, s); break; case 1: /* translation */ - tx = lcg_rand_u32(); - ty = lcg_rand_u32(); + tx = prng_rand(); + ty = prng_rand(); pixman_transform_translate (&xform, NULL, tx, ty); break; case 2: /* scale */ - sx = lcg_rand_u32(); - sy = lcg_rand_u32(); + sx = prng_rand(); + sy = prng_rand(); pixman_transform_scale (&xform, NULL, sx, sy); break; case 3: - if (lcg_rand_n (16) == 0) + if (prng_rand_n (16) == 0) { /* random */ for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j) - xform.matrix[i][j] = lcg_rand_u32(); + xform.matrix[i][j] = prng_rand(); break; } - else if (lcg_rand_n (16) == 0) + else if (prng_rand_n (16) == 0) { /* zero */ memset (&xform, 0, sizeof xform); @@ -554,10 +554,10 @@ random_color (void) { pixman_color_t color = { - lcg_rand() & 0xffff, - lcg_rand() & 0xffff, - lcg_rand() & 0xffff, - lcg_rand() & 0xffff, + prng_rand() & 0xffff, + prng_rand() & 0xffff, + prng_rand() & 0xffff, + prng_rand() & 0xffff, }; return color; @@ -581,7 +581,7 @@ create_random_stops (int *n_stops) int i; pixman_gradient_stop_t *stops; - *n_stops = lcg_rand_n (50) + 1; + *n_stops = prng_rand_n (50) + 1; step = pixman_fixed_1 / *n_stops; @@ -646,8 +646,8 @@ create_random_radial_image (void) inner_c = create_random_point(); outer_c = create_random_point(); - inner_r = lcg_rand(); - outer_r = lcg_rand(); + inner_r = prng_rand(); + outer_r = prng_rand(); stops = create_random_stops (&n_stops); @@ -672,7 +672,7 @@ create_random_conical_image (void) pixman_image_t *result; c = create_random_point(); - angle = lcg_rand(); + angle = prng_rand(); stops = create_random_stops (&n_stops); @@ -691,7 +691,7 @@ create_random_image (void) { pixman_image_t *result; - switch (lcg_rand_n (5)) + switch (prng_rand_n (5)) { default: case 0: @@ -793,7 +793,7 @@ run_test (uint32_t seed, pixman_bool_t verbose, uint32_t mod) printf ("Seed 0x%08x\n", seed); } - lcg_srand (seed); + prng_srand (seed); source = create_random_image (); mask = create_random_image (); @@ -803,7 +803,7 @@ run_test (uint32_t seed, pixman_bool_t verbose, uint32_t mod) { set_general_properties (dest, TRUE); - op = op_list [lcg_rand_n (ARRAY_LENGTH (op_list))]; + op = op_list [prng_rand_n (ARRAY_LENGTH (op_list))]; pixman_image_composite32 (op, source, mask, dest, diff --git a/pixman/test/utils-prng.c b/pixman/test/utils-prng.c new file mode 100644 index 000000000..7c2dd6a9a --- /dev/null +++ b/pixman/test/utils-prng.c @@ -0,0 +1,238 @@ +/* + * Copyright © 2012 Siarhei Siamashka <siarhei.siamashka@gmail.com> + * + * Based on the public domain implementation of small noncryptographic PRNG + * authored by Bob Jenkins: http://burtleburtle.net/bob/rand/smallprng.html + * + * 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. + */ + +#include "utils.h" +#include "utils-prng.h" + +void smallprng_srand_r (smallprng_t *x, uint32_t seed) +{ + uint32_t i; + x->a = 0xf1ea5eed, x->b = x->c = x->d = seed; + for (i = 0; i < 20; ++i) + smallprng_rand_r (x); +} + +/* + * Set a 32-bit seed for PRNG + * + * LCG is used here for generating independent seeds for different + * smallprng instances (in the case if smallprng is also used for + * generating these seeds, "Big Crush" test from TestU01 detects + * some problems in the glued 'prng_rand_128_r' output data). + * Actually we might be even better using some cryptographic + * hash for this purpose, but LCG seems to be also enough for + * passing "Big Crush". + */ +void prng_srand_r (prng_t *x, uint32_t seed) +{ +#ifdef GCC_VECTOR_EXTENSIONS_SUPPORTED + int i; + prng_rand_128_data_t dummy; + smallprng_srand_r (&x->p0, seed); + x->a[0] = x->a[1] = x->a[2] = x->a[3] = 0xf1ea5eed; + x->b[0] = x->c[0] = x->d[0] = (seed = seed * 1103515245 + 12345); + x->b[1] = x->c[1] = x->d[1] = (seed = seed * 1103515245 + 12345); + x->b[2] = x->c[2] = x->d[2] = (seed = seed * 1103515245 + 12345); + x->b[3] = x->c[3] = x->d[3] = (seed = seed * 1103515245 + 12345); + for (i = 0; i < 20; ++i) + prng_rand_128_r (x, &dummy); +#else + smallprng_srand_r (&x->p0, seed); + smallprng_srand_r (&x->p1, (seed = seed * 1103515245 + 12345)); + smallprng_srand_r (&x->p2, (seed = seed * 1103515245 + 12345)); + smallprng_srand_r (&x->p3, (seed = seed * 1103515245 + 12345)); + smallprng_srand_r (&x->p4, (seed = seed * 1103515245 + 12345)); +#endif +} + +static force_inline void +store_rand_128_data (void *addr, prng_rand_128_data_t *d, int aligned) +{ +#ifdef GCC_VECTOR_EXTENSIONS_SUPPORTED + if (aligned) + { + *(uint8x16 *)addr = d->vb; + return; + } +#endif + /* we could try something better for unaligned writes (packed attribute), + * but GCC is not very reliable: http://gcc.gnu.org/PR55454 */ + memcpy (addr, d, 16); +} + +/* + * Helper function and the actual code for "prng_randmemset_r" function + */ +static force_inline void +randmemset_internal (prng_t *prng, + uint8_t *buf, + size_t size, + prng_randmemset_flags_t flags, + int aligned) +{ + prng_t local_prng = *prng; + prng_rand_128_data_t randdata; + + while (size >= 16) + { + prng_rand_128_data_t t; + if (flags == 0) + { + prng_rand_128_r (&local_prng, &randdata); + } + else + { + prng_rand_128_r (&local_prng, &t); + prng_rand_128_r (&local_prng, &randdata); +#ifdef GCC_VECTOR_EXTENSIONS_SUPPORTED + if (flags & RANDMEMSET_MORE_FF) + { + const uint8x16 const_C0 = + { + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 + }; + randdata.vb |= (t.vb >= const_C0); + } + if (flags & RANDMEMSET_MORE_00) + { + const uint8x16 const_40 = + { + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 + }; + randdata.vb &= (t.vb >= const_40); + } +#else + #define PROCESS_ONE_LANE(i) \ + if (flags & RANDMEMSET_MORE_FF) \ + { \ + uint32_t mask_ff = (t.w[i] & (t.w[i] << 1)) & 0x80808080; \ + mask_ff |= mask_ff >> 1; \ + mask_ff |= mask_ff >> 2; \ + mask_ff |= mask_ff >> 4; \ + randdata.w[i] |= mask_ff; \ + } \ + if (flags & RANDMEMSET_MORE_00) \ + { \ + uint32_t mask_00 = (t.w[i] | (t.w[i] << 1)) & 0x80808080; \ + mask_00 |= mask_00 >> 1; \ + mask_00 |= mask_00 >> 2; \ + mask_00 |= mask_00 >> 4; \ + randdata.w[i] &= mask_00; \ + } + + PROCESS_ONE_LANE (0) + PROCESS_ONE_LANE (1) + PROCESS_ONE_LANE (2) + PROCESS_ONE_LANE (3) +#endif + } + if (is_little_endian ()) + { + store_rand_128_data (buf, &randdata, aligned); + buf += 16; + } + else + { +#ifdef GCC_VECTOR_EXTENSIONS_SUPPORTED + const uint8x16 bswap_shufflemask = + { + 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 + }; + randdata.vb = __builtin_shuffle (randdata.vb, bswap_shufflemask); + store_rand_128_data (buf, &randdata, aligned); + buf += 16; +#else + uint8_t t1, t2, t3, t4; + #define STORE_ONE_LANE(i) \ + t1 = randdata.b[i * 4 + 3]; \ + t2 = randdata.b[i * 4 + 2]; \ + t3 = randdata.b[i * 4 + 1]; \ + t4 = randdata.b[i * 4 + 0]; \ + *buf++ = t1; \ + *buf++ = t2; \ + *buf++ = t3; \ + *buf++ = t4; + + STORE_ONE_LANE (0) + STORE_ONE_LANE (1) + STORE_ONE_LANE (2) + STORE_ONE_LANE (3) +#endif + } + size -= 16; + } + while (size > 0) + { + uint8_t randbyte = prng_rand_r (&local_prng) & 0xFF; + if (flags != 0) + { + uint8_t t = prng_rand_r (&local_prng) & 0xFF; + if ((flags & RANDMEMSET_MORE_FF) && (t >= 0xC0)) + randbyte = 0xFF; + if ((flags & RANDMEMSET_MORE_00) && (t < 0x40)) + randbyte = 0x00; + } + *buf++ = randbyte; + size--; + } + *prng = local_prng; +} + +/* + * Fill memory buffer with random data. Flags argument may be used + * to tweak some statistics properties: + * RANDMEMSET_MORE_00 - set ~25% of bytes to 0x00 + * RANDMEMSET_MORE_FF - set ~25% of bytes to 0xFF + */ +void prng_randmemset_r (prng_t *prng, + void *voidbuf, + size_t size, + prng_randmemset_flags_t flags) +{ + uint8_t *buf = (uint8_t *)voidbuf; + if ((uintptr_t)buf & 15) + { + /* unaligned buffer */ + if (flags == 0) + randmemset_internal (prng, buf, size, 0, 0); + else if (flags == RANDMEMSET_MORE_00_AND_FF) + randmemset_internal (prng, buf, size, RANDMEMSET_MORE_00_AND_FF, 0); + else + randmemset_internal (prng, buf, size, flags, 0); + } + else + { + /* aligned buffer */ + if (flags == 0) + randmemset_internal (prng, buf, size, 0, 1); + else if (flags == RANDMEMSET_MORE_00_AND_FF) + randmemset_internal (prng, buf, size, RANDMEMSET_MORE_00_AND_FF, 1); + else + randmemset_internal (prng, buf, size, flags, 1); + } +} diff --git a/pixman/test/utils-prng.h b/pixman/test/utils-prng.h new file mode 100644 index 000000000..285107f08 --- /dev/null +++ b/pixman/test/utils-prng.h @@ -0,0 +1,168 @@ +/* + * Copyright © 2012 Siarhei Siamashka <siarhei.siamashka@gmail.com> + * + * Based on the public domain implementation of small noncryptographic PRNG + * authored by Bob Jenkins: http://burtleburtle.net/bob/rand/smallprng.html + * + * 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. + */ + +#ifndef __UTILS_PRNG_H__ +#define __UTILS_PRNG_H__ + +/* + * This file provides a fast SIMD-optimized noncryptographic PRNG (pseudorandom + * number generator), with the output good enough to pass "Big Crush" tests + * from TestU01 (http://en.wikipedia.org/wiki/TestU01). + * + * SIMD code uses http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html + * which is a GCC specific extension. There is also a slower alternative + * code path, which should work with any C compiler. + * + * The "prng_t" structure keeps the internal state of the random number + * generator. It is possible to have multiple instances of the random number + * generator active at the same time, in this case each of them needs to have + * its own "prng_t". All the functions take a pointer to "prng_t" + * as the first argument. + * + * Functions: + * + * ---------------------------------------------------------------------------- + * void prng_srand_r (prng_t *prng, uint32_t seed); + * + * Initialize the pseudorandom number generator. The sequence of preudorandom + * numbers is deterministic and only depends on "seed". Any two generators + * initialized with the same seed will produce exactly the same sequence. + * + * ---------------------------------------------------------------------------- + * uint32_t prng_rand_r (prng_t *prng); + * + * Generate a single uniformly distributed 32-bit pseudorandom value. + * + * ---------------------------------------------------------------------------- + * void prng_randmemset_r (prng_t *prng, + * void *buffer, + * size_t size, + * prng_randmemset_flags_t flags); + * + * Fills the memory buffer "buffer" with "size" bytes of pseudorandom data. + * The "flags" argument may be used to tweak some statistics properties: + * RANDMEMSET_MORE_00 - set ~25% of bytes to 0x00 + * RANDMEMSET_MORE_FF - set ~25% of bytes to 0xFF + * The flags can be combined. This allows a bit better simulation of typical + * pixel data, which normally contains a lot of fully transparent or fully + * opaque pixels. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "pixman-private.h" + +/*****************************************************************************/ + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) +#define GCC_VECTOR_EXTENSIONS_SUPPORTED +typedef uint32_t uint32x4 __attribute__ ((vector_size(16))); +typedef uint8_t uint8x16 __attribute__ ((vector_size(16))); +#endif + +typedef struct +{ + uint32_t a, b, c, d; +} smallprng_t; + +typedef struct +{ +#ifdef GCC_VECTOR_EXTENSIONS_SUPPORTED + uint32x4 a, b, c, d; +#else + smallprng_t p1, p2, p3, p4; +#endif + smallprng_t p0; +} prng_t; + +typedef union +{ + uint8_t b[16]; + uint32_t w[4]; +#ifdef GCC_VECTOR_EXTENSIONS_SUPPORTED + uint8x16 vb; + uint32x4 vw; +#endif +} prng_rand_128_data_t; + +/*****************************************************************************/ + +static force_inline uint32_t +smallprng_rand_r (smallprng_t *x) +{ + uint32_t e = x->a - ((x->b << 27) + (x->b >> (32 - 27))); + x->a = x->b ^ ((x->c << 17) ^ (x->c >> (32 - 17))); + x->b = x->c + x->d; + x->c = x->d + e; + x->d = e + x->a; + return x->d; +} + +/* Generate 4 bytes (32-bits) of random data */ +static force_inline uint32_t +prng_rand_r (prng_t *x) +{ + return smallprng_rand_r (&x->p0); +} + +/* Generate 16 bytes (128-bits) of random data */ +static force_inline void +prng_rand_128_r (prng_t *x, prng_rand_128_data_t *data) +{ +#ifdef GCC_VECTOR_EXTENSIONS_SUPPORTED + uint32x4 e = x->a - ((x->b << 27) + (x->b >> (32 - 27))); + x->a = x->b ^ ((x->c << 17) ^ (x->c >> (32 - 17))); + x->b = x->c + x->d; + x->c = x->d + e; + x->d = e + x->a; + data->vw = x->d; +#else + data->w[0] = smallprng_rand_r (&x->p1); + data->w[1] = smallprng_rand_r (&x->p2); + data->w[2] = smallprng_rand_r (&x->p3); + data->w[3] = smallprng_rand_r (&x->p4); +#endif +} + +typedef enum +{ + RANDMEMSET_MORE_00 = 1, /* ~25% chance for 0x00 bytes */ + RANDMEMSET_MORE_FF = 2, /* ~25% chance for 0xFF bytes */ + RANDMEMSET_MORE_00_AND_FF = (RANDMEMSET_MORE_00 | RANDMEMSET_MORE_FF) +} prng_randmemset_flags_t; + +/* Set the 32-bit seed for PRNG */ +void prng_srand_r (prng_t *prng, uint32_t seed); + +/* Fill memory buffer with random data */ +void prng_randmemset_r (prng_t *prng, + void *buffer, + size_t size, + prng_randmemset_flags_t flags); + +#endif diff --git a/pixman/test/utils.c b/pixman/test/utils.c index c887a6db9..66c8dcb89 100644 --- a/pixman/test/utils.c +++ b/pixman/test/utils.c @@ -27,10 +27,11 @@ #include <png.h> #endif -/* Random number seed +/* Random number generator state */ -uint32_t lcg_seed; +prng_t prng_state_data; +prng_t *prng_state; /*----------------------------------------------------------------------------*\ * CRC-32 version 2.0.0 by Craig Bruce, 2006-04-29. @@ -237,14 +238,6 @@ compute_crc32_for_image (uint32_t crc32, return crc32; } -pixman_bool_t -is_little_endian (void) -{ - volatile uint16_t endian_check_var = 0x1234; - - return (*(volatile uint8_t *)&endian_check_var == 0x34); -} - /* perform endian conversion of pixel data */ void @@ -431,13 +424,11 @@ uint8_t * make_random_bytes (int n_bytes) { uint8_t *bytes = fence_malloc (n_bytes); - int i; if (!bytes) return NULL; - for (i = 0; i < n_bytes; ++i) - bytes[i] = lcg_rand () & 0xff; + prng_randmemset (bytes, n_bytes, 0); return bytes; } @@ -689,9 +680,9 @@ get_random_seed (void) { union { double d; uint32_t u32; } t; t.d = gettime(); - lcg_srand (t.u32); + prng_srand (t.u32); - return lcg_rand_u32 (); + return prng_rand (); } #ifdef HAVE_SIGACTION @@ -785,7 +776,7 @@ initialize_palette (pixman_indexed_t *palette, uint32_t depth, int is_rgb) uint32_t mask = (1 << depth) - 1; for (i = 0; i < 32768; ++i) - palette->ent[i] = lcg_rand() & mask; + palette->ent[i] = prng_rand() & mask; memset (palette->rgba, 0, sizeof (palette->rgba)); @@ -805,7 +796,7 @@ initialize_palette (pixman_indexed_t *palette, uint32_t depth, int is_rgb) { uint32_t old_idx; - rgba24 = lcg_rand(); + rgba24 = prng_rand(); i15 = CONVERT_15 (rgba24, is_rgb); old_idx = palette->ent[i15]; diff --git a/pixman/test/utils.h b/pixman/test/utils.h index f7ea34c5f..78cf0d16d 100644 --- a/pixman/test/utils.h +++ b/pixman/test/utils.h @@ -4,6 +4,7 @@ #include <assert.h> #include "pixman-private.h" /* For 'inline' definition */ +#include "utils-prng.h" #define ARRAY_LENGTH(A) ((int) (sizeof (A) / sizeof ((A) [0]))) @@ -11,49 +12,44 @@ * taken from POSIX.1-2001 example */ -extern uint32_t lcg_seed; +extern prng_t prng_state_data; +extern prng_t *prng_state; #ifdef USE_OPENMP -#pragma omp threadprivate(lcg_seed) +#pragma omp threadprivate(prng_state_data) +#pragma omp threadprivate(prng_state) #endif static inline uint32_t -lcg_rand (void) +prng_rand (void) { - lcg_seed = lcg_seed * 1103515245 + 12345; - return ((uint32_t)(lcg_seed / 65536) % 32768); + return prng_rand_r (prng_state); } static inline void -lcg_srand (uint32_t seed) +prng_srand (uint32_t seed) { - lcg_seed = seed; + if (!prng_state) + { + /* Without setting a seed, PRNG does not work properly (is just + * returning zeros). So we only initialize the pointer here to + * make sure that 'prng_srand' is always called before any + * other 'prng_*' function. The wrongdoers violating this order + * will get a segfault. */ + prng_state = &prng_state_data; + } + prng_srand_r (prng_state, seed); } static inline uint32_t -lcg_rand_n (int max) +prng_rand_n (int max) { - return lcg_rand () % max; + return prng_rand () % max; } -static inline uint32_t -lcg_rand_N (int max) -{ - uint32_t lo = lcg_rand (); - uint32_t hi = lcg_rand () << 15; - return (lo | hi) % max; -} - -static inline uint32_t -lcg_rand_u32 (void) +static inline void +prng_randmemset (void *buffer, size_t size, prng_randmemset_flags_t flags) { - /* This uses the 10/11 most significant bits from the 3 lcg results - * (and mixes them with the low from the adjacent one). - */ - uint32_t lo = lcg_rand() >> -(32 - 15 - 11 * 2); - uint32_t mid = lcg_rand() << (32 - 15 - 11 * 1); - uint32_t hi = lcg_rand() << (32 - 15 - 11 * 0); - - return (hi ^ mid ^ lo); + prng_randmemset_r (prng_state, buffer, size, flags); } /* CRC 32 computation @@ -69,8 +65,12 @@ compute_crc32_for_image (uint32_t in_crc32, /* Returns TRUE if running on a little endian system */ -pixman_bool_t -is_little_endian (void); +static force_inline pixman_bool_t +is_little_endian (void) +{ + unsigned long endian_check_var = 1; + return *(unsigned char *)&endian_check_var == 1; +} /* perform endian conversion of pixel data */ |