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