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