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