x11perf.c revision 6f13e4f1
1/**************************************************************************** 2Copyright 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 3 4 All Rights Reserved 5 6Permission to use, copy, modify, and distribute this software and its 7documentation for any purpose and without fee is hereby granted, 8provided that the above copyright notice appear in all copies and that 9both that copyright notice and this permission notice appear in 10supporting documentation, and that the name of Digital not be 11used in advertising or publicity pertaining to distribution of the 12software without specific, written prior permission. 13 14DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20SOFTWARE. 21 22****************************************************************************/ 23 24#include <stdio.h> 25#include <ctype.h> 26#include <signal.h> 27#include <stdint.h> 28 29#ifndef VMS 30#include <X11/Xatom.h> 31#include <X11/Xos.h> 32#else 33#include <decw$include/Xatom.h> 34#endif 35#include "x11perf.h" 36#include <X11/Xmu/SysUtil.h> 37 38#include <time.h> 39#define Time_t time_t 40#include <stdlib.h> 41 42/* Only for working on ``fake'' servers, for hardware that doesn't exist */ 43static Bool drawToFakeServer = False; 44static Bool falsePrecision = False; 45static Pixmap tileToQuery = None; 46static char *displayName; 47int abortTest; 48 49typedef struct _RopNames { const char *name; int rop; } RopNameRec, *RopNamePtr; 50 51static RopNameRec ropNames[] = { 52 { "clear", GXclear }, /* 0 */ 53 { "and", GXand }, /* src AND dst */ 54 { "andReverse", GXandReverse }, /* src AND NOT dst */ 55 { "copy", GXcopy }, /* src */ 56 { "andInverted", GXandInverted }, /* NOT src AND dst */ 57 { "noop", GXnoop }, /* dst */ 58 { "xor", GXxor }, /* src XOR dst */ 59 { "or", GXor }, /* src OR dst */ 60 { "nor", GXnor }, /* NOT src AND NOT dst */ 61 { "equiv", GXequiv }, /* NOT src XOR dst */ 62 { "invert", GXinvert }, /* NOT dst */ 63 { "orReverse", GXorReverse }, /* src OR NOT dst */ 64 { "copyInverted", GXcopyInverted }, /* NOT src */ 65 { "orInverted", GXorInverted }, /* NOT src OR dst */ 66 { "nand", GXnand }, /* NOT src OR NOT dst */ 67 { "set", GXset } /* 1 */ 68}; 69 70static RopNameRec popNames[] = { 71 { "Clear", PictOpClear }, 72 { "Src", PictOpSrc }, 73 { "Dst", PictOpDst }, 74 { "Over", PictOpOver }, 75 { "OverReverse", PictOpOverReverse }, 76 { "In", PictOpIn }, 77 { "InReverse", PictOpInReverse }, 78 { "Out", PictOpOut }, 79 { "OutReverse", PictOpOutReverse }, 80 { "Atop", PictOpAtop }, 81 { "AtopReverse", PictOpAtopReverse }, 82 { "Xor", PictOpXor }, 83 { "Add", PictOpAdd }, 84 { "Saturate", PictOpSaturate }, 85}; 86 87static RopNameRec formatNames[] = { 88 { "RGB24", PictStandardRGB24 }, 89 { "ARGB32", PictStandardARGB32 }, 90 { "A8", PictStandardA8 }, 91 { "A4", PictStandardA4 }, 92 { "A1", PictStandardA1 }, 93 { "NATIVE", PictStandardNative }, 94}; 95 96static const char *(visualClassNames)[] = { 97 "StaticGray", 98 "GrayScale", 99 "StaticColor", 100 "PseudoColor", 101 "TrueColor", 102 "DirectColor" 103}; 104 105static Bool labels = False; 106static int repeat = 5; 107static int seconds = 5; 108static int delay = 0; 109 110static Window status; /* Status window and GC */ 111static GC tgc; 112static int HSx, HSy; 113 114static double syncTime = 0.0; 115 116static int saveargc; 117static char **saveargv; 118 119#define NUM_ROPS 16 120static int numRops = 1; 121static int rops[NUM_ROPS] = { GXcopy }; 122#define NUM_POPS 14 123static int numPops = 1; 124static int pops[NUM_POPS] = { PictOpOver }; 125#define NUM_FORMATS 6 126static int numFormats = 1; 127static int formats[NUM_FORMATS] = { PictStandardNative }; 128static int numPlanemasks = 1; 129static unsigned long planemasks[256] = { (unsigned long)~0 }; 130 131static const char *foreground = NULL; 132static const char *background = NULL; 133static const char *ddbackground = NULL; 134static int clips = 0; 135 136static int numSubWindows = 7; 137static unsigned long subWindows[] = {4, 16, 25, 50, 75, 100, 200, 0}; 138 139static int fixedReps = 0; 140 141static Bool *doit; 142 143static XRectangle ws[] = { /* Clip rectangles */ 144 {195, 195, 120, 120}, 145 { 45, 145, 120, 120}, 146 {345, 245, 120, 120}, 147 { 45, 275, 120, 120}, 148 {345, 115, 120, 120}, 149 {195, 325, 120, 120} 150 151}; 152#define MAXCLIP (sizeof(ws) / sizeof(ws[0])) 153static Window clipWindows[MAXCLIP]; 154static Colormap cmap; 155static int depth = -1; /* -1 means use default depth */ 156static int vclass = -1; /* -1 means use CopyFromParent */ 157 158/* ScreenSaver state */ 159static XParmRec xparms; 160static int ssTimeout, ssInterval, ssPreferBlanking, ssAllowExposures; 161 162/* Static functions */ 163static int GetWords(int argi, int argc, char **argv, char **wordsp, int *nump); 164static int GetNumbers(int argi, int argc, char **argv, unsigned long *intsp, 165 int *nump); 166static int GetRops(int argi, int argc, char **argv, int *ropsp, int *nump); 167static int GetPops(int argi, int argc, char **argv, int *popsp, int *nump); 168static int GetFormats(int argi, int argc, char **argv, int *formatsp, int *nump); 169static int FormatFromName (char *name); 170static const char *NameFromFormat (int format); 171 172 173/************************************************ 174* time related stuff * 175************************************************/ 176 177#ifdef VMS 178 179typedef struct _vms_time { 180 unsigned long low; 181 unsigned long high; 182}vms_time; 183 184struct timeval { 185 long tv_sec; /* seconds since Jan. 1, 1970 */ 186 long tv_usec; /* and microseconds */ 187}; 188 189struct timezone { 190 int tz_minuteswest; /* of Greenwich */ 191 int tz_dsttime; /* type of dst correction to apply */ 192}; 193 194 195static int firsttime = True; 196static vms_time basetime; 197 198int gettimeofday(tp) 199 struct timeval *tp; 200{ 201 vms_time current_time, resultant; 202 unsigned long mumble, foo; 203 int status; 204 205 if (firsttime) { 206 sys$gettim(&basetime); 207 firsttime = False; 208 } 209 sys$gettim(¤t_time); 210 resultant.high = current_time.high - basetime.high; 211 resultant.low = current_time.low - basetime.low; 212 if (current_time.low < basetime.low) { 213 resultant.high -= 1; 214 } 215 status = lib$ediv( &(10000000), &resultant, &tp->tv_sec, &tp->tv_usec); 216 tp->tv_usec /= 10; 217 return 0; 218} 219 220#endif 221 222static struct timeval start; 223 224static void 225PrintTime(void) 226{ 227 Time_t t; 228 229 t = time((Time_t *)NULL); 230 printf("%s\n", ctime(&t)); 231} 232 233static void 234InitTimes(void) 235{ 236 X_GETTIMEOFDAY(&start); 237} 238 239static double 240ElapsedTime(double correction) 241{ 242 struct timeval stop; 243 244 X_GETTIMEOFDAY(&stop); 245 if (stop.tv_usec < start.tv_usec) { 246 stop.tv_usec += 1000000; 247 stop.tv_sec -= 1; 248 } 249 return (double)(stop.tv_usec - start.tv_usec) + 250 (1000000.0 * (double)(stop.tv_sec - start.tv_sec)) - correction; 251} 252 253static double 254RoundTo3Digits(double d) 255{ 256 /* It's kind of silly to print out things like ``193658.4/sec'' so just 257 junk all but 3 most significant digits. */ 258 double exponent, sign; 259 260 if (falsePrecision) 261 return d; 262 263 exponent = 1.0; 264 /* the code below won't work if d should happen to be non-positive. */ 265 if (d < 0.0) { 266 d = -d; 267 sign = -1.0; 268 } else 269 sign = 1.0; 270 if (d >= 1000.0) { 271 do { 272 exponent *= 10.0; 273 } while (d/exponent >= 1000.0); 274 d = (double)((int) (d/exponent + 0.5)); 275 d *= exponent; 276 } else { 277 if (d != 0.0) { 278 while (d*exponent < 100.0) { 279 exponent *= 10.0; 280 } 281 } 282 d = (double)((int) (d*exponent + 0.5)); 283 d /= exponent; 284 } 285 return d * sign; 286} 287 288 289static void 290ReportTimes(double usecs, int64_t n, char *str, int average) 291{ 292 if(usecs != 0.0) 293 { 294 double msecsperobj = usecs / (1000.0 * (double)n); 295 double objspersec = (double) n * 1000000.0 / usecs; 296 297 /* Round obj/sec to 3 significant digits. Leave msec untouched, to 298 allow averaging results from several repetitions. */ 299 objspersec = RoundTo3Digits(objspersec); 300 301 if (average) { 302 printf("%11lld trep @ %8.4f msec (%8.1f/sec): %s\n", 303 (long long) n, msecsperobj, objspersec, str); 304 } else { 305 printf("%11lld reps @ %8.4f msec (%8.1f/sec): %s\n", 306 (long long) n, msecsperobj, objspersec, str); 307 } 308 } else { 309 printf("%6lld %sreps @ 0.0 msec (unmeasurably fast): %s\n", 310 (long long) n, average ? "t" : "", str); 311 } 312 313} 314 315 316 317/************************************************ 318* Generic X stuff * 319************************************************/ 320 321static char *program_name; 322static void usage(void) _X_NORETURN; 323 324/* 325 * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obsolete) 326 * If found, remove it from command line. Don't go past a lone -. 327 */ 328static char * 329Get_Display_Name(int *pargc, /* MODIFIED */ 330 char **argv) /* MODIFIED */ 331{ 332 int argc = *pargc; 333 char **pargv = argv+1; 334 char *displayname = NULL; 335 336 for (int i = 1; i != argc; i++) { 337 char *arg = argv[i]; 338 339 if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) { 340 if (++i >= argc) usage (); 341 342 displayname = argv[i]; 343 *pargc -= 2; 344 continue; 345 } 346 if (!strcmp(arg,"-")) { 347 while (i<argc) *pargv++ = argv[i++]; 348 break; 349 } 350 *pargv++ = arg; 351 } 352 353 *pargv = NULL; 354 return (displayname); 355} 356 357 358/* 359 * GetVersion (argc, argv) Look for -v1.2, -v1.3, or -v1.4. 360 * If found remove it from command line. Don't go past a lone -. 361 */ 362 363static Version 364GetVersion(int *pargc, /* MODIFIED */ 365 char **argv) /* MODIFIED */ 366{ 367 int argc = *pargc; 368 char **pargv = argv+1; 369 Version version = VERSION1_6; 370 Bool found = False; 371 372 for (int i = 1; i != argc; i++) { 373 char *arg = argv[i]; 374 375 if (!strcmp (arg, "-v1.2")) { 376 version = VERSION1_2; 377 *pargc -= 1; 378 if (found) { 379 fprintf(stderr, "Warning: multiple version specifications\n"); 380 } 381 found = True; 382 continue; 383 } 384 if (!strcmp (arg, "-v1.3")) { 385 version = VERSION1_3; 386 *pargc -= 1; 387 if (found) { 388 fprintf(stderr, "Warning: multiple version specifications\n"); 389 } 390 found = True; 391 continue; 392 } 393 if (!strcmp (arg, "-v1.4")) { 394 version = VERSION1_4; 395 *pargc -= 1; 396 if (found) { 397 fprintf(stderr, "Warning: multiple version specifications\n"); 398 } 399 found = True; 400 continue; 401 } 402 if (!strcmp (arg, "-v1.5")) { 403 version = VERSION1_5; 404 *pargc -= 1; 405 if (found) { 406 fprintf(stderr, "Warning: multiple version specifications\n"); 407 } 408 found = True; 409 continue; 410 } 411 if (!strcmp(arg,"-")) { 412 while (i<argc) *pargv++ = argv[i++]; 413 break; 414 } 415 *pargv++ = arg; 416 } 417 418 *pargv = NULL; 419 return (version); 420} 421 422 423 424/* 425 * Open_Display: Routine to open a display with correct error handling. 426 */ 427static Display * 428Open_Display(char *display_name) 429{ 430 Display *d; 431 432 d = XOpenDisplay(display_name); 433 if (d == NULL) { 434 fprintf (stderr, "%s: unable to open display '%s'\n", 435 program_name, XDisplayName (display_name)); 436 exit(1); 437 } 438 439 return(d); 440} 441 442static void 443Cleanup(int sig) 444{ 445 abortTest = sig; 446} 447 448void 449AbortTest(void) 450{ 451 fflush(stdout); 452 453 XSetScreenSaver(xparms.d, ssTimeout, ssInterval, ssPreferBlanking, 454 ssAllowExposures); 455 XFlush(xparms.d); 456 exit (abortTest); 457} 458 459/************************************************ 460* Performance stuff * 461************************************************/ 462 463 464static void 465usage(void) 466{ 467 int i = 0; 468 static const char *help_message = 469"where options include:\n" 470" -display <host:display> the X server to contact\n" 471" -sync do the tests in synchronous mode\n" 472" -pack pack rectangles right next to each other\n" 473" -repeat <n> do tests <n> times (default = 5)\n" 474" -time <s> do tests for <s> seconds each (default = 5)\n" 475" -pause <s> pause for <s> seconds between each run\n" 476/* 477" -draw draw after each test -- pmax only\n" 478*/ 479" -all do all tests\n" 480" -range <test1>[,<test2>] like all, but do <test1> to <test2>\n" 481" -labels generate test labels for use by fillblnk\n" 482" -fg the foreground color to use\n" 483" -bg the background color to use\n" 484" -clips <default> default number of clip windows per test\n" 485" -ddbg the background color to use for DoubleDash\n" 486" -rop <rop0 rop1 ...> use the given rops to draw (default = GXcopy)\n" 487" -pm <pm0 pm1 ...> use the given planemasks to draw (default = ~0)\n" 488" -depth <depth> use a visual with <depth> planes per pixel\n" 489" -vclass <class> the visual class to use (default = root)\n" 490" -reps <n> fix the rep count (default = auto scale)\n" 491" -subs <s0 s1 ...> a list of the number of sub-windows to use\n" 492" -v1.2 perform only v1.2 tests using old semantics\n" 493" -v1.3 perform only v1.3 tests using old semantics\n" 494" -su request save unders on windows\n" 495" -bs <backing_store_hint> WhenMapped or Always (default = NotUseful)\n" 496; 497 498 fflush(stdout); 499 fprintf(stderr, "usage: %s [-options ...]\n%s", program_name, help_message); 500 while (test[i].option != NULL) { 501 if (test[i].versions & xparms.version ) { 502 fprintf(stderr, " %-24s %s\n", 503 test[i].option, 504 test[i].label14 ? test[i].label14 : test[i].label); 505 } 506 i++; 507 } 508 fprintf(stderr, "\n"); 509 510 /* Print out original command line as the above usage message is so long */ 511 for (i = 0; i != saveargc; i++) { 512 fprintf(stderr, "%s ", saveargv[i]); 513 } 514 fprintf(stderr, "\n\n"); 515 exit (1); 516} 517 518void 519NullProc(XParms xp, Parms p) 520{ 521} 522 523int 524NullInitProc(XParms xp, Parms p, int64_t reps) 525{ 526 return reps; 527} 528 529static void 530HardwareSync(XParms xp) 531{ 532 /* 533 * Some graphics hardware allows the server to claim it is done, 534 * while in reality the hardware is busily working away. So fetch 535 * a pixel from the drawable that was drawn to, which should be 536 * enough to make the server wait for the graphics hardware. 537 */ 538 XImage *image; 539 540 image = XGetImage(xp->d, xp->p ? xp->p : xp->w, HSx, HSy, 541 1, 1, ~0, ZPixmap); 542 if (image) XDestroyImage(image); 543} 544 545static void 546DoHardwareSync(XParms xp, Parms p, int64_t reps) 547{ 548 for (int i = 0; i != reps; i++) { 549 HardwareSync(xp); 550 CheckAbort (); 551 } 552} 553 554static Test syncTest = { 555 "syncTime", "Internal test for finding how long HardwareSync takes", NULL, 556 NullInitProc, DoHardwareSync, NullProc, NullProc, 557 V1_2FEATURE, NONROP, 0, 558 {1} 559}; 560 561 562static Window 563CreatePerfWindow(XParms xp, int x, int y, int width, int height) 564{ 565 XSetWindowAttributes xswa; 566 Window w; 567/* 568 Screen *s; 569 int su; 570 571 s = DefaultScreenOfDisplay(xp->d); 572 su = XDoesBackingStore(s); 573 printf("Backing store of screen returns %d\n", su); 574 su = XDoesSaveUnders(s); 575 printf("Save unders of screen returns %d\n", su); 576 su = XPlanesOfScreen(s); 577 printf("Planes of screen returns %d\n", su); 578*/ 579 xswa.background_pixel = xp->background; 580 xswa.border_pixel = xp->foreground; 581 xswa.colormap = cmap; 582 xswa.override_redirect = True; 583 xswa.backing_store = xp->backing_store; 584 xswa.save_under = xp->save_under; 585 w = XCreateWindow(xp->d, DefaultRootWindow(xp->d), x, y, width, height, 1, 586 xp->vinfo.depth, CopyFromParent, xp->vinfo.visual, 587 CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect 588 | CWBackingStore | CWSaveUnder, &xswa); 589 XMapWindow (xp->d, w); 590 return w; 591} 592 593 594static void 595CreateClipWindows(XParms xp, int clips) 596{ 597 XWindowAttributes xwa; 598 599 (void) XGetWindowAttributes(xp->d, xp->w, &xwa); 600 if (clips > MAXCLIP) clips = MAXCLIP; 601 for (int j = 0; j != clips; j++) { 602 clipWindows[j] = CreatePerfWindow(xp, 603 xwa.x + ws[j].x, xwa.y + ws[j].y, ws[j].width, ws[j].height); 604 } 605} /* CreateClipWindows */ 606 607 608static void 609DestroyClipWindows(XParms xp, int clips) 610{ 611 if (clips > MAXCLIP) clips = MAXCLIP; 612 for (int j = 0; j != clips; j++) { 613 XDestroyWindow(xp->d, clipWindows[j]); 614 } 615} /* DestroyClipWindows */ 616 617 618static double 619DoTest(XParms xp, Test *test, int64_t reps) 620{ 621 double time; 622 unsigned int ret_width, ret_height; 623 624 /* Tell screen-saver to restart counting again. See comments below for the 625 XSetScreenSaver call. */ 626 XForceScreenSaver(xp->d, ScreenSaverReset); 627 HardwareSync (xp); 628 InitTimes (); 629 (*test->proc) (xp, &test->parms, reps); 630 HardwareSync(xp); 631 632 time = ElapsedTime(syncTime); 633 if (time < 0.0) time = 0.0; 634 CheckAbort (); 635 if (drawToFakeServer) 636 XQueryBestSize(xp->d, TileShape, tileToQuery, 637 32, 32, &ret_width, &ret_height); 638 (*test->passCleanup) (xp, &test->parms); 639 return time; 640} 641 642 643static int64_t 644CalibrateTest(XParms xp, Test *test, int seconds, double *usecperobj) 645{ 646#define goal 2500000.0 /* Try to get up to 2.5 seconds */ 647#define enough 2000000.0 /* But settle for 2.0 seconds */ 648#define tick 10000.0 /* Assume clock not faster than .01 seconds */ 649 650 double usecs; 651 int64_t reps, didreps; /* Reps desired, reps performed */ 652 int exponent; 653 654 /* Attempt to get an idea how long each rep lasts by getting enough 655 reps to last more tan enough. Then scale that up to the number of 656 seconds desired. 657 658 If init call to test ever fails, return False and test will be skipped. 659 */ 660 661 if (fixedReps != 0) { 662 return fixedReps; 663 } 664 reps = 1; 665 for (;;) { 666 XDestroySubwindows(xp->d, xp->w); 667 XClearWindow(xp->d, xp->w); 668 didreps = (*test->init) (xp, &test->parms, reps); 669 CheckAbort (); 670 if (didreps == 0) { 671 return 0; 672 } 673 if ( test->clips < clips ) 674 test->clips = clips ; 675 /* Create clip windows if requested */ 676 CreateClipWindows(xp, test->clips); 677 HardwareSync(xp); 678 InitTimes(); 679 (*test->proc) (xp, &test->parms, reps); 680 HardwareSync(xp); 681 usecs = ElapsedTime(syncTime); 682 (*test->passCleanup) (xp, &test->parms); 683 (*test->cleanup) (xp, &test->parms); 684 DestroyClipWindows(xp, test->clips); 685 CheckAbort (); 686 687 if (didreps != reps) { 688 /* The test can't do the number of reps as we asked for. 689 Give up */ 690 *usecperobj = 691 usecs / (double)(didreps * test->parms.objects); 692 return didreps; 693 } 694 /* Did we go long enough? */ 695 if (usecs >= enough) break; 696 697 /* Don't let too short a clock make new reps wildly high */ 698 if (usecs <= tick)reps = reps*10; 699 else{ 700 /* Try to get up to goal seconds. */ 701 reps = (int) (goal * (double)reps / usecs) + 1; 702 } 703 } 704 705 *usecperobj = usecs / (double) (reps * test->parms.objects); 706 reps = (int) ((double)seconds * 1000000.0 * (double)reps / usecs) + 1; 707 708 /* Now round reps up to 1 digit accuracy, so we don't get stupid-looking 709 numbers of repetitions. */ 710 reps--; 711 exponent = 1; 712 while (reps > 9) { 713 reps /= 10; 714 exponent *= 10; 715 } 716 reps = (reps + 1) * exponent; 717 return reps; 718} /* CalibrateTest */ 719 720static void 721CreatePerfGCs(XParms xp, int func, unsigned long pm) 722{ 723 XGCValues gcvfg, gcvbg, gcvddbg,gcvddfg; 724 unsigned long fg, bg, ddbg; 725 726 fg = xp->foreground; 727 bg = xp->background; 728 ddbg = xp->ddbackground; 729 gcvfg.graphics_exposures = False; 730 gcvbg.graphics_exposures = False; 731 gcvddfg.graphics_exposures = False; 732 gcvddbg.graphics_exposures = False; 733 gcvfg.plane_mask = pm; 734 gcvbg.plane_mask = pm; 735 gcvddfg.plane_mask = pm; 736 gcvddbg.plane_mask = pm; 737 gcvfg.function = func; 738 gcvbg.function = func; 739 gcvddfg.function = func; 740 gcvddbg.function = func; 741 742 if (func == GXxor) { 743 /* Make test look good visually if possible */ 744 gcvbg.foreground = gcvfg.foreground = bg ^ fg; 745 gcvbg.background = gcvfg.background = bg; 746 /* Double Dash GCs (This doesn't make a huge amount of sense) */ 747 gcvddbg.foreground = gcvddfg.foreground = bg ^ fg; 748 gcvddbg.background = gcvddfg.foreground = bg ^ ddbg; 749 } else { 750 gcvfg.foreground = fg; 751 gcvfg.background = bg; 752 gcvbg.foreground = bg; 753 gcvbg.background = fg; 754 gcvddfg.foreground = fg; 755 gcvddfg.background = ddbg; 756 gcvddbg.foreground = ddbg; 757 gcvddbg.background = fg; 758 } 759 xp->fggc = XCreateGC(xp->d, xp->w, 760 GCForeground | GCBackground | GCGraphicsExposures 761 | GCFunction | GCPlaneMask, &gcvfg); 762 xp->bggc = XCreateGC(xp->d, xp->w, 763 GCForeground | GCBackground | GCGraphicsExposures 764 | GCFunction | GCPlaneMask, &gcvbg); 765 xp->ddfggc = XCreateGC(xp->d, xp->w, 766 GCForeground | GCBackground | GCGraphicsExposures 767 | GCFunction | GCPlaneMask, &gcvddfg); 768 xp->ddbggc = XCreateGC(xp->d, xp->w, 769 GCForeground | GCBackground | GCGraphicsExposures 770 | GCFunction | GCPlaneMask, &gcvddbg); 771} 772 773 774static void 775DestroyPerfGCs(XParms xp) 776{ 777 XFreeGC(xp->d, xp->fggc); 778 XFreeGC(xp->d, xp->bggc); 779 XFreeGC(xp->d, xp->ddfggc); 780 XFreeGC(xp->d, xp->ddbggc); 781} 782 783static unsigned long 784AllocateColor(Display *display, const char *name, unsigned long pixel) 785{ 786 XColor color; 787 788 if (name != NULL) { 789 /* Try to parse color name */ 790 if (XParseColor(display, cmap, name, &color)) { 791 if (XAllocColor(display, cmap, &color)) { 792 pixel = color.pixel; 793 } else { 794 (void) fprintf(stderr, 795 "Can't allocate colormap entry for color %s\n", name); 796 } 797 } else { 798 if(*name >= '0' && *name <= '9') 799 pixel = atoi(name); 800 else 801 (void) fprintf(stderr, "Can't parse color name %s\n", name); 802 } 803 } 804 return pixel; 805} /* AllocateColor */ 806 807 808static void 809DisplayStatus(Display *d, const char *message, const char *test, int try) 810{ 811 char s[500]; 812 813 XClearWindow(d, status); 814 sprintf(s, "%d %s %s", try, message, test); 815 /* We should really look at the height, descent of the font, etc. but 816 who cares. This works. */ 817 XDrawString(d, status, tgc, 10, 13, s, strlen(s)); 818} 819 820 821static void 822ProcessTest(XParms xp, Test *test, int func, unsigned long pm, char *label) 823{ 824 double time, totalTime; 825 long long reps; 826 827 xp->planemask = pm; 828 xp->func = func; 829 if (test->testType == COMP) 830 { 831 func = GXcopy; 832 pm = ~0L; 833 } 834 CreatePerfGCs(xp, func, pm); 835 DisplayStatus(xp->d, "Calibrating", label, 0); 836 reps = CalibrateTest(xp, test, seconds, &time); 837 if (reps != 0) { 838 XDestroySubwindows(xp->d, xp->w); 839 XClearWindow(xp->d, xp->w); 840 reps = (*test->init) (xp, &test->parms, reps); 841 if (abortTest) 842 AbortTest (); 843 /* 844 * if using fixedReps then will not have done CalibrateTest so must 845 * check result of init for 0 here 846 */ 847 if(reps == 0){ 848 DestroyPerfGCs(xp); 849 return; 850 } 851 /* Create clip windows if requested */ 852 CreateClipWindows(xp, test->clips); 853 854 totalTime = 0.0; 855 for (int j = 0; j != repeat; j++) { 856 DisplayStatus(xp->d, "Testing", label, j+1); 857 time = DoTest(xp, test, reps); 858 if (abortTest) 859 AbortTest (); 860 totalTime += time; 861 ReportTimes (time, reps * test->parms.objects, 862 label, False); 863 if (delay) 864 sleep(delay); 865 } 866 if (repeat > 1) { 867 ReportTimes(totalTime, 868 repeat * reps * test->parms.objects, 869 label, True); 870 } 871 (*test->cleanup) (xp, &test->parms); 872 DestroyClipWindows(xp, test->clips); 873 } else { 874 /* Test failed to initialize properly */ 875 } 876 printf ("\n"); 877 fflush(stdout); 878 DestroyPerfGCs(xp); 879} /* ProcessTest */ 880 881#define Strstr strstr 882 883#define LABELP(i) (test[i].label14 && (xparms.version >= VERSION1_4) \ 884 ? test[i].label14 : test[i].label) 885 886int 887main(int argc, char *argv[]) 888{ 889 int i, j, n, skip; 890 int numTests; /* Even though the linker knows, we don't. */ 891 char hostname[100]; 892 Bool foundOne = False; 893 Bool synchronous = False; 894 XGCValues tgcv; 895 int screen; 896 int rop, pm; 897 int pop, format; 898 int window_y, window_x; 899 XVisualInfo *vinfolist, vinfotempl; 900 unsigned long vmask; 901 902 /* Save away argv, argc, for usage to print out */ 903 saveargc = argc; 904 saveargv = malloc(argc * sizeof(char *)); 905 for (i = 0; i != argc; i++) { 906 saveargv[i] = argv[i]; 907 } 908 909 xparms.pack = False; 910 xparms.save_under = False; 911 xparms.backing_store = NotUseful; 912 913 /* Count number of tests */ 914 ForEachTest(numTests); 915 doit = calloc(numTests, sizeof(Bool)); 916 917 /* Parse arguments */ 918 program_name = argv[0]; 919 displayName = Get_Display_Name (&argc, argv); 920 xparms.version = GetVersion(&argc, argv); 921 for (i = 1; i != argc; i++) { 922 if (strcmp (argv[i], "-all") == 0) { 923 ForEachTest (j) 924 doit[j] = test[j].versions & xparms.version; 925 foundOne = True; 926 } else if (strcmp (argv[i], "-labels") == 0) { 927 labels = True; 928 } else if (strcmp(argv[i], "-range") == 0) { 929 char *cp1; 930 char *cp2; 931 932 if (argc <= ++i) 933 usage(); 934 cp1 = argv[i]; 935 if (*cp1 == '-') 936 cp1++; 937 for (cp2 = cp1; *cp2 != '\0' && *cp2 != ','; cp2++) {}; 938 if (*cp2 == ',') { 939 *cp2++ = '\0'; 940 if (*cp2 == '-') 941 cp2++; 942 } else { 943 cp2 = "-"; 944 } 945 ForEachTest (j) { 946 if (strcmp (cp1, (test[j].option) + 1) == 0 && 947 (test[j].versions & xparms.version)) { 948 int k = j; 949 do { 950 doit[k] = test[j].versions & xparms.version; 951 } while (!(strcmp(cp2, (test[k].option + 1)) == 0 && 952 (test[k].versions & xparms.version)) && 953 test[++k].option != NULL); 954 if (*cp2 != '-' && test[k].option == NULL) 955 usage(); 956 break; 957 } 958 } 959 if (test[j].option == NULL) 960 usage(); 961 foundOne = True; 962 } else if (strcmp (argv[i], "-sync") == 0) { 963 synchronous = True; 964 } else if (strcmp (argv[i], "-pack") == 0) { 965 xparms.pack = True; 966 } else if (strcmp (argv[i], "-draw") == 0) { 967 drawToFakeServer = True; 968 } else if (strcmp (argv[i], "-falseprecision") == 0) { 969 falsePrecision = True; 970 } else if (strcmp (argv[i], "-repeat") == 0) { 971 i++; 972 if (argc <= i) 973 usage (); 974 repeat = atoi (argv[i]); 975 if (repeat <= 0) 976 usage (); 977 } else if (strcmp (argv[i], "-time") == 0) { 978 i++; 979 if (argc <= i) 980 usage (); 981 seconds = atoi (argv[i]); 982 if (seconds <= 0) 983 usage (); 984 } else if (strcmp (argv[i], "-pause") == 0) { 985 ++i; 986 if (argc <= i) 987 usage (); 988 delay = atoi (argv[i]); 989 if (delay < 0) 990 usage (); 991 } else if (strcmp(argv[i], "-fg") == 0) { 992 i++; 993 if (argc <= i) 994 usage (); 995 foreground = argv[i]; 996 } else if (strcmp(argv[i], "-bg") == 0) { 997 i++; 998 if (argc <= i) 999 usage (); 1000 background = argv[i]; 1001 if(ddbackground == NULL) 1002 ddbackground = argv[i]; 1003 } else if (strcmp(argv[i], "-clips") == 0 ) { 1004 i++; 1005 if (argc <= i) 1006 usage (); 1007 clips = atoi( argv[i] ); 1008 } else if (strcmp(argv[i], "-ddbg") == 0) { 1009 if (argc <= i) 1010 usage (); 1011 i++; 1012 ddbackground = argv[i]; 1013 } else if (strcmp(argv[i], "-rop") == 0) { 1014 skip = GetRops (i+1, argc, argv, rops, &numRops); 1015 i += skip; 1016 } else if (strcmp(argv[i], "-pop") == 0) { 1017 skip = GetPops (i+1, argc, argv, pops, &numPops); 1018 i += skip; 1019 } else if (strcmp(argv[i], "-format") == 0) { 1020 skip = GetFormats (i+1, argc, argv, formats, &numFormats); 1021 i += skip; 1022 } else if (strcmp(argv[i], "-pm") == 0) { 1023 skip = GetNumbers (i+1, argc, argv, planemasks, &numPlanemasks); 1024 i += skip; 1025 } else if (strcmp(argv[i], "-xor") == 0) { 1026 numRops = 1; 1027 rops[0] = GXxor; 1028 } else if (strcmp (argv[i], "-both") == 0) { 1029 numRops = 2; 1030 rops[0] = GXcopy; 1031 rops[1] = GXxor; 1032 } else if (strcmp(argv[i], "-reps") == 0) { 1033 i++; 1034 if (argc <= i) 1035 usage (); 1036 fixedReps = atoi (argv[i]); 1037 if (fixedReps <= 0) 1038 usage (); 1039 } else if (strcmp(argv[i], "-depth") == 0) { 1040 i++; 1041 if (argc <= i) 1042 usage (); 1043 depth = atoi(argv[i]); 1044 if (depth <= 0) 1045 usage (); 1046 } else if (strcmp(argv[i], "-vclass") == 0) { 1047 i++; 1048 if (argc <= i) 1049 usage (); 1050 for (j = StaticGray; j <= DirectColor; j++) { 1051 if (strcmp(argv[i], visualClassNames[j]) == 0) { 1052 vclass = j; 1053 break; 1054 } 1055 } 1056 if (vclass < 0) 1057 usage (); 1058 } else if (strcmp(argv[i], "-subs") == 0) { 1059 skip = GetNumbers (i+1, argc, argv, subWindows, &numSubWindows); 1060 i += skip; 1061 } else if (strcmp(argv[i], "-v1.2") == 0) { 1062 xparms.version = VERSION1_2; 1063 } else if (strcmp(argv[i], "-v1.3") == 0) { 1064 xparms.version = VERSION1_3; 1065 } else if (strcmp(argv[i], "-su") == 0) { 1066 xparms.save_under = True; 1067 } else if (strcmp(argv[i], "-bs") == 0) { 1068 i++; 1069 if (argc <= i) 1070 usage (); 1071 if (strcmp(argv[i], "WhenMapped") == 0) { 1072 xparms.backing_store = WhenMapped; 1073 } else if (strcmp(argv[i], "Always") == 0) { 1074 xparms.backing_store = Always; 1075 } else usage (); 1076 } else { 1077 int len,found; 1078 ForEachTest (j) { 1079 if (strcmp (argv[i], test[j].option) == 0 && 1080 (test[j].versions & xparms.version)) { 1081 doit[j] = True; 1082 goto LegalOption; 1083 } 1084 } 1085 found = False; 1086 len = strlen(argv[i]); 1087 if(len>=3) 1088 ForEachTest (j) { 1089 if (Strstr (test[j].option, argv[i]+1) != NULL) { 1090 fprintf(stderr," -> %s %s\n", test[j].option, LABELP(j)); 1091 doit[j] = found = True; 1092 } 1093 } 1094 if(!found) 1095 ForEachTest (j) { 1096 if (Strstr (LABELP(j), argv[i]+1) != NULL) { 1097 fprintf(stderr," -> %s %s\n", test[j].option, LABELP(j)); 1098 doit[j] = found = True; 1099 } 1100 } 1101 if(!found) 1102 usage (); 1103 LegalOption: 1104 foundOne = True; 1105 } 1106 } 1107 1108 if (labels) { 1109 /* Just print out list of tests for use with .sh programs that 1110 assemble data from different x11perf runs into a nice format */ 1111 ForEachTest (i) { 1112 if (doit[i]) { 1113 switch (test[i].testType) { 1114 case NONROP: 1115 printf ("%s\n", LABELP(i)); 1116 break; 1117 1118 case ROP: 1119 /* Run it through all specified rops and planemasks */ 1120 for (rop = 0; rop < numRops; rop++) { 1121 for (pm = 0; pm < numPlanemasks; pm++) { 1122 if (planemasks[pm] == ~0) { 1123 if (rops[rop] == GXcopy) { 1124 printf ("%s\n", LABELP(i)); 1125 } else { 1126 printf ("(%s) %s\n", 1127 ropNames[rops[rop]].name, 1128 LABELP(i)); 1129 } 1130 } else { 1131 printf ("(%s 0x%lx) %s\n", 1132 ropNames[rops[rop]].name, 1133 planemasks[pm], 1134 LABELP(i)); 1135 } 1136 } /* for pm */ 1137 } /* for rop */ 1138 break; 1139 1140 case PLANEMASK: 1141 /* Run it through all specified planemasks */ 1142 for (pm = 0; pm < numPlanemasks; pm++) { 1143 if (planemasks[pm] == ~0) { 1144 printf ("%s\n", LABELP(i)); 1145 } else { 1146 printf ("(0x%lx) %s\n", 1147 planemasks[pm], 1148 LABELP(i)); 1149 } 1150 } /* for pm */ 1151 break; 1152 1153 case WINDOW: 1154 for (int child = 0; child != numSubWindows; child++) { 1155 printf ("%s (%ld kids)\n", 1156 LABELP(i), subWindows[child]); 1157 } 1158 break; 1159 case COMP: 1160 /* Run it through all specified pops */ 1161 for (pop = 0; pop < numPops; pop++) { 1162 if (pops[pop] == PictOpOver) { 1163 printf ("%s\n", LABELP(i)); 1164 } else { 1165 printf ("(%s) %s\n", 1166 popNames[pops[pop]].name, 1167 LABELP(i)); 1168 } 1169 } /* for pop */ 1170 break; 1171 } /* switch */ 1172 } 1173 } 1174 exit(0); 1175 } 1176 1177 if (!foundOne) 1178 usage (); 1179 xparms.d = Open_Display (displayName); 1180 screen = DefaultScreen(xparms.d); 1181 1182 /* get visual info of default visual */ 1183 vmask = VisualIDMask | VisualScreenMask; 1184 vinfotempl.visualid = XVisualIDFromVisual(XDefaultVisual(xparms.d, screen)); 1185 vinfotempl.screen = screen; 1186 vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n); 1187 if (!vinfolist || n != 1) { 1188 fprintf (stderr, "%s: can't get visual info of default visual\n", 1189 program_name); 1190 exit(1); 1191 } 1192 1193 if (depth == -1 && vclass == -1) { 1194 /* use the default visual and colormap */ 1195 xparms.vinfo = *vinfolist; 1196 cmap = XDefaultColormap(xparms.d, screen); 1197 } else { 1198 /* find the specified visual */ 1199 int errorDepth = vinfolist[0].depth; 1200 int errorClass = vinfolist[0].class; 1201 1202 vmask = VisualScreenMask; 1203 vinfotempl.screen = screen; 1204 if (depth >= 0) { 1205 vinfotempl.depth = depth; 1206 vmask |= VisualDepthMask; 1207 errorDepth = depth; 1208 } 1209 if (vclass >= 0) { 1210 vinfotempl.class = vclass; 1211 vmask |= VisualClassMask; 1212 errorClass = vclass; 1213 } 1214 vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n); 1215 if (!vinfolist) { 1216 fprintf (stderr, 1217 "%s: can't find a visual of depth %d and class %s\n", 1218 program_name, errorDepth, visualClassNames[errorClass]); 1219 exit(1); 1220 } 1221 xparms.vinfo = *vinfolist; /* use the first one in list */ 1222 if (xparms.vinfo.visualid == 1223 XVisualIDFromVisual(XDefaultVisual(xparms.d, screen))) { 1224 /* matched visual is same as default visual */ 1225 cmap = XDefaultColormap(xparms.d, screen); 1226 } else { 1227 cmap = XCreateColormap(xparms.d, DefaultRootWindow(xparms.d), 1228 xparms.vinfo.visual, AllocNone); 1229 /* since this is not default cmap, must force color allocation */ 1230 if (!foreground) foreground = "Black"; 1231 if (!background) background = "White"; 1232 XInstallColormap(xparms.d, cmap); 1233 } 1234 } 1235 xparms.cmap = cmap; 1236 1237 printf("x11perf - X11 performance program, version %s\n", 1238 xparms.version & VERSION1_5 ? "1.5" : 1239 xparms.version & VERSION1_4 ? "1.4" : 1240 xparms.version & VERSION1_3 ? "1.3" : 1241 "1.2" 1242 ); 1243 XmuGetHostname(hostname, 100); 1244 printf ("%s server version %d on %s\nfrom %s\n", 1245 ServerVendor (xparms.d), VendorRelease (xparms.d), 1246 DisplayString (xparms.d), hostname); 1247 PrintTime (); 1248 1249 /* Force screen out of screen-saver mode, grab current data, and set 1250 time to blank to 8 hours. We should just be able to turn the screen- 1251 saver off, but this causes problems on some servers. We also reset 1252 the screen-saver timer each test, as 8 hours is about the maximum time 1253 we can use, and that isn't long enough for some X terminals using a 1254 serial protocol to finish all the tests. As long as the tests run to 1255 completion, the old screen-saver values are restored. */ 1256 XForceScreenSaver(xparms.d, ScreenSaverReset); 1257 XGetScreenSaver(xparms.d, &ssTimeout, &ssInterval, &ssPreferBlanking, 1258 &ssAllowExposures); 1259 (void) signal(SIGINT, Cleanup); /* ^C */ 1260#ifdef SIGQUIT 1261 (void) signal(SIGQUIT, Cleanup); 1262#endif 1263 (void) signal(SIGTERM, Cleanup); 1264#ifdef SIGHUP 1265 (void) signal(SIGHUP, Cleanup); 1266#endif 1267 XSetScreenSaver(xparms.d, 8 * 3600, ssInterval, ssPreferBlanking, 1268 ssAllowExposures); 1269 1270 if (drawToFakeServer) { 1271 tileToQuery = 1272 XCreatePixmap(xparms.d, DefaultRootWindow (xparms.d), 32, 32, 1); 1273 } 1274 1275 1276 xparms.foreground = 1277 AllocateColor(xparms.d, foreground, BlackPixel(xparms.d, screen)); 1278 xparms.background = 1279 AllocateColor(xparms.d, background, WhitePixel(xparms.d, screen)); 1280 xparms.ddbackground = 1281 AllocateColor(xparms.d, ddbackground, WhitePixel(xparms.d, screen)); 1282 window_x = 2; 1283 if (DisplayWidth(xparms.d, screen) < WIDTH + window_x + 1) 1284 window_x = -1; 1285 window_y = 2; 1286 if (DisplayHeight(xparms.d, screen) < HEIGHT + window_y + 1) 1287 window_y = -1; 1288 xparms.w = CreatePerfWindow(&xparms, window_x, window_y, WIDTH, HEIGHT); 1289 HSx = WIDTH-1; 1290 if (window_x + 1 + WIDTH > DisplayWidth(xparms.d, screen)) 1291 HSx = DisplayWidth(xparms.d, screen) - (1 + window_x + 1); 1292 HSy = HEIGHT-1; 1293 if (window_y + 1 + HEIGHT > DisplayHeight(xparms.d, screen)) 1294 HSy = DisplayHeight(xparms.d, screen) - (1 + window_y + 1); 1295 status = CreatePerfWindow(&xparms, window_x, HEIGHT+5, WIDTH, 20); 1296 tgcv.foreground = 1297 AllocateColor(xparms.d, "black", BlackPixel(xparms.d, screen)); 1298 tgcv.background = 1299 AllocateColor(xparms.d, "white", WhitePixel(xparms.d, screen)); 1300 tgc = XCreateGC(xparms.d, status, GCForeground | GCBackground, &tgcv); 1301 1302 xparms.p = (Pixmap)0; 1303 1304 if (synchronous) 1305 XSynchronize (xparms.d, True); 1306 1307 /* Get mouse pointer out of the way of the performance window. On 1308 software cursor machines it will slow graphics performance. On 1309 all current MIT-derived servers it will slow window 1310 creation/configuration performance. */ 1311 XWarpPointer(xparms.d, None, status, 0, 0, 0, 0, WIDTH+32, 20+32); 1312 1313 /* Figure out how long to call HardwareSync, so we can adjust for that 1314 in our total elapsed time */ 1315 (void) CalibrateTest(&xparms, &syncTest, 1, &syncTime); 1316 printf("Sync time adjustment is %6.4f msecs.\n\n", syncTime/1000); 1317 1318 ForEachTest (i) { 1319 char label[200]; 1320 1321 if (doit[i] && (test[i].versions & xparms.version)) { 1322 switch (test[i].testType) { 1323 case NONROP: 1324 /* Simplest...just run it once */ 1325 strcpy (label, LABELP(i)); 1326 ProcessTest(&xparms, &test[i], GXcopy, ~0L, label); 1327 break; 1328 1329 case ROP: 1330 /* Run it through all specified rops and planemasks */ 1331 for (rop = 0; rop < numRops; rop++) { 1332 for (pm = 0; pm < numPlanemasks; pm++) { 1333 if (planemasks[pm] == ~0) { 1334 if (rops[rop] == GXcopy) { 1335 sprintf (label, "%s", LABELP(i)); 1336 } else { 1337 sprintf (label, "(%s) %s", 1338 ropNames[rops[rop]].name, 1339 LABELP(i)); 1340 } 1341 } else { 1342 sprintf (label, "(%s 0x%lx) %s", 1343 ropNames[rops[rop]].name, 1344 planemasks[pm], 1345 LABELP(i)); 1346 } 1347 ProcessTest(&xparms, &test[i], rops[rop], 1348 planemasks[pm], label); 1349 } /* for pm */ 1350 } /* for rop */ 1351 break; 1352 1353 case PLANEMASK: 1354 /* Run it through all specified planemasks */ 1355 for (pm = 0; pm < numPlanemasks; pm++) { 1356 if (planemasks[pm] == ~0) { 1357 sprintf (label, "%s", LABELP(i)); 1358 } else { 1359 sprintf (label, "(0x%lx) %s", 1360 planemasks[pm], 1361 LABELP(i)); 1362 } 1363 ProcessTest(&xparms, &test[i], GXcopy, 1364 planemasks[pm], label); 1365 } /* for pm */ 1366 break; 1367 1368 case WINDOW: 1369 /* Loop through number of children array */ 1370 for (int child = 0; child != numSubWindows; child++) { 1371 test[i].parms.objects = subWindows[child]; 1372 sprintf(label, "%s (%d kids)", 1373 LABELP(i), test[i].parms.objects); 1374 ProcessTest(&xparms, &test[i], GXcopy, ~0L, label); 1375 } 1376 break; 1377 case COMP: 1378 /* Loop through the composite operands */ 1379 for (pop = 0; pop < numPops; pop++) { 1380 for (format = 0; format < numFormats; format++) { 1381 if (formats[format] == PictStandardNative) { 1382 if (pops[pop] == PictOpOver) { 1383 sprintf (label, "%s", LABELP(i)); 1384 } else { 1385 sprintf (label, "(%s) %s", 1386 popNames[pops[pop]].name, 1387 LABELP(i)); 1388 } 1389 } else { 1390 const char *name = NameFromFormat (formats[format]); 1391 sprintf (label, "(%s %s) %s", 1392 popNames[pops[pop]].name, 1393 name, 1394 LABELP(i)); 1395 } 1396 ProcessTest (&xparms, &test[i], pops[pop], formats[format], label); 1397 } 1398 } 1399 break; 1400 } /* switch */ 1401 } /* if doit */ 1402 } /* ForEachTest */ 1403 1404 XFreeGC(xparms.d, tgc); 1405 XDestroyWindow(xparms.d, xparms.w); 1406 XFree(vinfolist); 1407 if (drawToFakeServer) 1408 XFreePixmap(xparms.d, tileToQuery); 1409 /* Restore ScreenSaver to original state. */ 1410 XSetScreenSaver(xparms.d, ssTimeout, ssInterval, ssPreferBlanking, 1411 ssAllowExposures); 1412 XCloseDisplay(xparms.d); 1413 free(saveargv); 1414 free(doit); 1415 exit(0); 1416} 1417 1418static int 1419GetWords (int argi, int argc, char **argv, char **wordsp, int *nump) 1420{ 1421 int count; 1422 1423 if (argc <= argi) 1424 usage(); 1425 count = 0; 1426 while (argv[argi] && *(argv[argi]) != '-') { 1427 *wordsp++ = argv[argi]; 1428 ++argi; 1429 count++; 1430 } 1431 *nump = count; 1432 return count; 1433} 1434 1435static long 1436atox (char *s) 1437{ 1438 long v, c = 0; 1439 1440 v = 0; 1441 while (*s) { 1442 if ('0' <= *s && *s <= '9') 1443 c = *s - '0'; 1444 else if ('a' <= *s && *s <= 'f') 1445 c = *s - 'a' + 10; 1446 else if ('A' <= *s && *s <= 'F') 1447 c = *s - 'A' + 10; 1448 v = v * 16 + c; 1449 s++; 1450 } 1451 return v; 1452} 1453 1454static int 1455GetNumbers (int argi, int argc, char **argv, unsigned long *intsp, int *nump) 1456{ 1457 char *words[256]; 1458 int count; 1459 1460 count = GetWords (argi, argc, argv, words, nump); 1461 for (int i = 0; i < count; i++) { 1462 int flip = 0; 1463 if (!strncmp (words[i], "~", 1)) { 1464 words[i]++; 1465 flip = ~0; 1466 } 1467 if (!strncmp (words[i], "0x", 2)) 1468 intsp[i] = atox(words[i] + 2) ^ flip; 1469 else 1470 intsp[i] = atoi (words[i]) ^ flip; 1471 } 1472 return count; 1473} 1474 1475static int 1476GetRops (int argi, int argc, char **argv, int *ropsp, int *nump) 1477{ 1478 char *words[256]; 1479 int count; 1480 int rop; 1481 1482 count = GetWords (argi, argc, argv, words, nump); 1483 for (int i = 0; i < count; i++) { 1484 if (!strncmp (words[i], "GX", 2)) 1485 words[i] += 2; 1486 if (!strcmp (words[i], "all")) { 1487 for (i = 0; i < NUM_ROPS; i++) 1488 ropsp[i] = ropNames[i].rop; 1489 *nump = NUM_ROPS; 1490 break; 1491 } 1492 for (rop = 0; rop < NUM_ROPS; rop++) { 1493 if (!strcmp (words[i], ropNames[rop].name)) { 1494 ropsp[i] = ropNames[rop].rop; 1495 break; 1496 } 1497 } 1498 if (rop == NUM_ROPS) { 1499 usage (); 1500 fprintf (stderr, "unknown rop name %s\n", words[i]); 1501 } 1502 } 1503 return count; 1504} 1505 1506static int 1507GetPops (int argi, int argc, char **argv, int *popsp, int *nump) 1508{ 1509 char *words[256]; 1510 int count; 1511 int i; 1512 int pop; 1513 1514 count = GetWords (argi, argc, argv, words, nump); 1515 for (i = 0; i < count; i++) { 1516 if (!strncmp (words[i], "PictOp", 6)) 1517 words[i] += 6; 1518 if (!strcmp (words[i], "all")) { 1519 for (i = 0; i < NUM_POPS; i++) 1520 popsp[i] = popNames[i].rop; 1521 *nump = NUM_POPS; 1522 break; 1523 } 1524 for (pop = 0; pop < NUM_POPS; pop++) { 1525 if (!strcmp (words[i], popNames[pop].name)) { 1526 popsp[i] = popNames[pop].rop; 1527 break; 1528 } 1529 } 1530 if (pop == NUM_POPS) { 1531 usage (); 1532 fprintf (stderr, "unknown picture op name %s\n", words[i]); 1533 } 1534 } 1535 return count; 1536} 1537 1538static int 1539FormatFromName (char *name) 1540{ 1541 int i; 1542 for (i = 0; i < NUM_FORMATS; i++) 1543 if (!strcmp (name, formatNames[i].name)) 1544 return formatNames[i].rop; 1545 return -1; 1546} 1547 1548static const char * 1549NameFromFormat (int format) 1550{ 1551 for (int i = 0; i < NUM_FORMATS; i++) 1552 if (formatNames[i].rop == format) 1553 return formatNames[i].name; 1554 return NULL; 1555} 1556 1557static int 1558GetFormats (int argi, int argc, char **argv, int *formatsp, int *nump) 1559{ 1560 char *words[256]; 1561 int count; 1562 int i; 1563 1564 count = GetWords (argi, argc, argv, words, nump); 1565 for (i = 0; i < count; i++) { 1566 int format; 1567 1568 if (!strcmp (words[i], "all")) { 1569 for (i = 0; i < NUM_FORMATS; i++) 1570 formatsp[i] = formatNames[i].rop; 1571 *nump = NUM_FORMATS; 1572 break; 1573 } 1574 format = FormatFromName (words[i]); 1575 if (format < 0) { 1576 usage (); 1577 fprintf (stderr, "unknown format name %s\n", words[i]); 1578 } 1579 formatsp[i] = format; 1580 } 1581 return count; 1582} 1583