lowlevel-blt-bench.c revision a156c6bd
1/* 2 * Copyright © 2009 Nokia Corporation 3 * Copyright © 2010 Movial Creative Technologies Oy 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include "utils.h" 29 30#define SOLID_FLAG 1 31#define CA_FLAG 2 32 33#define L1CACHE_SIZE (8 * 1024) 34#define L2CACHE_SIZE (128 * 1024) 35 36/* This is applied to both L1 and L2 tests - alternatively, you could 37 * parameterise bench_L or split it into two functions. It could be 38 * read at runtime on some architectures, but it only really matters 39 * that it's a number that's an integer divisor of both cacheline 40 * lengths, and further, it only really matters for caches that don't 41 * do allocate0on-write. */ 42#define CACHELINE_LENGTH (32) /* bytes */ 43 44#define WIDTH 1920 45#define HEIGHT 1080 46#define BUFSIZE (WIDTH * HEIGHT * 4) 47#define XWIDTH 256 48#define XHEIGHT 256 49#define TILEWIDTH 32 50#define TINYWIDTH 8 51 52#define EXCLUDE_OVERHEAD 1 53 54uint32_t *dst; 55uint32_t *src; 56uint32_t *mask; 57 58double bandwidth = 0.0; 59 60double 61bench_memcpy () 62{ 63 int64_t n = 0, total; 64 double t1, t2; 65 int x = 0; 66 67 t1 = gettime (); 68 while (1) 69 { 70 memcpy (dst, src, BUFSIZE - 64); 71 memcpy (src, dst, BUFSIZE - 64); 72 n += 4 * (BUFSIZE - 64); 73 t2 = gettime (); 74 if (t2 - t1 > 0.5) 75 break; 76 } 77 n = total = n * 5; 78 t1 = gettime (); 79 while (n > 0) 80 { 81 if (++x >= 64) 82 x = 0; 83 memcpy ((char *)dst + 1, (char *)src + x, BUFSIZE - 64); 84 memcpy ((char *)src + 1, (char *)dst + x, BUFSIZE - 64); 85 n -= 4 * (BUFSIZE - 64); 86 } 87 t2 = gettime (); 88 return (double)total / (t2 - t1); 89} 90 91static pixman_bool_t use_scaling = FALSE; 92static pixman_filter_t filter = PIXMAN_FILTER_NEAREST; 93static pixman_bool_t use_csv_output = FALSE; 94 95/* nearly 1x scale factor */ 96static pixman_transform_t m = 97{ 98 { 99 { pixman_fixed_1 + 1, 0, 0 }, 100 { 0, pixman_fixed_1, 0 }, 101 { 0, 0, pixman_fixed_1 } 102 } 103}; 104 105static void 106pixman_image_composite_wrapper (pixman_implementation_t *impl, 107 pixman_composite_info_t *info) 108{ 109 if (use_scaling) 110 { 111 pixman_image_set_filter (info->src_image, filter, NULL, 0); 112 pixman_image_set_transform(info->src_image, &m); 113 } 114 pixman_image_composite (info->op, 115 info->src_image, info->mask_image, info->dest_image, 116 info->src_x, info->src_y, 117 info->mask_x, info->mask_y, 118 info->dest_x, info->dest_y, 119 info->width, info->height); 120} 121 122static void 123pixman_image_composite_empty (pixman_implementation_t *impl, 124 pixman_composite_info_t *info) 125{ 126 if (use_scaling) 127 { 128 pixman_image_set_filter (info->src_image, filter, NULL, 0); 129 pixman_image_set_transform(info->src_image, &m); 130 } 131 pixman_image_composite (info->op, 132 info->src_image, info->mask_image, info->dest_image, 133 0, 0, 0, 0, 0, 0, 1, 1); 134} 135 136static inline void 137call_func (pixman_composite_func_t func, 138 pixman_op_t op, 139 pixman_image_t * src_image, 140 pixman_image_t * mask_image, 141 pixman_image_t * dest_image, 142 int32_t src_x, 143 int32_t src_y, 144 int32_t mask_x, 145 int32_t mask_y, 146 int32_t dest_x, 147 int32_t dest_y, 148 int32_t width, 149 int32_t height) 150{ 151 pixman_composite_info_t info; 152 153 info.op = op; 154 info.src_image = src_image; 155 info.mask_image = mask_image; 156 info.dest_image = dest_image; 157 info.src_x = src_x; 158 info.src_y = src_y; 159 info.mask_x = mask_x; 160 info.mask_y = mask_y; 161 info.dest_x = dest_x; 162 info.dest_y = dest_y; 163 info.width = width; 164 info.height = height; 165 166 func (0, &info); 167} 168 169double 170noinline 171bench_L (pixman_op_t op, 172 pixman_image_t * src_img, 173 pixman_image_t * mask_img, 174 pixman_image_t * dst_img, 175 int64_t n, 176 pixman_composite_func_t func, 177 int width, 178 int lines_count) 179{ 180 int64_t i, j, k; 181 int x = 0; 182 int q = 0; 183 184 for (i = 0; i < n; i++) 185 { 186 /* For caches without allocate-on-write, we need to force the 187 * destination buffer back into the cache on each iteration, 188 * otherwise if they are evicted during the test, they remain 189 * uncached. This doesn't matter for tests which read the 190 * destination buffer, or for caches that do allocate-on-write, 191 * but in those cases this loop just adds constant time, which 192 * should be successfully cancelled out. 193 */ 194 for (j = 0; j < lines_count; j++) 195 { 196 for (k = 0; k < width + 62; k += CACHELINE_LENGTH / sizeof *dst) 197 { 198 q += dst[j * WIDTH + k]; 199 } 200 q += dst[j * WIDTH + width + 62]; 201 } 202 if (++x >= 64) 203 x = 0; 204 call_func (func, op, src_img, mask_img, dst_img, x, 0, x, 0, 63 - x, 0, width, lines_count); 205 } 206 207 return (double)n * lines_count * width; 208} 209 210double 211noinline 212bench_M (pixman_op_t op, 213 pixman_image_t * src_img, 214 pixman_image_t * mask_img, 215 pixman_image_t * dst_img, 216 int64_t n, 217 pixman_composite_func_t func) 218{ 219 int64_t i; 220 int x = 0; 221 222 for (i = 0; i < n; i++) 223 { 224 if (++x >= 64) 225 x = 0; 226 call_func (func, op, src_img, mask_img, dst_img, x, 0, x, 0, 1, 0, WIDTH - 64, HEIGHT); 227 } 228 229 return (double)n * (WIDTH - 64) * HEIGHT; 230} 231 232double 233noinline 234bench_HT (pixman_op_t op, 235 pixman_image_t * src_img, 236 pixman_image_t * mask_img, 237 pixman_image_t * dst_img, 238 int64_t n, 239 pixman_composite_func_t func) 240{ 241 double pix_cnt = 0; 242 int x = 0; 243 int y = 0; 244 int64_t i; 245 246 srand (0); 247 for (i = 0; i < n; i++) 248 { 249 int w = (rand () % (TILEWIDTH * 2)) + 1; 250 int h = (rand () % (TILEWIDTH * 2)) + 1; 251 if (x + w > WIDTH) 252 { 253 x = 0; 254 y += TILEWIDTH * 2; 255 } 256 if (y + h > HEIGHT) 257 { 258 y = 0; 259 } 260 call_func (func, op, src_img, mask_img, dst_img, x, y, x, y, x, y, w, h); 261 x += w; 262 pix_cnt += w * h; 263 } 264 return pix_cnt; 265} 266 267double 268noinline 269bench_VT (pixman_op_t op, 270 pixman_image_t * src_img, 271 pixman_image_t * mask_img, 272 pixman_image_t * dst_img, 273 int64_t n, 274 pixman_composite_func_t func) 275{ 276 double pix_cnt = 0; 277 int x = 0; 278 int y = 0; 279 int64_t i; 280 281 srand (0); 282 for (i = 0; i < n; i++) 283 { 284 int w = (rand () % (TILEWIDTH * 2)) + 1; 285 int h = (rand () % (TILEWIDTH * 2)) + 1; 286 if (y + h > HEIGHT) 287 { 288 y = 0; 289 x += TILEWIDTH * 2; 290 } 291 if (x + w > WIDTH) 292 { 293 x = 0; 294 } 295 call_func (func, op, src_img, mask_img, dst_img, x, y, x, y, x, y, w, h); 296 y += h; 297 pix_cnt += w * h; 298 } 299 return pix_cnt; 300} 301 302double 303noinline 304bench_R (pixman_op_t op, 305 pixman_image_t * src_img, 306 pixman_image_t * mask_img, 307 pixman_image_t * dst_img, 308 int64_t n, 309 pixman_composite_func_t func, 310 int maxw, 311 int maxh) 312{ 313 double pix_cnt = 0; 314 int64_t i; 315 316 if (maxw <= TILEWIDTH * 2 || maxh <= TILEWIDTH * 2) 317 { 318 printf("error: maxw <= TILEWIDTH * 2 || maxh <= TILEWIDTH * 2\n"); 319 return 0; 320 } 321 322 srand (0); 323 for (i = 0; i < n; i++) 324 { 325 int w = (rand () % (TILEWIDTH * 2)) + 1; 326 int h = (rand () % (TILEWIDTH * 2)) + 1; 327 int sx = rand () % (maxw - TILEWIDTH * 2); 328 int sy = rand () % (maxh - TILEWIDTH * 2); 329 int dx = rand () % (maxw - TILEWIDTH * 2); 330 int dy = rand () % (maxh - TILEWIDTH * 2); 331 call_func (func, op, src_img, mask_img, dst_img, sx, sy, sx, sy, dx, dy, w, h); 332 pix_cnt += w * h; 333 } 334 return pix_cnt; 335} 336 337double 338noinline 339bench_RT (pixman_op_t op, 340 pixman_image_t * src_img, 341 pixman_image_t * mask_img, 342 pixman_image_t * dst_img, 343 int64_t n, 344 pixman_composite_func_t func, 345 int maxw, 346 int maxh) 347{ 348 double pix_cnt = 0; 349 int64_t i; 350 351 if (maxw <= TINYWIDTH * 2 || maxh <= TINYWIDTH * 2) 352 { 353 printf("error: maxw <= TINYWIDTH * 2 || maxh <= TINYWIDTH * 2\n"); 354 return 0; 355 } 356 357 srand (0); 358 for (i = 0; i < n; i++) 359 { 360 int w = (rand () % (TINYWIDTH * 2)) + 1; 361 int h = (rand () % (TINYWIDTH * 2)) + 1; 362 int sx = rand () % (maxw - TINYWIDTH * 2); 363 int sy = rand () % (maxh - TINYWIDTH * 2); 364 int dx = rand () % (maxw - TINYWIDTH * 2); 365 int dy = rand () % (maxh - TINYWIDTH * 2); 366 call_func (func, op, src_img, mask_img, dst_img, sx, sy, sx, sy, dx, dy, w, h); 367 pix_cnt += w * h; 368 } 369 return pix_cnt; 370} 371 372static double 373Mpx_per_sec (double pix_cnt, double t1, double t2, double t3) 374{ 375 double overhead = t2 - t1; 376 double testtime = t3 - t2; 377 378 return pix_cnt / (testtime - overhead) / 1e6; 379} 380 381void 382bench_composite (const char *testname, 383 int src_fmt, 384 int src_flags, 385 int op, 386 int mask_fmt, 387 int mask_flags, 388 int dst_fmt, 389 double npix) 390{ 391 pixman_image_t * src_img; 392 pixman_image_t * dst_img; 393 pixman_image_t * mask_img; 394 pixman_image_t * xsrc_img; 395 pixman_image_t * xdst_img; 396 pixman_image_t * xmask_img; 397 double t1, t2, t3, pix_cnt; 398 int64_t n, l1test_width, nlines; 399 double bytes_per_pix = 0; 400 pixman_bool_t bench_pixbuf = FALSE; 401 402 pixman_composite_func_t func = pixman_image_composite_wrapper; 403 404 if (!(src_flags & SOLID_FLAG)) 405 { 406 bytes_per_pix += (src_fmt >> 24) / 8.0; 407 src_img = pixman_image_create_bits (src_fmt, 408 WIDTH, HEIGHT, 409 src, 410 WIDTH * 4); 411 xsrc_img = pixman_image_create_bits (src_fmt, 412 XWIDTH, XHEIGHT, 413 src, 414 XWIDTH * 4); 415 } 416 else 417 { 418 src_img = pixman_image_create_bits (src_fmt, 419 1, 1, 420 src, 421 4); 422 xsrc_img = pixman_image_create_bits (src_fmt, 423 1, 1, 424 src, 425 4); 426 pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NORMAL); 427 pixman_image_set_repeat (xsrc_img, PIXMAN_REPEAT_NORMAL); 428 } 429 430 bytes_per_pix += (dst_fmt >> 24) / 8.0; 431 dst_img = pixman_image_create_bits (dst_fmt, 432 WIDTH, HEIGHT, 433 dst, 434 WIDTH * 4); 435 436 mask_img = NULL; 437 xmask_img = NULL; 438 if (strcmp (testname, "pixbuf") == 0 || strcmp (testname, "rpixbuf") == 0) 439 { 440 bench_pixbuf = TRUE; 441 } 442 if (!(mask_flags & SOLID_FLAG) && mask_fmt != PIXMAN_null) 443 { 444 bytes_per_pix += (mask_fmt >> 24) / ((op == PIXMAN_OP_SRC) ? 8.0 : 4.0); 445 mask_img = pixman_image_create_bits (mask_fmt, 446 WIDTH, HEIGHT, 447 bench_pixbuf ? src : mask, 448 WIDTH * 4); 449 xmask_img = pixman_image_create_bits (mask_fmt, 450 XWIDTH, XHEIGHT, 451 bench_pixbuf ? src : mask, 452 XWIDTH * 4); 453 } 454 else if (mask_fmt != PIXMAN_null) 455 { 456 mask_img = pixman_image_create_bits (mask_fmt, 457 1, 1, 458 mask, 459 4); 460 xmask_img = pixman_image_create_bits (mask_fmt, 461 1, 1, 462 mask, 463 4 * 4); 464 pixman_image_set_repeat (mask_img, PIXMAN_REPEAT_NORMAL); 465 pixman_image_set_repeat (xmask_img, PIXMAN_REPEAT_NORMAL); 466 } 467 if ((mask_flags & CA_FLAG) && mask_fmt != PIXMAN_null) 468 { 469 pixman_image_set_component_alpha (mask_img, 1); 470 } 471 xdst_img = pixman_image_create_bits (dst_fmt, 472 XWIDTH, XHEIGHT, 473 dst, 474 XWIDTH * 4); 475 476 if (!use_csv_output) 477 printf ("%24s %c", testname, func != pixman_image_composite_wrapper ? 478 '-' : '='); 479 480 memcpy (dst, src, BUFSIZE); 481 memcpy (src, dst, BUFSIZE); 482 483 l1test_width = L1CACHE_SIZE / 8 - 64; 484 if (l1test_width < 1) 485 l1test_width = 1; 486 if (l1test_width > WIDTH - 64) 487 l1test_width = WIDTH - 64; 488 n = 1 + npix / (l1test_width * 8); 489 t1 = gettime (); 490#if EXCLUDE_OVERHEAD 491 pix_cnt = bench_L (op, src_img, mask_img, dst_img, n, pixman_image_composite_empty, l1test_width, 1); 492#endif 493 t2 = gettime (); 494 pix_cnt = bench_L (op, src_img, mask_img, dst_img, n, func, l1test_width, 1); 495 t3 = gettime (); 496 if (use_csv_output) 497 printf ("%g,", Mpx_per_sec (pix_cnt, t1, t2, t3)); 498 else 499 printf (" L1:%7.2f", Mpx_per_sec (pix_cnt, t1, t2, t3)); 500 fflush (stdout); 501 502 memcpy (dst, src, BUFSIZE); 503 memcpy (src, dst, BUFSIZE); 504 505 nlines = (L2CACHE_SIZE / l1test_width) / 506 ((PIXMAN_FORMAT_BPP(src_fmt) + PIXMAN_FORMAT_BPP(dst_fmt)) / 8); 507 if (nlines < 1) 508 nlines = 1; 509 n = 1 + npix / (l1test_width * nlines); 510 t1 = gettime (); 511#if EXCLUDE_OVERHEAD 512 pix_cnt = bench_L (op, src_img, mask_img, dst_img, n, pixman_image_composite_empty, l1test_width, nlines); 513#endif 514 t2 = gettime (); 515 pix_cnt = bench_L (op, src_img, mask_img, dst_img, n, func, l1test_width, nlines); 516 t3 = gettime (); 517 if (use_csv_output) 518 printf ("%g,", Mpx_per_sec (pix_cnt, t1, t2, t3)); 519 else 520 printf (" L2:%7.2f", Mpx_per_sec (pix_cnt, t1, t2, t3)); 521 fflush (stdout); 522 523 memcpy (dst, src, BUFSIZE); 524 memcpy (src, dst, BUFSIZE); 525 526 n = 1 + npix / (WIDTH * HEIGHT); 527 t1 = gettime (); 528#if EXCLUDE_OVERHEAD 529 pix_cnt = bench_M (op, src_img, mask_img, dst_img, n, pixman_image_composite_empty); 530#endif 531 t2 = gettime (); 532 pix_cnt = bench_M (op, src_img, mask_img, dst_img, n, func); 533 t3 = gettime (); 534 if (use_csv_output) 535 printf ("%g,", Mpx_per_sec (pix_cnt, t1, t2, t3)); 536 else 537 printf (" M:%6.2f (%6.2f%%)", Mpx_per_sec (pix_cnt, t1, t2, t3), 538 (pix_cnt / ((t3 - t2) - (t2 - t1)) * bytes_per_pix) * (100.0 / bandwidth) ); 539 fflush (stdout); 540 541 memcpy (dst, src, BUFSIZE); 542 memcpy (src, dst, BUFSIZE); 543 544 n = 1 + npix / (8 * TILEWIDTH * TILEWIDTH); 545 t1 = gettime (); 546#if EXCLUDE_OVERHEAD 547 pix_cnt = bench_HT (op, src_img, mask_img, dst_img, n, pixman_image_composite_empty); 548#endif 549 t2 = gettime (); 550 pix_cnt = bench_HT (op, src_img, mask_img, dst_img, n, func); 551 t3 = gettime (); 552 if (use_csv_output) 553 printf ("%g,", Mpx_per_sec (pix_cnt, t1, t2, t3)); 554 else 555 printf (" HT:%6.2f", Mpx_per_sec (pix_cnt, t1, t2, t3)); 556 fflush (stdout); 557 558 memcpy (dst, src, BUFSIZE); 559 memcpy (src, dst, BUFSIZE); 560 561 n = 1 + npix / (8 * TILEWIDTH * TILEWIDTH); 562 t1 = gettime (); 563#if EXCLUDE_OVERHEAD 564 pix_cnt = bench_VT (op, src_img, mask_img, dst_img, n, pixman_image_composite_empty); 565#endif 566 t2 = gettime (); 567 pix_cnt = bench_VT (op, src_img, mask_img, dst_img, n, func); 568 t3 = gettime (); 569 if (use_csv_output) 570 printf ("%g,", Mpx_per_sec (pix_cnt, t1, t2, t3)); 571 else 572 printf (" VT:%6.2f", Mpx_per_sec (pix_cnt, t1, t2, t3)); 573 fflush (stdout); 574 575 memcpy (dst, src, BUFSIZE); 576 memcpy (src, dst, BUFSIZE); 577 578 n = 1 + npix / (8 * TILEWIDTH * TILEWIDTH); 579 t1 = gettime (); 580#if EXCLUDE_OVERHEAD 581 pix_cnt = bench_R (op, src_img, mask_img, dst_img, n, pixman_image_composite_empty, WIDTH, HEIGHT); 582#endif 583 t2 = gettime (); 584 pix_cnt = bench_R (op, src_img, mask_img, dst_img, n, func, WIDTH, HEIGHT); 585 t3 = gettime (); 586 if (use_csv_output) 587 printf ("%g,", Mpx_per_sec (pix_cnt, t1, t2, t3)); 588 else 589 printf (" R:%6.2f", Mpx_per_sec (pix_cnt, t1, t2, t3)); 590 fflush (stdout); 591 592 memcpy (dst, src, BUFSIZE); 593 memcpy (src, dst, BUFSIZE); 594 595 n = 1 + npix / (16 * TINYWIDTH * TINYWIDTH); 596 t1 = gettime (); 597#if EXCLUDE_OVERHEAD 598 pix_cnt = bench_RT (op, src_img, mask_img, dst_img, n, pixman_image_composite_empty, WIDTH, HEIGHT); 599#endif 600 t2 = gettime (); 601 pix_cnt = bench_RT (op, src_img, mask_img, dst_img, n, func, WIDTH, HEIGHT); 602 t3 = gettime (); 603 if (use_csv_output) 604 printf ("%g\n", Mpx_per_sec (pix_cnt, t1, t2, t3)); 605 else 606 printf (" RT:%6.2f (%4.0fKops/s)\n", Mpx_per_sec (pix_cnt, t1, t2, t3), (double) n / ((t3 - t2) * 1000)); 607 608 if (mask_img) { 609 pixman_image_unref (mask_img); 610 pixman_image_unref (xmask_img); 611 } 612 pixman_image_unref (src_img); 613 pixman_image_unref (dst_img); 614 pixman_image_unref (xsrc_img); 615 pixman_image_unref (xdst_img); 616} 617 618#define PIXMAN_OP_OUT_REV (PIXMAN_OP_OUT_REVERSE) 619 620struct test_entry 621{ 622 const char *testname; 623 int src_fmt; 624 int src_flags; 625 int op; 626 int mask_fmt; 627 int mask_flags; 628 int dst_fmt; 629}; 630 631typedef struct test_entry test_entry_t; 632 633static const test_entry_t tests_tbl[] = 634{ 635 { "add_8_8_8", PIXMAN_a8, 0, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a8 }, 636 { "add_n_8_8", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a8 }, 637 { "add_n_8_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a8r8g8b8 }, 638 { "add_n_8_x888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_x8r8g8b8 }, 639 { "add_n_8_0565", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 640 { "add_n_8_1555", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a1r5g5b5 }, 641 { "add_n_8_4444", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a4r4g4b4 }, 642 { "add_n_8_2222", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a2r2g2b2 }, 643 { "add_n_8_2x10", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_x2r10g10b10 }, 644 { "add_n_8_2a10", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a2r10g10b10 }, 645 { "add_n_8", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a8 }, 646 { "add_n_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 647 { "add_n_x888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 648 { "add_n_0565", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 649 { "add_n_1555", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a1r5g5b5 }, 650 { "add_n_4444", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a4r4g4b4 }, 651 { "add_n_2222", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a2r2g2b2 }, 652 { "add_n_2x10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_x2r10g10b10 }, 653 { "add_n_2a10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a2r10g10b10 }, 654 { "add_8_8", PIXMAN_a8, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a8 }, 655 { "add_x888_x888", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 656 { "add_8888_8888", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 657 { "add_8888_0565", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 658 { "add_8888_1555", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a1r5g5b5 }, 659 { "add_8888_4444", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a4r4g4b4 }, 660 { "add_8888_2222", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a2r2g2b2 }, 661 { "add_0565_0565", PIXMAN_r5g6b5, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 662 { "add_1555_1555", PIXMAN_a1r5g5b5, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a1r5g5b5 }, 663 { "add_0565_2x10", PIXMAN_r5g6b5, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_x2r10g10b10 }, 664 { "add_2a10_2a10", PIXMAN_a2r10g10b10, 0, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a2r10g10b10 }, 665 { "in_n_8_8", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_IN, PIXMAN_a8, 0, PIXMAN_a8 }, 666 { "in_8_8", PIXMAN_a8, 0, PIXMAN_OP_IN, PIXMAN_null, 0, PIXMAN_a8 }, 667 { "src_n_2222", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a2r2g2b2 }, 668 { "src_n_0565", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 669 { "src_n_1555", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a1r5g5b5 }, 670 { "src_n_4444", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a4r4g4b4 }, 671 { "src_n_x888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 672 { "src_n_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 673 { "src_n_2x10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x2r10g10b10 }, 674 { "src_n_2a10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a2r10g10b10 }, 675 { "src_8888_0565", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 676 { "src_0565_8888", PIXMAN_r5g6b5, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 677 { "src_8888_4444", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a4r4g4b4 }, 678 { "src_8888_2222", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a2r2g2b2 }, 679 { "src_8888_2x10", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x2r10g10b10 }, 680 { "src_8888_2a10", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a2r10g10b10 }, 681 { "src_0888_0565", PIXMAN_r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 682 { "src_0888_8888", PIXMAN_r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 683 { "src_0888_x888", PIXMAN_r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 684 { "src_0888_8888_rev", PIXMAN_b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 685 { "src_0888_0565_rev", PIXMAN_b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 686 { "src_x888_x888", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 687 { "src_x888_8888", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 688 { "src_8888_8888", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 689 { "src_0565_0565", PIXMAN_r5g6b5, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 690 { "src_1555_0565", PIXMAN_a1r5g5b5, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 691 { "src_0565_1555", PIXMAN_r5g6b5, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a1r5g5b5 }, 692 { "src_8_8", PIXMAN_a8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8 }, 693 { "src_n_8", PIXMAN_a8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8 }, 694 { "src_n_8_0565", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 695 { "src_n_8_1555", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a1r5g5b5 }, 696 { "src_n_8_4444", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a4r4g4b4 }, 697 { "src_n_8_2222", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a2r2g2b2 }, 698 { "src_n_8_x888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_x8r8g8b8 }, 699 { "src_n_8_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a8r8g8b8 }, 700 { "src_n_8_2x10", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_x2r10g10b10 }, 701 { "src_n_8_2a10", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a2r10g10b10 }, 702 { "src_8888_8_0565", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 703 { "src_0888_8_0565", PIXMAN_r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 704 { "src_0888_8_8888", PIXMAN_r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a8r8g8b8 }, 705 { "src_0888_8_x888", PIXMAN_r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_x8r8g8b8 }, 706 { "src_x888_8_x888", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_x8r8g8b8 }, 707 { "src_x888_8_8888", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a8r8g8b8 }, 708 { "src_0565_8_0565", PIXMAN_r5g6b5, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 709 { "src_1555_8_0565", PIXMAN_a1r5g5b5, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 710 { "src_0565_8_1555", PIXMAN_r5g6b5, 0, PIXMAN_OP_SRC, PIXMAN_a8, 0, PIXMAN_a1r5g5b5 }, 711 { "over_n_x888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 712 { "over_n_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 713 { "over_n_0565", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 714 { "over_n_1555", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_null, 0, PIXMAN_a1r5g5b5 }, 715 { "over_8888_0565", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 716 { "over_8888_8888", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 717 { "over_8888_x888", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 718 { "over_x888_8_0565", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 719 { "over_x888_8_8888", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_a8r8g8b8 }, 720 { "over_n_8_0565", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 721 { "over_n_8_1555", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_a1r5g5b5 }, 722 { "over_n_8_4444", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_a4r4g4b4 }, 723 { "over_n_8_2222", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_a2r2g2b2 }, 724 { "over_n_8_x888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_x8r8g8b8 }, 725 { "over_n_8_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_a8r8g8b8 }, 726 { "over_n_8_2x10", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_x2r10g10b10 }, 727 { "over_n_8_2a10", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8, 0, PIXMAN_a2r10g10b10 }, 728 { "over_n_8888_8888_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_a8r8g8b8 }, 729 { "over_n_8888_x888_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_x8r8g8b8 }, 730 { "over_n_8888_0565_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_r5g6b5 }, 731 { "over_n_8888_1555_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_a1r5g5b5 }, 732 { "over_n_8888_4444_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_a4r4g4b4 }, 733 { "over_n_8888_2222_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_a2r2g2b2 }, 734 { "over_n_8888_2x10_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_x2r10g10b10 }, 735 { "over_n_8888_2a10_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, 2, PIXMAN_a2r10g10b10 }, 736 { "over_8888_n_8888", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_a8, 1, PIXMAN_a8r8g8b8 }, 737 { "over_8888_n_x888", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_a8, 1, PIXMAN_x8r8g8b8 }, 738 { "over_8888_n_0565", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_a8, 1, PIXMAN_r5g6b5 }, 739 { "over_8888_n_1555", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_a8, 1, PIXMAN_a1r5g5b5 }, 740 { "over_x888_n_8888", PIXMAN_x8r8g8b8, 0, PIXMAN_OP_OVER, PIXMAN_a8, 1, PIXMAN_a8r8g8b8 }, 741 { "outrev_n_8_0565", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8, 0, PIXMAN_r5g6b5 }, 742 { "outrev_n_8_1555", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8, 0, PIXMAN_a1r5g5b5 }, 743 { "outrev_n_8_x888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8, 0, PIXMAN_x8r8g8b8 }, 744 { "outrev_n_8_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8, 0, PIXMAN_a8r8g8b8 }, 745 { "outrev_n_8888_0565_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8r8g8b8, 2, PIXMAN_r5g6b5 }, 746 { "outrev_n_8888_1555_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8r8g8b8, 2, PIXMAN_a1r5g5b5 }, 747 { "outrev_n_8888_x888_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8r8g8b8, 2, PIXMAN_x8r8g8b8 }, 748 { "outrev_n_8888_8888_ca", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OUT_REV, PIXMAN_a8r8g8b8, 2, PIXMAN_a8r8g8b8 }, 749 { "over_reverse_n_8888", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_OVER_REVERSE, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 750 { "in_reverse_8888_8888", PIXMAN_a8r8g8b8, 0, PIXMAN_OP_IN_REVERSE, PIXMAN_null, 0, PIXMAN_a8r8g8b8 }, 751 { "pixbuf", PIXMAN_x8b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_a8b8g8r8, 0, PIXMAN_a8r8g8b8 }, 752 { "rpixbuf", PIXMAN_x8b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_a8b8g8r8, 0, PIXMAN_a8b8g8r8 }, 753}; 754 755static const test_entry_t special_patterns[] = 756{ 757 { "add_n_2x10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_x2r10g10b10 }, 758 { "add_n_2a10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a2r10g10b10 }, 759 { "src_n_2x10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x2r10g10b10 }, 760 { "src_n_2a10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a2r10g10b10 }, 761 { "src_0888_8888_rev", PIXMAN_b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x8r8g8b8 }, 762 { "src_0888_0565_rev", PIXMAN_b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 }, 763 { "src_n_8", PIXMAN_a8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8 }, 764 { "pixbuf", PIXMAN_x8b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_a8b8g8r8, 0, PIXMAN_a8r8g8b8 }, 765 { "rpixbuf", PIXMAN_x8b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_a8b8g8r8, 0, PIXMAN_a8b8g8r8 }, 766}; 767 768/* Returns the sub-string's end pointer in string. */ 769static const char * 770copy_sub_string (char *buf, 771 const char *string, 772 const char *scan_from, 773 const char *end) 774{ 775 const char *delim; 776 size_t n; 777 778 delim = strchr (scan_from, '_'); 779 if (!delim) 780 delim = end; 781 782 n = delim - string; 783 strncpy(buf, string, n); 784 buf[n] = '\0'; 785 786 return delim; 787} 788 789static pixman_op_t 790parse_longest_operator (char *buf, const char **strp, const char *end) 791{ 792 const char *p = *strp; 793 const char *sub_end; 794 const char *best_end = p; 795 pixman_op_t best_op = PIXMAN_OP_NONE; 796 pixman_op_t op; 797 798 while (p < end) 799 { 800 sub_end = copy_sub_string (buf, *strp, p, end); 801 op = operator_from_string (buf); 802 p = sub_end + 1; 803 804 if (op != PIXMAN_OP_NONE) 805 { 806 best_end = p; 807 best_op = op; 808 } 809 } 810 811 *strp = best_end; 812 return best_op; 813} 814 815static pixman_format_code_t 816parse_format (char *buf, const char **p, const char *end) 817{ 818 pixman_format_code_t format; 819 const char *delim; 820 821 if (*p >= end) 822 return PIXMAN_null; 823 824 delim = copy_sub_string (buf, *p, *p, end); 825 format = format_from_string (buf); 826 827 if (format != PIXMAN_null) 828 *p = delim + 1; 829 830 return format; 831} 832 833static int 834parse_test_pattern (test_entry_t *test, const char *pattern) 835{ 836 const char *p = pattern; 837 const char *end = pattern + strlen (pattern); 838 char buf[1024]; 839 pixman_format_code_t format[3]; 840 int i; 841 842 if (strlen (pattern) > sizeof (buf) - 1) 843 return -1; 844 845 /* Special cases that the parser cannot produce. */ 846 for (i = 0; i < ARRAY_LENGTH (special_patterns); i++) 847 { 848 if (strcmp (pattern, special_patterns[i].testname) == 0) 849 { 850 *test = special_patterns[i]; 851 return 0; 852 } 853 } 854 855 test->testname = pattern; 856 857 /* Extract operator, may contain delimiters, 858 * so take the longest string that matches. 859 */ 860 test->op = parse_longest_operator (buf, &p, end); 861 if (test->op == PIXMAN_OP_NONE) 862 return -1; 863 864 /* extract up to three pixel formats */ 865 format[0] = parse_format (buf, &p, end); 866 format[1] = parse_format (buf, &p, end); 867 format[2] = parse_format (buf, &p, end); 868 869 if (format[0] == PIXMAN_null || format[1] == PIXMAN_null) 870 return -1; 871 872 /* recognize CA flag */ 873 test->mask_flags = 0; 874 if (p < end) 875 { 876 if (strcmp (p, "ca") == 0) 877 test->mask_flags |= CA_FLAG; 878 else 879 return -1; /* trailing garbage */ 880 } 881 882 test->src_fmt = format[0]; 883 if (format[2] == PIXMAN_null) 884 { 885 test->mask_fmt = PIXMAN_null; 886 test->dst_fmt = format[1]; 887 } 888 else 889 { 890 test->mask_fmt = format[1]; 891 test->dst_fmt = format[2]; 892 } 893 894 test->src_flags = 0; 895 if (test->src_fmt == PIXMAN_solid) 896 { 897 test->src_fmt = PIXMAN_a8r8g8b8; 898 test->src_flags |= SOLID_FLAG; 899 } 900 901 if (test->mask_fmt == PIXMAN_solid) 902 { 903 if (test->mask_flags & CA_FLAG) 904 test->mask_fmt = PIXMAN_a8r8g8b8; 905 else 906 test->mask_fmt = PIXMAN_a8; 907 908 test->mask_flags |= SOLID_FLAG; 909 } 910 911 return 0; 912} 913 914static int 915check_int (int got, int expected, const char *name, const char *field) 916{ 917 if (got == expected) 918 return 0; 919 920 printf ("%s: %s failure: expected %d, got %d.\n", 921 name, field, expected, got); 922 923 return 1; 924} 925 926static int 927check_format (int got, int expected, const char *name, const char *field) 928{ 929 if (got == expected) 930 return 0; 931 932 printf ("%s: %s failure: expected %s (%#x), got %s (%#x).\n", 933 name, field, 934 format_name (expected), expected, 935 format_name (got), got); 936 937 return 1; 938} 939 940static void 941parser_self_test (void) 942{ 943 const test_entry_t *ent; 944 test_entry_t test; 945 int fails = 0; 946 int i; 947 948 for (i = 0; i < ARRAY_LENGTH (tests_tbl); i++) 949 { 950 ent = &tests_tbl[i]; 951 952 if (parse_test_pattern (&test, ent->testname) < 0) 953 { 954 printf ("parsing failed for '%s'\n", ent->testname); 955 fails++; 956 continue; 957 } 958 959 fails += check_format (test.src_fmt, ent->src_fmt, 960 ent->testname, "src_fmt"); 961 fails += check_format (test.mask_fmt, ent->mask_fmt, 962 ent->testname, "mask_fmt"); 963 fails += check_format (test.dst_fmt, ent->dst_fmt, 964 ent->testname, "dst_fmt"); 965 fails += check_int (test.src_flags, ent->src_flags, 966 ent->testname, "src_flags"); 967 fails += check_int (test.mask_flags, ent->mask_flags, 968 ent->testname, "mask_flags"); 969 fails += check_int (test.op, ent->op, ent->testname, "op"); 970 } 971 972 if (fails) 973 { 974 printf ("Parser self-test failed.\n"); 975 exit (EXIT_FAILURE); 976 } 977 978 if (!use_csv_output) 979 printf ("Parser self-test complete.\n"); 980} 981 982static void 983print_test_details (const test_entry_t *test) 984{ 985 printf ("%s: %s, src %s%s, mask %s%s%s, dst %s\n", 986 test->testname, 987 operator_name (test->op), 988 format_name (test->src_fmt), 989 test->src_flags & SOLID_FLAG ? " solid" : "", 990 format_name (test->mask_fmt), 991 test->mask_flags & SOLID_FLAG ? " solid" : "", 992 test->mask_flags & CA_FLAG ? " CA" : "", 993 format_name (test->dst_fmt)); 994} 995 996static void 997run_one_test (const char *pattern, double bandwidth_, pixman_bool_t prdetails) 998{ 999 test_entry_t test; 1000 1001 if (parse_test_pattern (&test, pattern) < 0) 1002 { 1003 printf ("Error: Could not parse the test pattern '%s'.\n", pattern); 1004 return; 1005 } 1006 1007 if (prdetails) 1008 { 1009 print_test_details (&test); 1010 printf ("---\n"); 1011 } 1012 1013 bench_composite (pattern, 1014 test.src_fmt, 1015 test.src_flags, 1016 test.op, 1017 test.mask_fmt, 1018 test.mask_flags, 1019 test.dst_fmt, 1020 bandwidth_ / 8); 1021} 1022 1023static void 1024run_default_tests (double bandwidth_) 1025{ 1026 int i; 1027 1028 for (i = 0; i < ARRAY_LENGTH (tests_tbl); i++) 1029 run_one_test (tests_tbl[i].testname, bandwidth_, FALSE); 1030} 1031 1032static void 1033print_explanation (void) 1034{ 1035 printf ("Benchmark for a set of most commonly used functions\n"); 1036 printf ("---\n"); 1037 printf ("All results are presented in millions of pixels per second\n"); 1038 printf ("L1 - small Xx1 rectangle (fitting L1 cache), always blitted at the same\n"); 1039 printf (" memory location with small drift in horizontal direction\n"); 1040 printf ("L2 - small XxY rectangle (fitting L2 cache), always blitted at the same\n"); 1041 printf (" memory location with small drift in horizontal direction\n"); 1042 printf ("M - large %dx%d rectangle, always blitted at the same\n", 1043 WIDTH - 64, HEIGHT); 1044 printf (" memory location with small drift in horizontal direction\n"); 1045 printf ("HT - random rectangles with %dx%d average size are copied from\n", 1046 TILEWIDTH, TILEWIDTH); 1047 printf (" one %dx%d buffer to another, traversing from left to right\n", 1048 WIDTH, HEIGHT); 1049 printf (" and from top to bottom\n"); 1050 printf ("VT - random rectangles with %dx%d average size are copied from\n", 1051 TILEWIDTH, TILEWIDTH); 1052 printf (" one %dx%d buffer to another, traversing from top to bottom\n", 1053 WIDTH, HEIGHT); 1054 printf (" and from left to right\n"); 1055 printf ("R - random rectangles with %dx%d average size are copied from\n", 1056 TILEWIDTH, TILEWIDTH); 1057 printf (" random locations of one %dx%d buffer to another\n", 1058 WIDTH, HEIGHT); 1059 printf ("RT - as R, but %dx%d average sized rectangles are copied\n", 1060 TINYWIDTH, TINYWIDTH); 1061 printf ("---\n"); 1062} 1063 1064static void 1065print_speed_scaling (double bw) 1066{ 1067 printf ("reference memcpy speed = %.1fMB/s (%.1fMP/s for 32bpp fills)\n", 1068 bw / 1000000., bw / 4000000); 1069 1070 if (use_scaling) 1071 { 1072 printf ("---\n"); 1073 if (filter == PIXMAN_FILTER_BILINEAR) 1074 printf ("BILINEAR scaling\n"); 1075 else if (filter == PIXMAN_FILTER_NEAREST) 1076 printf ("NEAREST scaling\n"); 1077 else 1078 printf ("UNKNOWN scaling\n"); 1079 } 1080 1081 printf ("---\n"); 1082} 1083 1084static void 1085usage (const char *progname) 1086{ 1087 printf ("Usage: %s [-b] [-n] [-c] [-m M] pattern\n", progname); 1088 printf (" -n : benchmark nearest scaling\n"); 1089 printf (" -b : benchmark bilinear scaling\n"); 1090 printf (" -c : print output as CSV data\n"); 1091 printf (" -m M : set reference memcpy speed to M MB/s instead of measuring it\n"); 1092} 1093 1094int 1095main (int argc, char *argv[]) 1096{ 1097 int i; 1098 const char *pattern = NULL; 1099 1100 for (i = 1; i < argc; i++) 1101 { 1102 if (argv[i][0] == '-') 1103 { 1104 if (strchr (argv[i] + 1, 'b')) 1105 { 1106 use_scaling = TRUE; 1107 filter = PIXMAN_FILTER_BILINEAR; 1108 } 1109 else if (strchr (argv[i] + 1, 'n')) 1110 { 1111 use_scaling = TRUE; 1112 filter = PIXMAN_FILTER_NEAREST; 1113 } 1114 1115 if (strchr (argv[i] + 1, 'c')) 1116 use_csv_output = TRUE; 1117 1118 if (strcmp (argv[i], "-m") == 0 && i + 1 < argc) 1119 bandwidth = atof (argv[++i]) * 1e6; 1120 } 1121 else 1122 { 1123 if (pattern) 1124 { 1125 pattern = NULL; 1126 printf ("Error: extra arguments given.\n"); 1127 break; 1128 } 1129 pattern = argv[i]; 1130 } 1131 } 1132 1133 if (!pattern) 1134 { 1135 usage (argv[0]); 1136 return 1; 1137 } 1138 1139 parser_self_test (); 1140 1141 src = aligned_malloc (4096, BUFSIZE * 3); 1142 memset (src, 0xCC, BUFSIZE * 3); 1143 dst = src + (BUFSIZE / 4); 1144 mask = dst + (BUFSIZE / 4); 1145 1146 if (!use_csv_output) 1147 print_explanation (); 1148 1149 if (bandwidth < 1.0) 1150 bandwidth = bench_memcpy (); 1151 if (!use_csv_output) 1152 print_speed_scaling (bandwidth); 1153 1154 if (strcmp (pattern, "all") == 0) 1155 run_default_tests (bandwidth); 1156 else 1157 run_one_test (pattern, bandwidth, !use_csv_output); 1158 1159 free (src); 1160 return 0; 1161} 1162