test: Move random number generator from blitters/scaling-test to utils.[ch]
[profile/ivi/pixman.git] / test / blitters-test.c
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
30 /* A primitive pseudorandom number generator, taken from POSIX.1-2001 example */
31
32 static void *
33 aligned_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 /* perform endian conversion of pixel data */
48 static void
49 image_endian_swap (pixman_image_t *img, int bpp)
50 {
51     int stride = pixman_image_get_stride (img);
52     uint32_t *data = pixman_image_get_data (img);
53     int height = pixman_image_get_height (img);
54     int i, j;
55
56     /* swap bytes only on big endian systems */
57     volatile uint16_t endian_check_var = 0x1234;
58     if (*(volatile uint8_t *)&endian_check_var != 0x12)
59         return;
60
61     for (i = 0; i < height; i++)
62     {
63         uint8_t *line_data = (uint8_t *)data + stride * i;
64         /* swap bytes only for 16, 24 and 32 bpp for now */
65         switch (bpp)
66         {
67         case 1:
68             for (j = 0; j < stride; j++)
69             {
70                 line_data[j] =
71                     ((line_data[j] & 0x80) >> 7) |
72                     ((line_data[j] & 0x40) >> 5) |
73                     ((line_data[j] & 0x20) >> 3) |
74                     ((line_data[j] & 0x10) >> 1) |
75                     ((line_data[j] & 0x08) << 1) |
76                     ((line_data[j] & 0x04) << 3) |
77                     ((line_data[j] & 0x02) << 5) |
78                     ((line_data[j] & 0x01) << 7);
79             }
80             break;
81         case 4:
82             for (j = 0; j < stride; j++)
83             {
84                 line_data[j] = (line_data[j] >> 4) | (line_data[j] << 4);
85             }
86             break;
87         case 16:
88             for (j = 0; j + 2 <= stride; j += 2)
89             {
90                 char t1 = line_data[j + 0];
91                 char t2 = line_data[j + 1];
92
93                 line_data[j + 1] = t1;
94                 line_data[j + 0] = t2;
95             }
96             break;
97         case 24:
98             for (j = 0; j + 3 <= stride; j += 3)
99             {
100                 char t1 = line_data[j + 0];
101                 char t2 = line_data[j + 1];
102                 char t3 = line_data[j + 2];
103
104                 line_data[j + 2] = t1;
105                 line_data[j + 1] = t2;
106                 line_data[j + 0] = t3;
107             }
108             break;
109         case 32:
110             for (j = 0; j + 4 <= stride; j += 4)
111             {
112                 char t1 = line_data[j + 0];
113                 char t2 = line_data[j + 1];
114                 char t3 = line_data[j + 2];
115                 char t4 = line_data[j + 3];
116
117                 line_data[j + 3] = t1;
118                 line_data[j + 2] = t2;
119                 line_data[j + 1] = t3;
120                 line_data[j + 0] = t4;
121             }
122             break;
123         default:
124             break;
125         }
126     }
127 }
128
129 /* Create random image for testing purposes */
130 static pixman_image_t *
131 create_random_image (pixman_format_code_t *allowed_formats,
132                      int                   max_width,
133                      int                   max_height,
134                      int                   max_extra_stride,
135                      pixman_format_code_t *used_fmt)
136 {
137     int n = 0, i, width, height, stride;
138     pixman_format_code_t fmt;
139     uint32_t *buf;
140     pixman_image_t *img;
141
142     while (allowed_formats[n] != -1)
143         n++;
144     fmt = allowed_formats[lcg_rand_n (n)];
145     width = lcg_rand_n (max_width) + 1;
146     height = lcg_rand_n (max_height) + 1;
147     stride = (width * PIXMAN_FORMAT_BPP (fmt) + 7) / 8 +
148         lcg_rand_n (max_extra_stride + 1);
149     stride = (stride + 3) & ~3;
150
151     /* do the allocation */
152     buf = aligned_malloc (64, stride * height);
153
154     /* initialize image with random data */
155     for (i = 0; i < stride * height; i++)
156     {
157         /* generation is biased to having more 0 or 255 bytes as
158          * they are more likely to be special-cased in code
159          */
160         *((uint8_t *)buf + i) = lcg_rand_n (4) ? lcg_rand_n (256) :
161             (lcg_rand_n (2) ? 0 : 255);
162     }
163
164     img = pixman_image_create_bits (fmt, width, height, buf, stride);
165
166     image_endian_swap (img, PIXMAN_FORMAT_BPP (fmt));
167
168     if (used_fmt) *used_fmt = fmt;
169     return img;
170 }
171
172 /* Free random image, and optionally update crc32 based on its data */
173 static uint32_t
174 free_random_image (uint32_t initcrc,
175                    pixman_image_t *img,
176                    pixman_format_code_t fmt)
177 {
178     uint32_t crc32 = 0;
179     int stride = pixman_image_get_stride (img);
180     uint32_t *data = pixman_image_get_data (img);
181     int height = pixman_image_get_height (img);;
182
183     if (fmt != -1)
184     {
185         /* mask unused 'x' part */
186         if (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt) &&
187             PIXMAN_FORMAT_DEPTH (fmt) != 0)
188         {
189             int i;
190             uint32_t *data = pixman_image_get_data (img);
191             uint32_t mask = (1 << PIXMAN_FORMAT_DEPTH (fmt)) - 1;
192
193             if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA)
194                 mask <<= (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt));
195
196             for (i = 0; i < 32; i++)
197                 mask |= mask << (i * PIXMAN_FORMAT_BPP (fmt));
198
199             for (i = 0; i < stride * height / 4; i++)
200                 data[i] &= mask;
201         }
202
203         /* swap endiannes in order to provide identical results on both big
204          * and litte endian systems
205          */
206         image_endian_swap (img, PIXMAN_FORMAT_BPP (fmt));
207         crc32 = compute_crc32 (initcrc, data, stride * height);
208     }
209
210     pixman_image_unref (img);
211     free (data);
212
213     return crc32;
214 }
215
216 static pixman_op_t op_list[] = {
217     PIXMAN_OP_SRC,
218     PIXMAN_OP_OVER,
219     PIXMAN_OP_ADD,
220     PIXMAN_OP_CLEAR,
221     PIXMAN_OP_SRC,
222     PIXMAN_OP_DST,
223     PIXMAN_OP_OVER,
224     PIXMAN_OP_OVER_REVERSE,
225     PIXMAN_OP_IN,
226     PIXMAN_OP_IN_REVERSE,
227     PIXMAN_OP_OUT,
228     PIXMAN_OP_OUT_REVERSE,
229     PIXMAN_OP_ATOP,
230     PIXMAN_OP_ATOP_REVERSE,
231     PIXMAN_OP_XOR,
232     PIXMAN_OP_ADD,
233     PIXMAN_OP_SATURATE,
234     PIXMAN_OP_DISJOINT_CLEAR,
235     PIXMAN_OP_DISJOINT_SRC,
236     PIXMAN_OP_DISJOINT_DST,
237     PIXMAN_OP_DISJOINT_OVER,
238     PIXMAN_OP_DISJOINT_OVER_REVERSE,
239     PIXMAN_OP_DISJOINT_IN,
240     PIXMAN_OP_DISJOINT_IN_REVERSE,
241     PIXMAN_OP_DISJOINT_OUT,
242     PIXMAN_OP_DISJOINT_OUT_REVERSE,
243     PIXMAN_OP_DISJOINT_ATOP,
244     PIXMAN_OP_DISJOINT_ATOP_REVERSE,
245     PIXMAN_OP_DISJOINT_XOR,
246     PIXMAN_OP_CONJOINT_CLEAR,
247     PIXMAN_OP_CONJOINT_SRC,
248     PIXMAN_OP_CONJOINT_DST,
249     PIXMAN_OP_CONJOINT_OVER,
250     PIXMAN_OP_CONJOINT_OVER_REVERSE,
251     PIXMAN_OP_CONJOINT_IN,
252     PIXMAN_OP_CONJOINT_IN_REVERSE,
253     PIXMAN_OP_CONJOINT_OUT,
254     PIXMAN_OP_CONJOINT_OUT_REVERSE,
255     PIXMAN_OP_CONJOINT_ATOP,
256     PIXMAN_OP_CONJOINT_ATOP_REVERSE,
257     PIXMAN_OP_CONJOINT_XOR,
258     PIXMAN_OP_MULTIPLY,
259     PIXMAN_OP_SCREEN,
260     PIXMAN_OP_OVERLAY,
261     PIXMAN_OP_DARKEN,
262     PIXMAN_OP_LIGHTEN,
263     PIXMAN_OP_COLOR_DODGE,
264     PIXMAN_OP_COLOR_BURN,
265     PIXMAN_OP_HARD_LIGHT,
266     PIXMAN_OP_DIFFERENCE,
267     PIXMAN_OP_EXCLUSION,
268 #if 0 /* these use floating point math and are not always bitexact on different platforms */
269     PIXMAN_OP_SOFT_LIGHT,
270     PIXMAN_OP_HSL_HUE,
271     PIXMAN_OP_HSL_SATURATION,
272     PIXMAN_OP_HSL_COLOR,
273     PIXMAN_OP_HSL_LUMINOSITY,
274 #endif
275 };
276
277 static pixman_format_code_t img_fmt_list[] = {
278     PIXMAN_a8r8g8b8,
279     PIXMAN_x8r8g8b8,
280     PIXMAN_r5g6b5,
281     PIXMAN_r3g3b2,
282     PIXMAN_a8,
283     PIXMAN_a8b8g8r8,
284     PIXMAN_x8b8g8r8,
285     PIXMAN_b8g8r8a8,
286     PIXMAN_b8g8r8x8,
287     PIXMAN_r8g8b8,
288     PIXMAN_b8g8r8,
289     PIXMAN_r5g6b5,
290     PIXMAN_b5g6r5,
291     PIXMAN_x2r10g10b10,
292     PIXMAN_a2r10g10b10,
293     PIXMAN_x2b10g10r10,
294     PIXMAN_a2b10g10r10,
295     PIXMAN_a1r5g5b5,
296     PIXMAN_x1r5g5b5,
297     PIXMAN_a1b5g5r5,
298     PIXMAN_x1b5g5r5,
299     PIXMAN_a4r4g4b4,
300     PIXMAN_x4r4g4b4,
301     PIXMAN_a4b4g4r4,
302     PIXMAN_x4b4g4r4,
303     PIXMAN_a8,
304     PIXMAN_r3g3b2,
305     PIXMAN_b2g3r3,
306     PIXMAN_a2r2g2b2,
307     PIXMAN_a2b2g2r2,
308 #if 0 /* using these crashes the test */
309     PIXMAN_c8,
310     PIXMAN_g8,
311     PIXMAN_x4c4,
312     PIXMAN_x4g4,
313     PIXMAN_c4,
314     PIXMAN_g4,
315     PIXMAN_g1,
316 #endif
317     PIXMAN_x4a4,
318     PIXMAN_a4,
319     PIXMAN_r1g2b1,
320     PIXMAN_b1g2r1,
321     PIXMAN_a1r1g1b1,
322     PIXMAN_a1b1g1r1,
323     PIXMAN_a1,
324     -1
325 };
326
327 static pixman_format_code_t mask_fmt_list[] = {
328     PIXMAN_a8r8g8b8,
329     PIXMAN_a8,
330     PIXMAN_a4,
331     PIXMAN_a1,
332     -1
333 };
334
335
336 /*
337  * Composite operation with pseudorandom images
338  */
339 uint32_t
340 test_composite (uint32_t initcrc, int testnum, int verbose)
341 {
342     int i;
343     pixman_image_t *src_img = NULL;
344     pixman_image_t *dst_img = NULL;
345     pixman_image_t *mask_img = NULL;
346     int src_width, src_height;
347     int dst_width, dst_height;
348     int src_stride, dst_stride;
349     int src_x, src_y;
350     int dst_x, dst_y;
351     int mask_x, mask_y;
352     int w, h;
353     int op;
354     pixman_format_code_t src_fmt, dst_fmt, mask_fmt;
355     uint32_t *dstbuf;
356     uint32_t crc32;
357     int max_width, max_height, max_extra_stride;
358
359     max_width = max_height = 24 + testnum / 10000;
360     max_extra_stride = 4 + testnum / 1000000;
361
362     if (max_width > 256)
363         max_width = 256;
364
365     if (max_height > 16)
366         max_height = 16;
367
368     if (max_extra_stride > 8)
369         max_extra_stride = 8;
370
371     lcg_srand (testnum);
372
373     op = op_list[lcg_rand_n (sizeof (op_list) / sizeof (op_list[0]))];
374
375     if (lcg_rand_n (8))
376     {
377         /* normal image */
378         src_img = create_random_image (img_fmt_list, max_width, max_height,
379                                        max_extra_stride, &src_fmt);
380     }
381     else
382     {
383         /* solid case */
384         src_img = create_random_image (img_fmt_list, 1, 1,
385                                        max_extra_stride, &src_fmt);
386
387         pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NORMAL);
388     }
389
390     dst_img = create_random_image (img_fmt_list, max_width, max_height,
391                                    max_extra_stride, &dst_fmt);
392
393     mask_img = NULL;
394     mask_fmt = -1;
395     mask_x = 0;
396     mask_y = 0;
397
398     if (lcg_rand_n (2))
399     {
400         if (lcg_rand_n (2))
401         {
402             mask_img = create_random_image (mask_fmt_list, max_width, max_height,
403                                            max_extra_stride, &mask_fmt);
404         }
405         else
406         {
407             /* solid case */
408             mask_img = create_random_image (mask_fmt_list, 1, 1,
409                                            max_extra_stride, &mask_fmt);
410             pixman_image_set_repeat (mask_img, PIXMAN_REPEAT_NORMAL);
411         }
412
413         if (lcg_rand_n (2))
414             pixman_image_set_component_alpha (mask_img, 1);
415
416         mask_x = lcg_rand_n (pixman_image_get_width (mask_img));
417         mask_y = lcg_rand_n (pixman_image_get_height (mask_img));
418     }
419
420     src_width = pixman_image_get_width (src_img);
421     src_height = pixman_image_get_height (src_img);
422     src_stride = pixman_image_get_stride (src_img);
423
424     dst_width = pixman_image_get_width (dst_img);
425     dst_height = pixman_image_get_height (dst_img);
426     dst_stride = pixman_image_get_stride (dst_img);
427
428     dstbuf = pixman_image_get_data (dst_img);
429
430     src_x = lcg_rand_n (src_width);
431     src_y = lcg_rand_n (src_height);
432     dst_x = lcg_rand_n (dst_width);
433     dst_y = lcg_rand_n (dst_height);
434
435     w = lcg_rand_n (dst_width - dst_x + 1);
436     h = lcg_rand_n (dst_height - dst_y + 1);
437
438     if (verbose)
439     {
440         printf ("op=%d, src_fmt=%08X, dst_fmt=%08X, mask_fmt=%08X\n",
441             op, src_fmt, dst_fmt, mask_fmt);
442         printf ("src_width=%d, src_height=%d, dst_width=%d, dst_height=%d\n",
443             src_width, src_height, dst_width, dst_height);
444         printf ("src_x=%d, src_y=%d, dst_x=%d, dst_y=%d\n",
445             src_x, src_y, dst_x, dst_y);
446         printf ("src_stride=%d, dst_stride=%d\n",
447             src_stride, dst_stride);
448         printf ("w=%d, h=%d\n", w, h);
449     }
450
451     pixman_image_composite (op, src_img, mask_img, dst_img,
452                             src_x, src_y, mask_x, mask_y, dst_x, dst_y, w, h);
453
454     if (verbose)
455     {
456         int j;
457
458         printf ("---\n");
459         for (i = 0; i < dst_height; i++)
460         {
461             for (j = 0; j < dst_stride; j++)
462             {
463                 if (j == (dst_width * PIXMAN_FORMAT_BPP (dst_fmt) + 7) / 8)
464                     printf ("| ");
465
466                 printf ("%02X ", *((uint8_t *)dstbuf + i * dst_stride + j));
467             }
468             printf ("\n");
469         }
470         printf ("---\n");
471     }
472
473     free_random_image (initcrc, src_img, -1);
474     crc32 = free_random_image (initcrc, dst_img, dst_fmt);
475
476     if (mask_img)
477         free_random_image (initcrc, mask_img, -1);
478
479     return crc32;
480 }
481
482 int
483 main (int argc, char *argv[])
484 {
485     int i, n1 = 1, n2 = 0;
486     uint32_t crc = 0;
487     int verbose = getenv ("VERBOSE") != NULL;
488
489     if (argc >= 3)
490     {
491         n1 = atoi (argv[1]);
492         n2 = atoi (argv[2]);
493     }
494     else if (argc >= 2)
495     {
496         n2 = atoi (argv[1]);
497     }
498     else
499     {
500         n1 = 1;
501         n2 = 2000000;
502     }
503
504     if (n2 < 0)
505     {
506         crc = test_composite (0, abs (n2), 1);
507         printf ("crc32=%08X\n", crc);
508     }
509     else
510     {
511         for (i = n1; i <= n2; i++)
512         {
513             crc = test_composite (crc, i, 0);
514
515             if (verbose)
516                 printf ("%d: %08X\n", i, crc);
517         }
518         printf ("crc32=%08X\n", crc);
519
520         if (n2 == 2000000)
521         {
522             /* Predefined value for running with all the fastpath functions
523                disabled. It needs to be updated every time when changes are
524                introduced to this program or behavior of pixman changes! */
525             if (crc == 0x1911E2C3)
526             {
527                 printf ("blitters test passed\n");
528             }
529             else
530             {
531                 printf ("blitters test failed!\n");
532                 return 1;
533             }
534         }
535     }
536     return 0;
537 }