blitters-test.c revision 5c2d8072
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 30static pixman_indexed_t palette; 31 32static void * 33aligned_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 */ 48static pixman_image_t * 49create_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 */ 98static uint32_t 99free_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 141static 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 202static 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 250static 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 */ 262uint32_t 263test_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 428static void 429initialize_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 440int 441main (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 == 0xBBACC28D) 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} 498