composite.c revision 14b11b2b
1/* 2 * Copyright © 2005 Eric Anholt 3 * Copyright © 2009 Chris Wilson 4 * Copyright © 2010 Soeren Sandmann 5 * Copyright © 2010 Red Hat, Inc. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that 10 * copyright notice and this permission notice appear in supporting 11 * documentation, and that the name of Eric Anholt not be used in 12 * advertising or publicity pertaining to distribution of the software without 13 * specific, written prior permission. Eric Anholt makes no 14 * representations about the suitability of this software for any purpose. It 15 * is provided "as is" without express or implied warranty. 16 * 17 * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19 * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 23 * PERFORMANCE OF THIS SOFTWARE. 24 */ 25#include <stdio.h> 26#include <stdlib.h> /* abort() */ 27#include <math.h> 28#include <time.h> 29#include "utils.h" 30 31typedef struct image_t image_t; 32 33static const color_t colors[] = 34{ 35 { 1.0, 1.0, 1.0, 1.0 }, 36 { 1.0, 1.0, 1.0, 0.0 }, 37 { 0.0, 0.0, 0.0, 1.0 }, 38 { 0.0, 0.0, 0.0, 0.0 }, 39 { 1.0, 0.0, 0.0, 1.0 }, 40 { 0.0, 1.0, 0.0, 1.0 }, 41 { 0.0, 0.0, 1.0, 1.0 }, 42 { 0.5, 0.0, 0.0, 0.5 }, 43}; 44 45static uint16_t 46_color_double_to_short (double d) 47{ 48 uint32_t i; 49 50 i = (uint32_t) (d * 65536); 51 i -= (i >> 16); 52 53 return i; 54} 55 56static void 57compute_pixman_color (const color_t *color, 58 pixman_color_t *out) 59{ 60 out->red = _color_double_to_short (color->r); 61 out->green = _color_double_to_short (color->g); 62 out->blue = _color_double_to_short (color->b); 63 out->alpha = _color_double_to_short (color->a); 64} 65 66#define REPEAT 0x01000000 67#define FLAGS 0xff000000 68 69static const int sizes[] = 70{ 71 0, 72 1, 73 1 | REPEAT, 74 10 75}; 76 77static const pixman_format_code_t formats[] = 78{ 79 /* 32 bpp formats */ 80 PIXMAN_a8r8g8b8, 81 PIXMAN_x8r8g8b8, 82 PIXMAN_a8b8g8r8, 83 PIXMAN_x8b8g8r8, 84 PIXMAN_b8g8r8a8, 85 PIXMAN_b8g8r8x8, 86 PIXMAN_r8g8b8a8, 87 PIXMAN_r8g8b8x8, 88 PIXMAN_x2r10g10b10, 89 PIXMAN_x2b10g10r10, 90 PIXMAN_a2r10g10b10, 91 PIXMAN_a2b10g10r10, 92 93 /* sRGB formats */ 94 PIXMAN_a8r8g8b8_sRGB, 95 PIXMAN_r8g8b8_sRGB, 96 97 /* 24 bpp formats */ 98 PIXMAN_r8g8b8, 99 PIXMAN_b8g8r8, 100 PIXMAN_r5g6b5, 101 PIXMAN_b5g6r5, 102 103 /* 16 bpp formats */ 104 PIXMAN_x1r5g5b5, 105 PIXMAN_x1b5g5r5, 106 PIXMAN_a1r5g5b5, 107 PIXMAN_a1b5g5r5, 108 PIXMAN_a4b4g4r4, 109 PIXMAN_x4b4g4r4, 110 PIXMAN_a4r4g4b4, 111 PIXMAN_x4r4g4b4, 112 113 /* 8 bpp formats */ 114 PIXMAN_a8, 115 PIXMAN_r3g3b2, 116 PIXMAN_b2g3r3, 117 PIXMAN_a2r2g2b2, 118 PIXMAN_a2b2g2r2, 119 PIXMAN_x4a4, 120 121 /* 4 bpp formats */ 122 PIXMAN_a4, 123 PIXMAN_r1g2b1, 124 PIXMAN_b1g2r1, 125 PIXMAN_a1r1g1b1, 126 PIXMAN_a1b1g1r1, 127 128 /* 1 bpp formats */ 129 PIXMAN_a1, 130}; 131 132struct image_t 133{ 134 pixman_image_t *image; 135 pixman_format_code_t format; 136 const color_t *color; 137 pixman_repeat_t repeat; 138 int size; 139}; 140 141static const pixman_op_t operators[] = 142{ 143 PIXMAN_OP_CLEAR, 144 PIXMAN_OP_SRC, 145 PIXMAN_OP_DST, 146 PIXMAN_OP_OVER, 147 PIXMAN_OP_OVER_REVERSE, 148 PIXMAN_OP_IN, 149 PIXMAN_OP_IN_REVERSE, 150 PIXMAN_OP_OUT, 151 PIXMAN_OP_OUT_REVERSE, 152 PIXMAN_OP_ATOP, 153 PIXMAN_OP_ATOP_REVERSE, 154 PIXMAN_OP_XOR, 155 PIXMAN_OP_ADD, 156 PIXMAN_OP_SATURATE, 157 158 PIXMAN_OP_DISJOINT_CLEAR, 159 PIXMAN_OP_DISJOINT_SRC, 160 PIXMAN_OP_DISJOINT_DST, 161 PIXMAN_OP_DISJOINT_OVER, 162 PIXMAN_OP_DISJOINT_OVER_REVERSE, 163 PIXMAN_OP_DISJOINT_IN, 164 PIXMAN_OP_DISJOINT_IN_REVERSE, 165 PIXMAN_OP_DISJOINT_OUT, 166 PIXMAN_OP_DISJOINT_OUT_REVERSE, 167 PIXMAN_OP_DISJOINT_ATOP, 168 PIXMAN_OP_DISJOINT_ATOP_REVERSE, 169 PIXMAN_OP_DISJOINT_XOR, 170 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}; 184 185static uint32_t 186get_value (pixman_image_t *image) 187{ 188 uint32_t value = *(uint32_t *)pixman_image_get_data (image); 189 190#ifdef WORDS_BIGENDIAN 191 { 192 pixman_format_code_t format = pixman_image_get_format (image); 193 value >>= 8 * sizeof(value) - PIXMAN_FORMAT_BPP (format); 194 } 195#endif 196 197 return value; 198} 199 200static char * 201describe_image (image_t *info, char *buf) 202{ 203 if (info->size) 204 { 205 sprintf (buf, "%s, %dx%d%s", 206 format_name (info->format), 207 info->size, info->size, 208 info->repeat ? " R" :""); 209 } 210 else 211 { 212 sprintf (buf, "solid"); 213 } 214 215 return buf; 216} 217 218static char * 219describe_color (const color_t *color, char *buf) 220{ 221 sprintf (buf, "%.3f %.3f %.3f %.3f", 222 color->r, color->g, color->b, color->a); 223 224 return buf; 225} 226 227static pixman_bool_t 228composite_test (image_t *dst, 229 pixman_op_t op, 230 image_t *src, 231 image_t *mask, 232 pixman_bool_t component_alpha, 233 int testno) 234{ 235 color_t expected, tdst, tsrc, tmsk; 236 pixel_checker_t checker; 237 238 if (mask) 239 { 240 pixman_image_set_component_alpha (mask->image, component_alpha); 241 242 pixman_image_composite (op, src->image, mask->image, dst->image, 243 0, 0, 0, 0, 0, 0, dst->size, dst->size); 244 } 245 else 246 { 247 pixman_image_composite (op, src->image, NULL, dst->image, 248 0, 0, 249 0, 0, 250 0, 0, 251 dst->size, dst->size); 252 } 253 254 tdst = *dst->color; 255 tsrc = *src->color; 256 257 if (mask) 258 { 259 tmsk = *mask->color; 260 } 261 262 /* It turns out that by construction all source, mask etc. colors are 263 * linear because they are made from fills, and fills are always in linear 264 * color space. However, if they have been converted to bitmaps, we need 265 * to simulate the sRGB approximation to pass the test cases. 266 */ 267 if (src->size) 268 { 269 if (PIXMAN_FORMAT_TYPE (src->format) == PIXMAN_TYPE_ARGB_SRGB) 270 { 271 tsrc.r = convert_linear_to_srgb (tsrc.r); 272 tsrc.g = convert_linear_to_srgb (tsrc.g); 273 tsrc.b = convert_linear_to_srgb (tsrc.b); 274 round_color (src->format, &tsrc); 275 tsrc.r = convert_srgb_to_linear (tsrc.r); 276 tsrc.g = convert_srgb_to_linear (tsrc.g); 277 tsrc.b = convert_srgb_to_linear (tsrc.b); 278 } 279 else 280 { 281 round_color (src->format, &tsrc); 282 } 283 } 284 285 if (mask && mask->size) 286 { 287 if (PIXMAN_FORMAT_TYPE (mask->format) == PIXMAN_TYPE_ARGB_SRGB) 288 { 289 tmsk.r = convert_linear_to_srgb (tmsk.r); 290 tmsk.g = convert_linear_to_srgb (tmsk.g); 291 tmsk.b = convert_linear_to_srgb (tmsk.b); 292 round_color (mask->format, &tmsk); 293 tmsk.r = convert_srgb_to_linear (tmsk.r); 294 tmsk.g = convert_srgb_to_linear (tmsk.g); 295 tmsk.b = convert_srgb_to_linear (tmsk.b); 296 } 297 else 298 { 299 round_color (mask->format, &tmsk); 300 } 301 } 302 303 if (PIXMAN_FORMAT_TYPE (dst->format) == PIXMAN_TYPE_ARGB_SRGB) 304 { 305 tdst.r = convert_linear_to_srgb (tdst.r); 306 tdst.g = convert_linear_to_srgb (tdst.g); 307 tdst.b = convert_linear_to_srgb (tdst.b); 308 round_color (dst->format, &tdst); 309 tdst.r = convert_srgb_to_linear (tdst.r); 310 tdst.g = convert_srgb_to_linear (tdst.g); 311 tdst.b = convert_srgb_to_linear (tdst.b); 312 } 313 else 314 { 315 round_color (dst->format, &tdst); 316 } 317 318 do_composite (op, 319 &tsrc, 320 mask? &tmsk : NULL, 321 &tdst, 322 &expected, 323 component_alpha); 324 325 pixel_checker_init (&checker, dst->format); 326 327 if (!pixel_checker_check (&checker, get_value (dst->image), &expected)) 328 { 329 char buf[40], buf2[40]; 330 int a, r, g, b; 331 uint32_t pixel; 332 333 printf ("---- Test %d failed ----\n", testno); 334 printf ("Operator: %s %s\n", 335 operator_name (op), component_alpha ? "CA" : ""); 336 337 printf ("Source: %s\n", describe_image (src, buf)); 338 if (mask != NULL) 339 printf ("Mask: %s\n", describe_image (mask, buf)); 340 341 printf ("Destination: %s\n\n", describe_image (dst, buf)); 342 printf (" R G B A Rounded\n"); 343 printf ("Source color: %s %s\n", 344 describe_color (src->color, buf), 345 describe_color (&tsrc, buf2)); 346 if (mask) 347 { 348 printf ("Mask color: %s %s\n", 349 describe_color (mask->color, buf), 350 describe_color (&tmsk, buf2)); 351 } 352 printf ("Dest. color: %s %s\n", 353 describe_color (dst->color, buf), 354 describe_color (&tdst, buf2)); 355 356 pixel = get_value (dst->image); 357 358 printf ("Expected: %s\n", describe_color (&expected, buf)); 359 360 pixel_checker_split_pixel (&checker, pixel, &a, &r, &g, &b); 361 362 printf ("Got: %5d %5d %5d %5d [pixel: 0x%08x]\n", r, g, b, a, pixel); 363 pixel_checker_get_min (&checker, &expected, &a, &r, &g, &b); 364 printf ("Min accepted: %5d %5d %5d %5d\n", r, g, b, a); 365 pixel_checker_get_max (&checker, &expected, &a, &r, &g, &b); 366 printf ("Max accepted: %5d %5d %5d %5d\n", r, g, b, a); 367 368 return FALSE; 369 } 370 return TRUE; 371} 372 373static void 374image_init (image_t *info, 375 int color, 376 int format, 377 int size) 378{ 379 pixman_color_t fill; 380 381 info->color = &colors[color]; 382 compute_pixman_color (info->color, &fill); 383 384 info->format = formats[format]; 385 info->size = sizes[size] & ~FLAGS; 386 info->repeat = PIXMAN_REPEAT_NONE; 387 388 if (info->size) 389 { 390 pixman_image_t *solid; 391 392 info->image = pixman_image_create_bits (info->format, 393 info->size, info->size, 394 NULL, 0); 395 396 solid = pixman_image_create_solid_fill (&fill); 397 pixman_image_composite32 (PIXMAN_OP_SRC, solid, NULL, info->image, 398 0, 0, 0, 0, 0, 0, info->size, info->size); 399 pixman_image_unref (solid); 400 401 if (sizes[size] & REPEAT) 402 { 403 pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL); 404 info->repeat = PIXMAN_REPEAT_NORMAL; 405 } 406 } 407 else 408 { 409 info->image = pixman_image_create_solid_fill (&fill); 410 } 411} 412 413static void 414image_fini (image_t *info) 415{ 416 pixman_image_unref (info->image); 417} 418 419static int 420random_size (void) 421{ 422 return prng_rand_n (ARRAY_LENGTH (sizes)); 423} 424 425static int 426random_color (void) 427{ 428 return prng_rand_n (ARRAY_LENGTH (colors)); 429} 430 431static int 432random_format (void) 433{ 434 return prng_rand_n (ARRAY_LENGTH (formats)); 435} 436 437static pixman_bool_t 438run_test (uint32_t seed) 439{ 440 image_t src, mask, dst; 441 pixman_op_t op; 442 int ca; 443 int ok; 444 445 prng_srand (seed); 446 447 image_init (&dst, random_color(), random_format(), 1); 448 image_init (&src, random_color(), random_format(), random_size()); 449 image_init (&mask, random_color(), random_format(), random_size()); 450 451 op = operators [prng_rand_n (ARRAY_LENGTH (operators))]; 452 453 ca = prng_rand_n (3); 454 455 switch (ca) 456 { 457 case 0: 458 ok = composite_test (&dst, op, &src, NULL, FALSE, seed); 459 break; 460 case 1: 461 ok = composite_test (&dst, op, &src, &mask, FALSE, seed); 462 break; 463 case 2: 464 ok = composite_test (&dst, op, &src, &mask, 465 mask.size? TRUE : FALSE, seed); 466 break; 467 default: 468 ok = FALSE; 469 break; 470 } 471 472 image_fini (&src); 473 image_fini (&mask); 474 image_fini (&dst); 475 476 return ok; 477} 478 479int 480main (int argc, char **argv) 481{ 482#define N_TESTS (8 * 1024 * 1024) 483 int result = 0; 484 uint32_t seed; 485 int32_t i; 486 487 if (argc > 1) 488 { 489 char *end; 490 491 i = strtol (argv[1], &end, 0); 492 493 if (end != argv[1]) 494 { 495 if (!run_test (i)) 496 return 1; 497 else 498 return 0; 499 } 500 else 501 { 502 printf ("Usage:\n\n %s <number>\n\n", argv[0]); 503 return -1; 504 } 505 } 506 507 if (getenv ("PIXMAN_RANDOMIZE_TESTS")) 508 seed = get_random_seed(); 509 else 510 seed = 1; 511 512#ifdef USE_OPENMP 513# pragma omp parallel for default(none) shared(result, argv, seed) 514#endif 515 for (i = 0; i <= N_TESTS; ++i) 516 { 517 if (!result && !run_test (i + seed)) 518 { 519 printf ("Test 0x%08X failed.\n", seed + i); 520 521 result = seed + i; 522 } 523 } 524 525 return result; 526} 527