scaling-test.c revision d0321353
1/*
2 * Test program, which can detect problems with nearest neighbout scaling
3 * implementation. Also SRC and OVER opetations tested for 16bpp and 32bpp
4 * images.
5 *
6 * Just run it without any command line arguments, and it will report either
7 *   "scaling test passed" - everything is ok
8 *   "scaling test failed!" - there is some problem
9 *
10 * In the case of failure, finding the problem involves the following steps:
11 * 1. Get the reference 'scaling-test' binary. It makes sense to disable all
12 *    the cpu specific optimizations in pixman and also configure it with
13 *    '--disable-shared' option. Those who are paranoid can also tweak the
14 *    sources to disable all fastpath functions. The resulting binary
15 *    can be renamed to something like 'scaling-test.ref'.
16 * 2. Compile the buggy binary (also with the '--disable-shared' option).
17 * 3. Run 'ruby scaling-test-bisect.rb ./scaling-test.ref ./scaling-test'
18 * 4. Look at the information about failed case (destination buffer content
19 *    will be shown) and try to figure out what is wrong. It is possible
20 *    to use debugging print to stderr in pixman to get more information,
21 *    this does not interfere with the testing script.
22 */
23#include <assert.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include "pixman.h"
27
28/* A primitive pseudorandom number generator, taken from POSIX.1-2001 example */
29
30static uint32_t lcg_seed;
31
32uint32_t
33lcg_rand (void)
34{
35    lcg_seed = lcg_seed * 1103515245 + 12345;
36    return ((uint32_t)(lcg_seed / 65536) % 32768);
37}
38
39void
40lcg_srand (uint32_t seed)
41{
42    lcg_seed = seed;
43}
44
45uint32_t
46lcg_rand_n (int max)
47{
48    return lcg_rand () % max;
49}
50
51/*----------------------------------------------------------------------------*\
52*  CRC-32 version 2.0.0 by Craig Bruce, 2006-04-29.
53*
54*  This program generates the CRC-32 values for the files named in the
55*  command-line arguments.  These are the same CRC-32 values used by GZIP,
56*  PKZIP, and ZMODEM.  The compute_crc32() can also be detached and
57*  used independently.
58*
59*  THIS PROGRAM IS PUBLIC-DOMAIN SOFTWARE.
60*
61*  Based on the byte-oriented implementation "File Verification Using CRC"
62*  by Mark R. Nelson in Dr. Dobb's Journal, May 1992, pp. 64-67.
63*
64*  v1.0.0: original release.
65*  v1.0.1: fixed printf formats.
66*  v1.0.2: fixed something else.
67*  v1.0.3: replaced CRC constant table by generator function.
68*  v1.0.4: reformatted code, made ANSI C.  1994-12-05.
69*  v2.0.0: rewrote to use memory buffer & static table, 2006-04-29.
70\*----------------------------------------------------------------------------*/
71
72/*----------------------------------------------------------------------------*\
73*  NAME:
74*     compute_crc32() - computes the CRC-32 value of a memory buffer
75*  DESCRIPTION:
76*     Computes or accumulates the CRC-32 value for a memory buffer.
77*     The 'in_crc32' gives a previously accumulated CRC-32 value to allow
78*     a CRC to be generated for multiple sequential buffer-fuls of data.
79*     The 'in_crc32' for the first buffer must be zero.
80*  ARGUMENTS:
81*     in_crc32 - accumulated CRC-32 value, must be 0 on first call
82*     buf     - buffer to compute CRC-32 value for
83*     buf_len  - number of bytes in buffer
84*  RETURNS:
85*     crc32 - computed CRC-32 value
86*  ERRORS:
87*     (no errors are possible)
88\*----------------------------------------------------------------------------*/
89
90static uint32_t
91compute_crc32 (uint32_t    in_crc32,
92		  const void *buf,
93		  size_t      buf_len)
94{
95    static const uint32_t crc_table[256] = {
96	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
97	0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
98	0x09B64C2B, 0x7EB17CBD,	0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
99	0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
100	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,	0x14015C4F, 0x63066CD9,
101	0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
102	0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
103	0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
104	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
105	0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
106	0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
107	0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
108	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
109	0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
110	0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
111	0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
112	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
113	0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
114	0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
115	0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
116	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
117	0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
118	0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
119	0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
120	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
121	0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
122	0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
123	0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
124	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
125	0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
126	0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
127	0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
128	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
129	0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
130	0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
131	0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
132	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
133	0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
134	0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
135	0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
136	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
137	0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
138	0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
139    };
140
141    uint32_t              crc32;
142    unsigned char *       byte_buf;
143    size_t                i;
144
145    /** accumulate crc32 for buffer **/
146    crc32 = in_crc32 ^ 0xFFFFFFFF;
147    byte_buf = (unsigned char*) buf;
148
149    for (i = 0; i < buf_len; i++)
150	crc32 = (crc32 >> 8) ^ crc_table[(crc32 ^ byte_buf[i]) & 0xFF];
151
152    return (crc32 ^ 0xFFFFFFFF);
153}
154
155/* perform endian conversion of pixel data */
156static void
157image_endian_swap (pixman_image_t *img,
158		   int             bpp)
159{
160    int       stride = pixman_image_get_stride (img);
161    uint32_t *data = pixman_image_get_data (img);
162    int       height = pixman_image_get_height (img);
163    int i, j;
164
165    /* swap bytes only on big endian systems */
166    volatile uint16_t endian_check_var = 0x1234;
167    if (*(volatile uint8_t *)&endian_check_var != 0x12)
168	return;
169
170    for (i = 0; i < height; i++)
171    {
172	char *line_data = (char *)data + stride * i;
173
174	/* swap bytes only for 16, 24 and 32 bpp for now */
175	switch (bpp)
176	{
177	case 16:
178	    for (j = 0; j + 2 <= stride; j += 2)
179	    {
180		char t1 = line_data[j + 0];
181		char t2 = line_data[j + 1];
182		line_data[j + 1] = t1;
183		line_data[j + 0] = t2;
184	    }
185	    break;
186
187	case 24:
188	    for (j = 0; j + 3 <= stride; j += 3)
189	    {
190		char t1 = line_data[j + 0];
191		char t2 = line_data[j + 1];
192		char t3 = line_data[j + 2];
193		line_data[j + 2] = t1;
194		line_data[j + 1] = t2;
195		line_data[j + 0] = t3;
196	    }
197	    break;
198
199	case 32:
200	    for (j = 0; j + 4 <= stride; j += 4)
201	    {
202		char t1 = line_data[j + 0];
203		char t2 = line_data[j + 1];
204		char t3 = line_data[j + 2];
205		char t4 = line_data[j + 3];
206		line_data[j + 3] = t1;
207		line_data[j + 2] = t2;
208		line_data[j + 1] = t3;
209		line_data[j + 0] = t4;
210	    }
211	    break;
212
213	default:
214	    break;
215	}
216    }
217}
218
219#define MAX_SRC_WIDTH  10
220#define MAX_SRC_HEIGHT 10
221#define MAX_DST_WIDTH  10
222#define MAX_DST_HEIGHT 10
223#define MAX_STRIDE     4
224
225/*
226 * Composite operation with pseudorandom images
227 */
228uint32_t
229test_composite (uint32_t initcrc,
230		int      testnum,
231		int      verbose)
232{
233    int                i;
234    pixman_image_t *   src_img;
235    pixman_image_t *   dst_img;
236    pixman_transform_t transform;
237    pixman_region16_t  clip;
238    int                src_width, src_height;
239    int                dst_width, dst_height;
240    int                src_stride, dst_stride;
241    int                src_x, src_y;
242    int                dst_x, dst_y;
243    int                src_bpp;
244    int                dst_bpp;
245    int                w, h;
246    int                scale_x = 32768, scale_y = 32768;
247    int                op;
248    int                repeat = 0;
249    int                src_fmt, dst_fmt;
250    uint32_t *         srcbuf;
251    uint32_t *         dstbuf;
252    uint32_t           crc32;
253
254    lcg_srand (testnum);
255
256    src_bpp = (lcg_rand_n (2) == 0) ? 2 : 4;
257    dst_bpp = (lcg_rand_n (2) == 0) ? 2 : 4;
258    op = (lcg_rand_n (2) == 0) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER;
259
260    src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1;
261    src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1;
262    dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1;
263    dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1;
264    src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp;
265    dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp;
266
267    if (src_stride & 3)
268	src_stride += 2;
269
270    if (dst_stride & 3)
271	dst_stride += 2;
272
273    src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2);
274    src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2);
275    dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2);
276    dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2);
277    w = lcg_rand_n (dst_width * 3 / 2 - dst_x);
278    h = lcg_rand_n (dst_height * 3 / 2 - dst_y);
279
280    srcbuf = (uint32_t *)malloc (src_stride * src_height);
281    dstbuf = (uint32_t *)malloc (dst_stride * dst_height);
282
283    for (i = 0; i < src_stride * src_height; i++)
284	*((uint8_t *)srcbuf + i) = lcg_rand_n (256);
285
286    for (i = 0; i < dst_stride * dst_height; i++)
287	*((uint8_t *)dstbuf + i) = lcg_rand_n (256);
288
289    src_fmt = src_bpp == 4 ? (lcg_rand_n (2) == 0 ?
290                              PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5;
291
292    dst_fmt = dst_bpp == 4 ? (lcg_rand_n (2) == 0 ?
293                              PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5;
294
295    src_img = pixman_image_create_bits (
296        src_fmt, src_width, src_height, srcbuf, src_stride);
297
298    dst_img = pixman_image_create_bits (
299        dst_fmt, dst_width, dst_height, dstbuf, dst_stride);
300
301    image_endian_swap (src_img, src_bpp * 8);
302    image_endian_swap (dst_img, dst_bpp * 8);
303
304    if (lcg_rand_n (8) > 0)
305    {
306	scale_x = 32768 + lcg_rand_n (65536);
307	scale_y = 32768 + lcg_rand_n (65536);
308	pixman_transform_init_scale (&transform, scale_x, scale_y);
309	pixman_image_set_transform (src_img, &transform);
310    }
311
312    switch (lcg_rand_n (4))
313    {
314    case 0:
315	repeat = PIXMAN_REPEAT_NONE;
316	break;
317
318    case 1:
319	repeat = PIXMAN_REPEAT_NORMAL;
320	break;
321
322    case 2:
323	repeat = PIXMAN_REPEAT_PAD;
324	break;
325
326    case 3:
327	repeat = PIXMAN_REPEAT_REFLECT;
328	break;
329    }
330    pixman_image_set_repeat (src_img, repeat);
331
332    if (verbose)
333    {
334	printf ("src_fmt=%08X, dst_fmt=%08X\n", src_fmt, dst_fmt);
335	printf ("op=%d, scale_x=%d, scale_y=%d, repeat=%d\n",
336	        op, scale_x, scale_y, repeat);
337	printf ("src_width=%d, src_height=%d, dst_width=%d, dst_height=%d\n",
338	        src_width, src_height, dst_width, dst_height);
339	printf ("src_x=%d, src_y=%d, dst_x=%d, dst_y=%d\n",
340	        src_x, src_y, dst_x, dst_y);
341	printf ("w=%d, h=%d\n", w, h);
342    }
343
344    if (lcg_rand_n (8) == 0)
345    {
346	pixman_box16_t clip_boxes[2];
347	int            n = lcg_rand_n (2) + 1;
348
349	for (i = 0; i < n; i++)
350	{
351	    clip_boxes[i].x1 = lcg_rand_n (src_width);
352	    clip_boxes[i].y1 = lcg_rand_n (src_height);
353	    clip_boxes[i].x2 =
354		clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1);
355	    clip_boxes[i].y2 =
356		clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1);
357
358	    if (verbose)
359	    {
360		printf ("source clip box: [%d,%d-%d,%d]\n",
361		        clip_boxes[i].x1, clip_boxes[i].y1,
362		        clip_boxes[i].x2, clip_boxes[i].y2);
363	    }
364	}
365
366	pixman_region_init_rects (&clip, clip_boxes, n);
367	pixman_image_set_clip_region (src_img, &clip);
368	pixman_image_set_source_clipping (src_img, 1);
369	pixman_region_fini (&clip);
370    }
371
372    if (lcg_rand_n (8) == 0)
373    {
374	pixman_box16_t clip_boxes[2];
375	int            n = lcg_rand_n (2) + 1;
376	for (i = 0; i < n; i++)
377	{
378	    clip_boxes[i].x1 = lcg_rand_n (dst_width);
379	    clip_boxes[i].y1 = lcg_rand_n (dst_height);
380	    clip_boxes[i].x2 =
381		clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1);
382	    clip_boxes[i].y2 =
383		clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1);
384
385	    if (verbose)
386	    {
387		printf ("destination clip box: [%d,%d-%d,%d]\n",
388		        clip_boxes[i].x1, clip_boxes[i].y1,
389		        clip_boxes[i].x2, clip_boxes[i].y2);
390	    }
391	}
392	pixman_region_init_rects (&clip, clip_boxes, n);
393	pixman_image_set_clip_region (dst_img, &clip);
394	pixman_region_fini (&clip);
395    }
396
397    pixman_image_composite (op, src_img, NULL, dst_img,
398                            src_x, src_y, 0, 0, dst_x, dst_y, w, h);
399
400    if (dst_fmt == PIXMAN_x8r8g8b8)
401    {
402	/* ignore unused part */
403	for (i = 0; i < dst_stride * dst_height / 4; i++)
404	    dstbuf[i] &= 0xFFFFFF;
405    }
406
407    image_endian_swap (dst_img, dst_bpp * 8);
408
409    if (verbose)
410    {
411	int j;
412
413	for (i = 0; i < dst_height; i++)
414	{
415	    for (j = 0; j < dst_stride; j++)
416		printf ("%02X ", *((uint8_t *)dstbuf + i * dst_stride + j));
417
418	    printf ("\n");
419	}
420    }
421
422    pixman_image_unref (src_img);
423    pixman_image_unref (dst_img);
424
425    crc32 = compute_crc32 (initcrc, dstbuf, dst_stride * dst_height);
426    free (srcbuf);
427    free (dstbuf);
428    return crc32;
429}
430
431int
432main (int   argc, char *argv[])
433{
434    int      i, n = 0;
435    uint32_t crc = 0;
436
437    pixman_disable_out_of_bounds_workaround ();
438
439    if (argc >= 2)
440	n = atoi (argv[1]);
441
442    if (n == 0) n = 3000000;
443
444    if (n < 0)
445    {
446	crc = test_composite (0, -n, 1);
447	printf ("crc32=%08X\n", crc);
448    }
449    else
450    {
451	for (i = 1; i <= n; i++)
452	    crc = test_composite (crc, i, 0);
453
454	printf ("crc32=%08X\n", crc);
455
456	if (n == 3000000)
457	{
458	    /* predefined value for running with all the fastpath functions disabled  */
459	    /* it needs to be updated every time changes are introduced to this program! */
460
461	    if (crc == 0x0B633CF4)
462	    {
463		printf ("scaling test passed\n");
464	    }
465	    else
466	    {
467		printf ("scaling test failed!\n");
468		return 1;
469	    }
470	}
471    }
472
473    return 0;
474}
475