blitters-test.c revision 1b18d63a
1/*
2 * Test program, which stresses the use of different color formats and
3 * compositing operations.
4 *
5 * Script 'fuzzer-find-diff.pl' can be used to narrow down the problem in
6 * the case of test failure.
7 */
8#include <assert.h>
9#include <stdlib.h>
10#include <stdio.h>
11#include <config.h>
12#include "utils.h"
13
14static pixman_indexed_t rgb_palette[9];
15static pixman_indexed_t y_palette[9];
16
17/* Create random image for testing purposes */
18static pixman_image_t *
19create_random_image (pixman_format_code_t *allowed_formats,
20		     int                   max_width,
21		     int                   max_height,
22		     int                   max_extra_stride,
23		     pixman_format_code_t *used_fmt)
24{
25    int n = 0, i, width, height, stride;
26    pixman_format_code_t fmt;
27    uint32_t *buf;
28    pixman_image_t *img;
29
30    while (allowed_formats[n] != -1)
31	n++;
32    fmt = allowed_formats[lcg_rand_n (n)];
33
34    width = lcg_rand_n (max_width) + 1;
35    height = lcg_rand_n (max_height) + 1;
36    stride = (width * PIXMAN_FORMAT_BPP (fmt) + 7) / 8 +
37	lcg_rand_n (max_extra_stride + 1);
38    stride = (stride + 3) & ~3;
39
40    /* do the allocation */
41    buf = aligned_malloc (64, stride * height);
42
43    /* initialize image with random data */
44    for (i = 0; i < stride * height; i++)
45    {
46	/* generation is biased to having more 0 or 255 bytes as
47	 * they are more likely to be special-cased in code
48	 */
49	*((uint8_t *)buf + i) = lcg_rand_n (4) ? lcg_rand_n (256) :
50	    (lcg_rand_n (2) ? 0 : 255);
51    }
52
53    img = pixman_image_create_bits (fmt, width, height, buf, stride);
54
55    if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_COLOR)
56    {
57	pixman_image_set_indexed (img, &(rgb_palette[PIXMAN_FORMAT_BPP (fmt)]));
58    }
59    else if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_GRAY)
60    {
61	pixman_image_set_indexed (img, &(y_palette[PIXMAN_FORMAT_BPP (fmt)]));
62    }
63
64    image_endian_swap (img, PIXMAN_FORMAT_BPP (fmt));
65
66    if (used_fmt) *used_fmt = fmt;
67    return img;
68}
69
70/* Free random image, and optionally update crc32 based on its data */
71static uint32_t
72free_random_image (uint32_t initcrc,
73		   pixman_image_t *img,
74		   pixman_format_code_t fmt)
75{
76    uint32_t crc32 = 0;
77    int stride = pixman_image_get_stride (img);
78    uint32_t *data = pixman_image_get_data (img);
79    int height = pixman_image_get_height (img);
80
81    if (fmt != -1)
82    {
83	/* mask unused 'x' part */
84	if (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt) &&
85	    PIXMAN_FORMAT_DEPTH (fmt) != 0)
86	{
87	    int i;
88	    uint32_t *data = pixman_image_get_data (img);
89	    uint32_t mask = (1 << PIXMAN_FORMAT_DEPTH (fmt)) - 1;
90
91	    if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA)
92		mask <<= (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt));
93
94	    for (i = 0; i < 32; i++)
95		mask |= mask << (i * PIXMAN_FORMAT_BPP (fmt));
96
97	    for (i = 0; i < stride * height / 4; i++)
98		data[i] &= mask;
99	}
100
101	/* swap endiannes in order to provide identical results on both big
102	 * and litte endian systems
103	 */
104	image_endian_swap (img, PIXMAN_FORMAT_BPP (fmt));
105	crc32 = compute_crc32 (initcrc, data, stride * height);
106    }
107
108    pixman_image_unref (img);
109    free (data);
110
111    return crc32;
112}
113
114static pixman_op_t op_list[] = {
115    PIXMAN_OP_SRC,
116    PIXMAN_OP_OVER,
117    PIXMAN_OP_ADD,
118    PIXMAN_OP_CLEAR,
119    PIXMAN_OP_SRC,
120    PIXMAN_OP_DST,
121    PIXMAN_OP_OVER,
122    PIXMAN_OP_OVER_REVERSE,
123    PIXMAN_OP_IN,
124    PIXMAN_OP_IN_REVERSE,
125    PIXMAN_OP_OUT,
126    PIXMAN_OP_OUT_REVERSE,
127    PIXMAN_OP_ATOP,
128    PIXMAN_OP_ATOP_REVERSE,
129    PIXMAN_OP_XOR,
130    PIXMAN_OP_ADD,
131    PIXMAN_OP_SATURATE,
132    PIXMAN_OP_DISJOINT_CLEAR,
133    PIXMAN_OP_DISJOINT_SRC,
134    PIXMAN_OP_DISJOINT_DST,
135    PIXMAN_OP_DISJOINT_OVER,
136    PIXMAN_OP_DISJOINT_OVER_REVERSE,
137    PIXMAN_OP_DISJOINT_IN,
138    PIXMAN_OP_DISJOINT_IN_REVERSE,
139    PIXMAN_OP_DISJOINT_OUT,
140    PIXMAN_OP_DISJOINT_OUT_REVERSE,
141    PIXMAN_OP_DISJOINT_ATOP,
142    PIXMAN_OP_DISJOINT_ATOP_REVERSE,
143    PIXMAN_OP_DISJOINT_XOR,
144    PIXMAN_OP_CONJOINT_CLEAR,
145    PIXMAN_OP_CONJOINT_SRC,
146    PIXMAN_OP_CONJOINT_DST,
147    PIXMAN_OP_CONJOINT_OVER,
148    PIXMAN_OP_CONJOINT_OVER_REVERSE,
149    PIXMAN_OP_CONJOINT_IN,
150    PIXMAN_OP_CONJOINT_IN_REVERSE,
151    PIXMAN_OP_CONJOINT_OUT,
152    PIXMAN_OP_CONJOINT_OUT_REVERSE,
153    PIXMAN_OP_CONJOINT_ATOP,
154    PIXMAN_OP_CONJOINT_ATOP_REVERSE,
155    PIXMAN_OP_CONJOINT_XOR,
156    PIXMAN_OP_MULTIPLY,
157    PIXMAN_OP_SCREEN,
158    PIXMAN_OP_OVERLAY,
159    PIXMAN_OP_DARKEN,
160    PIXMAN_OP_LIGHTEN,
161    PIXMAN_OP_COLOR_DODGE,
162    PIXMAN_OP_COLOR_BURN,
163    PIXMAN_OP_HARD_LIGHT,
164    PIXMAN_OP_DIFFERENCE,
165    PIXMAN_OP_EXCLUSION,
166#if 0 /* these use floating point math and are not always bitexact on different platforms */
167    PIXMAN_OP_SOFT_LIGHT,
168    PIXMAN_OP_HSL_HUE,
169    PIXMAN_OP_HSL_SATURATION,
170    PIXMAN_OP_HSL_COLOR,
171    PIXMAN_OP_HSL_LUMINOSITY,
172#endif
173};
174
175static pixman_format_code_t img_fmt_list[] = {
176    PIXMAN_a8r8g8b8,
177    PIXMAN_x8r8g8b8,
178    PIXMAN_r5g6b5,
179    PIXMAN_r3g3b2,
180    PIXMAN_a8,
181    PIXMAN_a8b8g8r8,
182    PIXMAN_x8b8g8r8,
183    PIXMAN_b8g8r8a8,
184    PIXMAN_b8g8r8x8,
185    PIXMAN_x14r6g6b6,
186    PIXMAN_r8g8b8,
187    PIXMAN_b8g8r8,
188    PIXMAN_r5g6b5,
189    PIXMAN_b5g6r5,
190    PIXMAN_x2r10g10b10,
191    PIXMAN_a2r10g10b10,
192    PIXMAN_x2b10g10r10,
193    PIXMAN_a2b10g10r10,
194    PIXMAN_a1r5g5b5,
195    PIXMAN_x1r5g5b5,
196    PIXMAN_a1b5g5r5,
197    PIXMAN_x1b5g5r5,
198    PIXMAN_a4r4g4b4,
199    PIXMAN_x4r4g4b4,
200    PIXMAN_a4b4g4r4,
201    PIXMAN_x4b4g4r4,
202    PIXMAN_a8,
203    PIXMAN_r3g3b2,
204    PIXMAN_b2g3r3,
205    PIXMAN_a2r2g2b2,
206    PIXMAN_a2b2g2r2,
207    PIXMAN_c8,
208    PIXMAN_g8,
209    PIXMAN_x4c4,
210    PIXMAN_x4g4,
211    PIXMAN_c4,
212    PIXMAN_g4,
213    PIXMAN_g1,
214    PIXMAN_x4a4,
215    PIXMAN_a4,
216    PIXMAN_r1g2b1,
217    PIXMAN_b1g2r1,
218    PIXMAN_a1r1g1b1,
219    PIXMAN_a1b1g1r1,
220    PIXMAN_a1,
221    -1
222};
223
224static pixman_format_code_t mask_fmt_list[] = {
225    PIXMAN_a8r8g8b8,
226    PIXMAN_a8,
227    PIXMAN_a4,
228    PIXMAN_a1,
229    -1
230};
231
232
233/*
234 * Composite operation with pseudorandom images
235 */
236uint32_t
237test_composite (int testnum, int verbose)
238{
239    int i;
240    pixman_image_t *src_img = NULL;
241    pixman_image_t *dst_img = NULL;
242    pixman_image_t *mask_img = NULL;
243    int src_width, src_height;
244    int dst_width, dst_height;
245    int src_stride, dst_stride;
246    int src_x, src_y;
247    int dst_x, dst_y;
248    int mask_x, mask_y;
249    int w, h;
250    int op;
251    pixman_format_code_t src_fmt, dst_fmt, mask_fmt;
252    uint32_t *dstbuf, *srcbuf, *maskbuf;
253    uint32_t crc32;
254    int max_width, max_height, max_extra_stride;
255    FLOAT_REGS_CORRUPTION_DETECTOR_START ();
256
257    max_width = max_height = 24 + testnum / 10000;
258    max_extra_stride = 4 + testnum / 1000000;
259
260    if (max_width > 256)
261	max_width = 256;
262
263    if (max_height > 16)
264	max_height = 16;
265
266    if (max_extra_stride > 8)
267	max_extra_stride = 8;
268
269    lcg_srand (testnum);
270
271    op = op_list[lcg_rand_n (sizeof (op_list) / sizeof (op_list[0]))];
272
273    if (lcg_rand_n (8))
274    {
275	/* normal image */
276	src_img = create_random_image (img_fmt_list, max_width, max_height,
277				       max_extra_stride, &src_fmt);
278    }
279    else
280    {
281	/* solid case */
282	src_img = create_random_image (img_fmt_list, 1, 1,
283				       max_extra_stride, &src_fmt);
284
285	pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NORMAL);
286    }
287
288    dst_img = create_random_image (img_fmt_list, max_width, max_height,
289				   max_extra_stride, &dst_fmt);
290
291    src_width = pixman_image_get_width (src_img);
292    src_height = pixman_image_get_height (src_img);
293    src_stride = pixman_image_get_stride (src_img);
294
295    dst_width = pixman_image_get_width (dst_img);
296    dst_height = pixman_image_get_height (dst_img);
297    dst_stride = pixman_image_get_stride (dst_img);
298
299    dstbuf = pixman_image_get_data (dst_img);
300    srcbuf = pixman_image_get_data (src_img);
301
302    src_x = lcg_rand_n (src_width);
303    src_y = lcg_rand_n (src_height);
304    dst_x = lcg_rand_n (dst_width);
305    dst_y = lcg_rand_n (dst_height);
306
307    mask_img = NULL;
308    mask_fmt = -1;
309    mask_x = 0;
310    mask_y = 0;
311    maskbuf = NULL;
312
313    if ((src_fmt == PIXMAN_x8r8g8b8 || src_fmt == PIXMAN_x8b8g8r8) &&
314	(lcg_rand_n (4) == 0))
315    {
316	/* PIXBUF */
317	mask_fmt = lcg_rand_n (2) ? PIXMAN_a8r8g8b8 : PIXMAN_a8b8g8r8;
318	mask_img = pixman_image_create_bits (mask_fmt,
319	                                     src_width,
320	                                     src_height,
321	                                     srcbuf,
322	                                     src_stride);
323	mask_x = src_x;
324	mask_y = src_y;
325	maskbuf = srcbuf;
326    }
327    else if (lcg_rand_n (2))
328    {
329	if (lcg_rand_n (2))
330	{
331	    mask_img = create_random_image (mask_fmt_list, max_width, max_height,
332					   max_extra_stride, &mask_fmt);
333	}
334	else
335	{
336	    /* solid case */
337	    mask_img = create_random_image (mask_fmt_list, 1, 1,
338					   max_extra_stride, &mask_fmt);
339	    pixman_image_set_repeat (mask_img, PIXMAN_REPEAT_NORMAL);
340	}
341
342	if (lcg_rand_n (2))
343	    pixman_image_set_component_alpha (mask_img, 1);
344
345	mask_x = lcg_rand_n (pixman_image_get_width (mask_img));
346	mask_y = lcg_rand_n (pixman_image_get_height (mask_img));
347    }
348
349
350    w = lcg_rand_n (dst_width - dst_x + 1);
351    h = lcg_rand_n (dst_height - dst_y + 1);
352
353    if (verbose)
354    {
355	printf ("op=%d, src_fmt=%08X, dst_fmt=%08X, mask_fmt=%08X\n",
356	    op, src_fmt, dst_fmt, mask_fmt);
357	printf ("src_width=%d, src_height=%d, dst_width=%d, dst_height=%d\n",
358	    src_width, src_height, dst_width, dst_height);
359	printf ("src_x=%d, src_y=%d, dst_x=%d, dst_y=%d\n",
360	    src_x, src_y, dst_x, dst_y);
361	printf ("src_stride=%d, dst_stride=%d\n",
362	    src_stride, dst_stride);
363	printf ("w=%d, h=%d\n", w, h);
364    }
365
366    pixman_image_composite (op, src_img, mask_img, dst_img,
367			    src_x, src_y, mask_x, mask_y, dst_x, dst_y, w, h);
368
369    if (verbose)
370    {
371	int j;
372
373	printf ("---\n");
374	for (i = 0; i < dst_height; i++)
375	{
376	    for (j = 0; j < dst_stride; j++)
377	    {
378		if (j == (dst_width * PIXMAN_FORMAT_BPP (dst_fmt) + 7) / 8)
379		    printf ("| ");
380
381		printf ("%02X ", *((uint8_t *)dstbuf + i * dst_stride + j));
382	    }
383	    printf ("\n");
384	}
385	printf ("---\n");
386    }
387
388    free_random_image (0, src_img, -1);
389    crc32 = free_random_image (0, dst_img, dst_fmt);
390
391    if (mask_img)
392    {
393	if (srcbuf == maskbuf)
394	    pixman_image_unref(mask_img);
395	else
396	    free_random_image (0, mask_img, -1);
397    }
398
399    FLOAT_REGS_CORRUPTION_DETECTOR_FINISH ();
400    return crc32;
401}
402
403#define CONVERT_15(c, is_rgb)						\
404    (is_rgb?								\
405     ((((c) >> 3) & 0x001f) |						\
406      (((c) >> 6) & 0x03e0) |						\
407      (((c) >> 9) & 0x7c00)) :						\
408     (((((c) >> 16) & 0xff) * 153 +					\
409       (((c) >>  8) & 0xff) * 301 +					\
410       (((c)      ) & 0xff) * 58) >> 2))
411
412static void
413initialize_palette (pixman_indexed_t *palette, uint32_t mask, int is_rgb)
414{
415    int i;
416
417    for (i = 0; i < 32768; ++i)
418	palette->ent[i] = lcg_rand() & mask;
419
420    for (i = 0; i < mask + 1; ++i)
421    {
422	uint32_t rgba24;
423 	pixman_bool_t retry;
424	uint32_t i15;
425
426	/* We filled the rgb->index map with random numbers, but we
427	 * do need the ability to round trip, that is if some indexed
428	 * color expands to an argb24, then the 15 bit version of that
429	 * color must map back to the index. Anything else, we don't
430	 * care about too much.
431	 */
432	do
433	{
434	    uint32_t old_idx;
435
436	    rgba24 = lcg_rand();
437	    i15 = CONVERT_15 (rgba24, is_rgb);
438
439	    old_idx = palette->ent[i15];
440	    if (CONVERT_15 (palette->rgba[old_idx], is_rgb) == i15)
441		retry = 1;
442	    else
443		retry = 0;
444	} while (retry);
445
446	palette->rgba[i] = rgba24;
447	palette->ent[i15] = i;
448    }
449
450    for (i = 0; i < mask + 1; ++i)
451    {
452	assert (palette->ent[CONVERT_15 (palette->rgba[i], is_rgb)] == i);
453    }
454}
455
456int
457main (int argc, const char *argv[])
458{
459    int i;
460
461    for (i = 1; i <= 8; i++)
462    {
463	initialize_palette (&(rgb_palette[i]), (1 << i) - 1, TRUE);
464	initialize_palette (&(y_palette[i]), (1 << i) - 1, FALSE);
465    }
466
467    return fuzzer_test_main("blitters", 2000000,
468			    0x1DB8BDF8,
469			    test_composite, argc, argv);
470}
471