stress-test.c revision 953d7d37
1#include "utils.h"
2
3#if 0
4#define fence_malloc malloc
5#define fence_free free
6#define make_random_bytes malloc
7#endif
8
9static const pixman_format_code_t image_formats[] =
10{
11    PIXMAN_a8r8g8b8,
12    PIXMAN_x8r8g8b8,
13    PIXMAN_r5g6b5,
14    PIXMAN_r3g3b2,
15    PIXMAN_a8,
16    PIXMAN_a8b8g8r8,
17    PIXMAN_x8b8g8r8,
18    PIXMAN_b8g8r8a8,
19    PIXMAN_b8g8r8x8,
20    PIXMAN_x14r6g6b6,
21    PIXMAN_r8g8b8,
22    PIXMAN_b8g8r8,
23    PIXMAN_r5g6b5,
24    PIXMAN_b5g6r5,
25    PIXMAN_x2r10g10b10,
26    PIXMAN_a2r10g10b10,
27    PIXMAN_x2b10g10r10,
28    PIXMAN_a2b10g10r10,
29    PIXMAN_a1r5g5b5,
30    PIXMAN_x1r5g5b5,
31    PIXMAN_a1b5g5r5,
32    PIXMAN_x1b5g5r5,
33    PIXMAN_a4r4g4b4,
34    PIXMAN_x4r4g4b4,
35    PIXMAN_a4b4g4r4,
36    PIXMAN_x4b4g4r4,
37    PIXMAN_a8,
38    PIXMAN_r3g3b2,
39    PIXMAN_b2g3r3,
40    PIXMAN_a2r2g2b2,
41    PIXMAN_a2b2g2r2,
42    PIXMAN_c8,
43    PIXMAN_g8,
44    PIXMAN_x4c4,
45    PIXMAN_x4g4,
46    PIXMAN_c4,
47    PIXMAN_g4,
48    PIXMAN_g1,
49    PIXMAN_x4a4,
50    PIXMAN_a4,
51    PIXMAN_r1g2b1,
52    PIXMAN_b1g2r1,
53    PIXMAN_a1r1g1b1,
54    PIXMAN_a1b1g1r1,
55    PIXMAN_a1
56};
57
58static pixman_filter_t filters[] =
59{
60    PIXMAN_FILTER_NEAREST,
61    PIXMAN_FILTER_BILINEAR,
62    PIXMAN_FILTER_FAST,
63    PIXMAN_FILTER_GOOD,
64    PIXMAN_FILTER_BEST,
65    PIXMAN_FILTER_CONVOLUTION
66};
67
68static int
69get_size (void)
70{
71    switch (lcg_rand_n (28))
72    {
73    case 0:
74	return 1;
75
76    case 1:
77	return 2;
78
79    default:
80    case 2:
81	return lcg_rand_n (200);
82
83    case 4:
84	return lcg_rand_n (2000) + 1000;
85
86    case 5:
87	return 65535;
88
89    case 6:
90	return 65536;
91
92    case 7:
93	return lcg_rand_N (64000) + 63000;
94    }
95}
96
97static void
98destroy (pixman_image_t *image, void *data)
99{
100    if (image->type == BITS && image->bits.free_me != image->bits.bits)
101    {
102	uint32_t *bits;
103
104	if (image->bits.bits != (void *)0x01)
105	{
106	    bits = image->bits.bits;
107
108	    if (image->bits.rowstride < 0)
109		bits -= (- image->bits.rowstride * (image->bits.height - 1));
110
111	    fence_free (bits);
112	}
113    }
114
115    free (data);
116}
117
118static uint32_t
119real_reader (const void *src, int size)
120{
121    switch (size)
122    {
123    case 1:
124	return *(uint8_t *)src;
125    case 2:
126	return *(uint16_t *)src;
127    case 4:
128	return *(uint32_t *)src;
129    default:
130	assert (0);
131	break;
132    }
133}
134
135static void
136real_writer (void *src, uint32_t value, int size)
137{
138    switch (size)
139    {
140    case 1:
141	*(uint8_t *)src = value;
142	break;
143
144    case 2:
145	*(uint16_t *)src = value;
146	break;
147
148    case 4:
149	*(uint32_t *)src = value;
150	break;
151
152    default:
153	assert (0);
154	break;
155    }
156}
157
158static uint32_t
159fake_reader (const void *src, int size)
160{
161    uint32_t r = lcg_rand_u32 ();
162
163    assert (size == 1 || size == 2 || size == 4);
164    return r & ((1 << (size * 8)) - 1);
165}
166
167static void
168fake_writer (void *src, uint32_t value, int size)
169{
170    assert (size == 1 || size == 2 || size == 4);
171}
172
173static int32_t
174log_rand (void)
175{
176    uint32_t mask;
177
178    mask = (1 << lcg_rand_n (31)) - 1;
179
180    return (lcg_rand () & mask) - (mask >> 1);
181}
182
183static pixman_image_t *
184create_random_bits_image (void)
185{
186    pixman_format_code_t format;
187    pixman_indexed_t *indexed;
188    pixman_image_t *image;
189    int width, height, stride;
190    uint32_t *bits;
191    pixman_read_memory_func_t read_func = NULL;
192    pixman_write_memory_func_t write_func = NULL;
193    pixman_filter_t filter;
194    pixman_fixed_t *coefficients = NULL;
195    int n_coefficients = 0;
196
197    /* format */
198    format = image_formats[lcg_rand_n (ARRAY_LENGTH (image_formats))];
199
200    indexed = NULL;
201    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_COLOR)
202    {
203	indexed = malloc (sizeof (pixman_indexed_t));
204
205	initialize_palette (indexed, PIXMAN_FORMAT_BPP (format), TRUE);
206    }
207    else if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_GRAY)
208    {
209	indexed = malloc (sizeof (pixman_indexed_t));
210
211	initialize_palette (indexed, PIXMAN_FORMAT_BPP (format), FALSE);
212    }
213    else
214    {
215	indexed = NULL;
216    }
217
218    /* size */
219    width = get_size ();
220    height = get_size ();
221
222    if ((uint64_t)width * height > 200000)
223    {
224	if (lcg_rand_n(2) == 0)
225	    height = 200000 / width;
226	else
227	    width = 200000 / height;
228    }
229
230    if (height == 0)
231	height = 1;
232    if (width == 0)
233	width = 1;
234
235    /* bits */
236    switch (lcg_rand_n (7))
237    {
238    default:
239    case 0:
240	stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17);
241	stride = (stride + 3) & (~3);
242	bits = (uint32_t *)make_random_bytes (height * stride);
243	break;
244
245    case 1:
246	stride = 0;
247	bits = NULL;
248	break;
249
250    case 2: /* Zero-filled */
251	stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17);
252	stride = (stride + 3) & (~3);
253	bits = fence_malloc (height * stride);
254	if (!bits)
255	    return NULL;
256	memset (bits, 0, height * stride);
257	break;
258
259    case 3: /* Filled with 0xFF */
260	stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17);
261	stride = (stride + 3) & (~3);
262	bits = fence_malloc (height * stride);
263	if (!bits)
264	    return NULL;
265	memset (bits, 0xff, height * stride);
266	break;
267
268    case 4: /* bits is a bad pointer, has read/write functions */
269	stride = 232;
270	bits = (void *)0x01;
271	read_func = fake_reader;
272	write_func = fake_writer;
273	break;
274
275    case 5: /* bits is a real pointer, has read/write functions */
276	stride = width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17);
277	stride = (stride + 3) & (~3);
278	bits = fence_malloc (height * stride);
279	if (!bits)
280	    return NULL;
281	memset (bits, 0xff, height * stride);
282	read_func = real_reader;
283	write_func = real_writer;
284	break;
285
286    case 6: /* bits is a real pointer, stride is negative */
287	stride = (width * PIXMAN_FORMAT_BPP (format) + lcg_rand_n (17));
288	stride = (stride + 3) & (~3);
289	bits = (uint32_t *)make_random_bytes (height * stride);
290	if (!bits)
291	    return NULL;
292	bits += ((height - 1) * stride) / 4;
293	stride = - stride;
294	break;
295    }
296
297    /* Filter */
298    filter = filters[lcg_rand_n (ARRAY_LENGTH (filters))];
299    if (filter == PIXMAN_FILTER_CONVOLUTION)
300    {
301	int width = lcg_rand_n (17);
302	int height = lcg_rand_n (19);
303
304	n_coefficients = width * height + 2;
305	coefficients = malloc (n_coefficients * sizeof (pixman_fixed_t));
306
307	if (coefficients)
308	{
309	    int i;
310
311	    for (i = 0; i < width * height; ++i)
312		coefficients[i + 2] = lcg_rand_u32();
313
314	    coefficients[0] = width << 16;
315	    coefficients[1] = height << 16;
316	}
317	else
318	{
319	    filter = PIXMAN_FILTER_BEST;
320	}
321    }
322
323    /* Finally create the image */
324    image = pixman_image_create_bits (format, width, height, bits, stride);
325    if (!image)
326	return NULL;
327
328    pixman_image_set_indexed (image, indexed);
329    pixman_image_set_destroy_function (image, destroy, indexed);
330    pixman_image_set_accessors (image, read_func, write_func);
331    pixman_image_set_filter (image, filter, coefficients, n_coefficients);
332
333    return image;
334}
335
336static pixman_repeat_t repeats[] =
337{
338    PIXMAN_REPEAT_NONE,
339    PIXMAN_REPEAT_NORMAL,
340    PIXMAN_REPEAT_REFLECT,
341    PIXMAN_REPEAT_PAD
342};
343
344static uint32_t
345absolute (int32_t i)
346{
347    return i < 0? -i : i;
348}
349
350static void
351set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map)
352{
353    pixman_repeat_t repeat;
354
355    /* Set properties that are generic to all images */
356
357    /* Repeat */
358    repeat = repeats[lcg_rand_n (ARRAY_LENGTH (repeats))];
359    pixman_image_set_repeat (image, repeat);
360
361    /* Alpha map */
362    if (allow_alpha_map && lcg_rand_n (3) == 0)
363    {
364	pixman_image_t *alpha_map;
365	int16_t x, y;
366
367	alpha_map = create_random_bits_image ();
368
369	if (alpha_map)
370	{
371	    set_general_properties (alpha_map, FALSE);
372
373	    x = lcg_rand_N (100000) - 65536;
374	    y = lcg_rand_N (100000) - 65536;
375
376	    pixman_image_set_alpha_map (image, alpha_map, x, y);
377
378	    pixman_image_unref (alpha_map);
379	}
380    }
381
382    /* Component alpha */
383    pixman_image_set_component_alpha (image, lcg_rand_n (3) == 0);
384
385    /* Clip region */
386    if (lcg_rand_n (8) != 0)
387    {
388	pixman_region32_t region;
389	int i, n_rects;
390
391	pixman_region32_init (&region);
392
393	switch (lcg_rand_n (10))
394	{
395	case 0:
396	    n_rects = 0;
397	    break;
398
399	case 1: case 2: case 3:
400	    n_rects = 1;
401	    break;
402
403	case 4: case 5:
404	    n_rects = 2;
405	    break;
406
407	case 6: case 7:
408	    n_rects = 3;
409
410	default:
411	    n_rects = lcg_rand_n (100);
412	    break;
413	}
414
415	for (i = 0; i < n_rects; ++i)
416	{
417	    uint32_t width, height;
418	    int x, y;
419
420	    x = log_rand();
421	    y = log_rand();
422	    width = absolute (log_rand ()) + 1;
423	    height = absolute (log_rand ()) + 1;
424
425	    pixman_region32_union_rect (
426		&region, &region, x, y, width, height);
427	}
428
429	pixman_image_set_clip_region32 (image, &region);
430
431	pixman_region32_fini (&region);
432    }
433
434    /* Whether source clipping is enabled */
435    pixman_image_set_source_clipping (image, !!lcg_rand_n (2));
436
437    /* Client clip */
438    pixman_image_set_has_client_clip (image, !!lcg_rand_n (2));
439
440    /* Transform */
441    if (lcg_rand_n (5) < 2)
442    {
443	pixman_transform_t xform;
444	int i, j, k;
445	uint32_t tx, ty, sx, sy;
446	uint32_t c, s;
447
448	memset (&xform, 0, sizeof xform);
449	xform.matrix[0][0] = pixman_fixed_1;
450	xform.matrix[1][1] = pixman_fixed_1;
451	xform.matrix[2][2] = pixman_fixed_1;
452
453	for (k = 0; k < 3; ++k)
454	{
455	    switch (lcg_rand_n (4))
456	    {
457	    case 0:
458		/* rotation */
459		c = lcg_rand_N (2 * 65536) - 65536;
460		s = lcg_rand_N (2 * 65536) - 65536;
461		pixman_transform_rotate (&xform, NULL, c, s);
462		break;
463
464	    case 1:
465		/* translation */
466		tx = lcg_rand_u32();
467		ty = lcg_rand_u32();
468		pixman_transform_translate (&xform, NULL, tx, ty);
469		break;
470
471	    case 2:
472		/* scale */
473		sx = lcg_rand_u32();
474		sy = lcg_rand_u32();
475		pixman_transform_scale (&xform, NULL, sx, sy);
476		break;
477
478	    case 3:
479		if (lcg_rand_n (16) == 0)
480		{
481		    /* random */
482		    for (i = 0; i < 3; ++i)
483			for (j = 0; j < 3; ++j)
484			    xform.matrix[i][j] = lcg_rand_u32();
485		    break;
486		}
487		else if (lcg_rand_n (16) == 0)
488		{
489		    /* zero */
490		    memset (&xform, 0, sizeof xform);
491		}
492		break;
493	    }
494	}
495
496	pixman_image_set_transform (image, &xform);
497    }
498}
499
500static pixman_color_t
501random_color (void)
502{
503    pixman_color_t color =
504    {
505	lcg_rand() & 0xffff,
506	lcg_rand() & 0xffff,
507	lcg_rand() & 0xffff,
508	lcg_rand() & 0xffff,
509    };
510
511    return color;
512}
513
514
515static pixman_image_t *
516create_random_solid_image (void)
517{
518    pixman_color_t color = random_color();
519    pixman_image_t *image = pixman_image_create_solid_fill (&color);
520
521    return image;
522}
523
524static pixman_gradient_stop_t *
525create_random_stops (int *n_stops)
526{
527    pixman_fixed_t step;
528    pixman_fixed_t s;
529    int i;
530    pixman_gradient_stop_t *stops;
531
532    *n_stops = lcg_rand_n (50) + 1;
533
534    step = pixman_fixed_1 / *n_stops;
535
536    stops = malloc (*n_stops * sizeof (pixman_gradient_stop_t));
537
538    s = 0;
539    for (i = 0; i < (*n_stops) - 1; ++i)
540    {
541	stops[i].x = s;
542	stops[i].color = random_color();
543
544	s += step;
545    }
546
547    stops[*n_stops - 1].x = pixman_fixed_1;
548    stops[*n_stops - 1].color = random_color();
549
550    return stops;
551}
552
553static pixman_point_fixed_t
554create_random_point (void)
555{
556    pixman_point_fixed_t p;
557
558    p.x = log_rand ();
559    p.y = log_rand ();
560
561    return p;
562}
563
564static pixman_image_t *
565create_random_linear_image (void)
566{
567    int n_stops;
568    pixman_gradient_stop_t *stops;
569    pixman_point_fixed_t p1, p2;
570    pixman_image_t *result;
571
572    stops = create_random_stops (&n_stops);
573    if (!stops)
574	return NULL;
575
576    p1 = create_random_point ();
577    p2 = create_random_point ();
578
579    result = pixman_image_create_linear_gradient (&p1, &p2, stops, n_stops);
580
581    free (stops);
582
583    return result;
584}
585
586static pixman_image_t *
587create_random_radial_image (void)
588{
589    int n_stops;
590    pixman_gradient_stop_t *stops;
591    pixman_point_fixed_t inner_c, outer_c;
592    pixman_fixed_t inner_r, outer_r;
593    pixman_image_t *result;
594
595    inner_c = create_random_point();
596    outer_c = create_random_point();
597    inner_r = lcg_rand();
598    outer_r = lcg_rand();
599
600    stops = create_random_stops (&n_stops);
601
602    if (!stops)
603	return NULL;
604
605    result = pixman_image_create_radial_gradient (
606	&inner_c, &outer_c, inner_r, outer_r, stops, n_stops);
607
608    free (stops);
609
610    return result;
611}
612
613static pixman_image_t *
614create_random_conical_image (void)
615{
616    pixman_gradient_stop_t *stops;
617    int n_stops;
618    pixman_point_fixed_t c;
619    pixman_fixed_t angle;
620    pixman_image_t *result;
621
622    c = create_random_point();
623    angle = lcg_rand();
624
625    stops = create_random_stops (&n_stops);
626
627    if (!stops)
628	return NULL;
629
630    result = pixman_image_create_conical_gradient (&c, angle, stops, n_stops);
631
632    free (stops);
633
634    return result;
635}
636
637static pixman_image_t *
638create_random_image (void)
639{
640    pixman_image_t *result;
641
642    switch (lcg_rand_n (5))
643    {
644    default:
645    case 0:
646	result = create_random_bits_image ();
647	break;
648
649    case 1:
650	result = create_random_solid_image ();
651	break;
652
653    case 2:
654	result = create_random_linear_image ();
655	break;
656
657    case 3:
658	result = create_random_radial_image ();
659	break;
660
661    case 4:
662	result = create_random_conical_image ();
663	break;
664    }
665
666    if (result)
667	set_general_properties (result, TRUE);
668
669    return result;
670}
671
672static const pixman_op_t op_list[] =
673{
674    PIXMAN_OP_SRC,
675    PIXMAN_OP_OVER,
676    PIXMAN_OP_ADD,
677    PIXMAN_OP_CLEAR,
678    PIXMAN_OP_SRC,
679    PIXMAN_OP_DST,
680    PIXMAN_OP_OVER,
681    PIXMAN_OP_OVER_REVERSE,
682    PIXMAN_OP_IN,
683    PIXMAN_OP_IN_REVERSE,
684    PIXMAN_OP_OUT,
685    PIXMAN_OP_OUT_REVERSE,
686    PIXMAN_OP_ATOP,
687    PIXMAN_OP_ATOP_REVERSE,
688    PIXMAN_OP_XOR,
689    PIXMAN_OP_ADD,
690    PIXMAN_OP_SATURATE,
691    PIXMAN_OP_DISJOINT_CLEAR,
692    PIXMAN_OP_DISJOINT_SRC,
693    PIXMAN_OP_DISJOINT_DST,
694    PIXMAN_OP_DISJOINT_OVER,
695    PIXMAN_OP_DISJOINT_OVER_REVERSE,
696    PIXMAN_OP_DISJOINT_IN,
697    PIXMAN_OP_DISJOINT_IN_REVERSE,
698    PIXMAN_OP_DISJOINT_OUT,
699    PIXMAN_OP_DISJOINT_OUT_REVERSE,
700    PIXMAN_OP_DISJOINT_ATOP,
701    PIXMAN_OP_DISJOINT_ATOP_REVERSE,
702    PIXMAN_OP_DISJOINT_XOR,
703    PIXMAN_OP_CONJOINT_CLEAR,
704    PIXMAN_OP_CONJOINT_SRC,
705    PIXMAN_OP_CONJOINT_DST,
706    PIXMAN_OP_CONJOINT_OVER,
707    PIXMAN_OP_CONJOINT_OVER_REVERSE,
708    PIXMAN_OP_CONJOINT_IN,
709    PIXMAN_OP_CONJOINT_IN_REVERSE,
710    PIXMAN_OP_CONJOINT_OUT,
711    PIXMAN_OP_CONJOINT_OUT_REVERSE,
712    PIXMAN_OP_CONJOINT_ATOP,
713    PIXMAN_OP_CONJOINT_ATOP_REVERSE,
714    PIXMAN_OP_CONJOINT_XOR,
715    PIXMAN_OP_MULTIPLY,
716    PIXMAN_OP_SCREEN,
717    PIXMAN_OP_OVERLAY,
718    PIXMAN_OP_DARKEN,
719    PIXMAN_OP_LIGHTEN,
720    PIXMAN_OP_COLOR_DODGE,
721    PIXMAN_OP_COLOR_BURN,
722    PIXMAN_OP_HARD_LIGHT,
723    PIXMAN_OP_DIFFERENCE,
724    PIXMAN_OP_EXCLUSION,
725    PIXMAN_OP_SOFT_LIGHT,
726    PIXMAN_OP_HSL_HUE,
727    PIXMAN_OP_HSL_SATURATION,
728    PIXMAN_OP_HSL_COLOR,
729    PIXMAN_OP_HSL_LUMINOSITY,
730};
731
732static void
733run_test (uint32_t seed)
734{
735    pixman_image_t *source, *mask, *dest;
736    pixman_op_t op;
737
738    lcg_srand (seed);
739
740    source = create_random_image ();
741    mask   = create_random_image ();
742    dest   = create_random_bits_image ();
743
744    if (source && mask && dest)
745    {
746	set_general_properties (dest, TRUE);
747
748	op = op_list [lcg_rand_n (ARRAY_LENGTH (op_list))];
749
750	pixman_image_composite32 (op,
751				  source, mask, dest,
752				  log_rand(), log_rand(),
753				  log_rand(), log_rand(),
754				  log_rand(), log_rand(),
755				  absolute (log_rand()),
756				  absolute (log_rand()));
757    }
758    if (source)
759	pixman_image_unref (source);
760    if (mask)
761	pixman_image_unref (mask);
762    if (dest)
763	pixman_image_unref (dest);
764}
765
766static pixman_bool_t
767get_int (char *s, uint32_t *i)
768{
769    char *end;
770    int p;
771
772    p = strtol (s, &end, 0);
773
774    if (end != s && *end == 0)
775    {
776	*i = p;
777	return TRUE;
778    }
779
780    return FALSE;
781}
782
783int
784main (int argc, char **argv)
785{
786    int verbose = FALSE;
787    uint32_t seed = 1;
788    uint32_t n_tests = 0xffffffff;
789    uint32_t mod = 0;
790    uint32_t i;
791
792    pixman_disable_out_of_bounds_workaround ();
793
794    enable_fp_exceptions();
795
796    if (getenv ("VERBOSE") != NULL)
797	verbose = TRUE;
798
799    for (i = 1; i < argc; ++i)
800    {
801	if (strcmp (argv[i], "-v") == 0)
802	{
803	    verbose = TRUE;
804
805	    if (i + 1 < argc)
806	    {
807		get_int (argv[i + 1], &mod);
808		i++;
809	    }
810	}
811	else if (strcmp (argv[i], "-s") == 0 && i + 1 < argc)
812	{
813	    get_int (argv[i + 1], &seed);
814	    i++;
815	}
816	else if (strcmp (argv[i], "-n") == 0 && i + 1 < argc)
817	{
818	    get_int (argv[i + 1], &n_tests);
819	    i++;
820	}
821	else
822	{
823	    if (strcmp (argv[i], "-h") != 0)
824		printf ("Unknown option '%s'\n\n", argv[i]);
825
826	    printf ("Options:\n\n"
827		    "-n <number>        Number of tests to run\n"
828		    "-s <seed> 	        Seed of first test\n"
829		    "-v                 Print out seeds\n"
830		    "-v <n>             Print out every n'th seed\n\n");
831
832	    exit (-1);
833	}
834    }
835
836    if (n_tests == 0xffffffff)
837	n_tests = 8000;
838
839    /* FIXME: seed 2005763 fails in set_lum() with divide by zero */
840#ifdef USE_OPENMP
841#   pragma omp parallel for default(none) shared(verbose, n_tests, mod, seed)
842#endif
843    for (i = seed; i < seed + n_tests; ++i)
844    {
845	if (verbose)
846	{
847	    if (mod == 0 || (i % mod) == 0)
848		printf ("Seed %d\n", i);
849	}
850
851	run_test (i);
852    }
853
854    return 0;
855}
856