Don't consider indexed formats opaque.
[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 static pixman_indexed_t palette;
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
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 */
98 static uint32_t
99 free_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
141 static 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
202 static 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
250 static 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  */
262 uint32_t
263 test_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
428 static void
429 initialize_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
440 int
441 main (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 == 0x8F9F7DC1)
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 }