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