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