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(&current_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;
322typedef enum {
323    USAGE_OPTIONS,
324    USAGE_TESTS,
325    USAGE_ALL
326} usage_contents;
327_X_NORETURN _X_COLD static void usage(usage_contents, int);
328
329_X_NORETURN _X_COLD static void
330missing_arg(const char *option)
331{
332    fprintf(stderr, "Error: missing argument to %s\n", option);
333    usage(USAGE_OPTIONS, EXIT_FAILURE);
334}
335
336_X_NORETURN _X_COLD static void
337invalid_arg( const char *arg, const char *option)
338{
339    fprintf(stderr, "Error: invalid argument '%s' to %s\n", arg, option);
340    usage(USAGE_OPTIONS, EXIT_FAILURE);
341}
342
343/*
344 * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obsolete)
345 * If found, remove it from command line.  Don't go past a lone -.
346 */
347static char *
348Get_Display_Name(int *pargc, /* MODIFIED */
349		 char **argv) /* MODIFIED */
350{
351    int     argc = *pargc;
352    char    **pargv = argv+1;
353    char    *displayname = NULL;
354
355    for (int i = 1; i != argc; i++) {
356	char *arg = argv[i];
357
358	if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) {
359	    if (++i >= argc)
360		missing_arg(arg);
361
362	    displayname = argv[i];
363	    *pargc -= 2;
364	    continue;
365	}
366	if (!strcmp(arg,"-")) {
367	    while (i<argc)  *pargv++ = argv[i++];
368	    break;
369	}
370	*pargv++ = arg;
371    }
372
373    *pargv = NULL;
374    return (displayname);
375}
376
377
378/*
379 * GetVersion (argc, argv) Look for -v followed by a version number.
380 * If found remove it from command line.  Don't go past a lone -.
381 * Leave -v followed by non-numbers as it could be -vclass or -version.
382 */
383
384static Version
385GetVersion(int *pargc, /* MODIFIED */
386	   char **argv)  /* MODIFIED */
387{
388    int     argc = *pargc;
389    char    **pargv = argv+1;
390    Version version = VERSION1_7;
391    Bool    found = False;
392
393    for (int i = 1; i != argc; i++) {
394	char *arg = argv[i];
395
396	if (arg[0] == '-' && arg[1] == 'v') {
397	    if (arg[2] == '1' && arg[3] == '.' && arg[5] == '\0') {
398		switch (arg[4]) {
399		case '2':
400		    version = VERSION1_2;
401		    break;
402		case '3':
403		    version = VERSION1_3;
404		    break;
405		case '4':
406		    version = VERSION1_4;
407		    break;
408		case '5':
409		    version = VERSION1_5;
410		    break;
411		case '6':
412		    version = VERSION1_6;
413		    break;
414		case '7':
415		    version = VERSION1_7;
416		    break;
417		default:
418		    goto unknown_version;
419		}
420
421		if (found) {
422		    fprintf(stderr, "Warning: multiple version specifications\n");
423		}
424		found = True;
425
426		/* reduce arg count and skip copying this arg to pargv */
427		*pargc -= 1;
428		continue;
429	    } else if (isdigit(arg[2])) {
430	      unknown_version:
431		fprintf(stderr, "Error: unknown version specification: %s\n",
432			arg);
433		exit(1);
434	    }
435	}
436	else if (!strcmp(arg,"-")) {
437	    while (i<argc)  *pargv++ = argv[i++];
438	    break;
439	}
440	*pargv++ = arg;
441    }
442
443    *pargv = NULL;
444    return (version);
445}
446
447
448
449/*
450 * Open_Display: Routine to open a display with correct error handling.
451 */
452static Display *
453Open_Display(char *display_name)
454{
455    Display *d;
456
457    d = XOpenDisplay(display_name);
458    if (d == NULL) {
459	fprintf (stderr, "%s:  unable to open display '%s'\n",
460		 program_name, XDisplayName (display_name));
461	exit(1);
462    }
463
464    return(d);
465}
466
467static void
468Cleanup(int sig)
469{
470    abortTest = sig;
471}
472
473void
474AbortTest(void)
475{
476    fflush(stdout);
477
478    XSetScreenSaver(xparms.d, ssTimeout, ssInterval, ssPreferBlanking,
479	ssAllowExposures);
480    XFlush(xparms.d);
481    exit (abortTest);
482}
483
484/************************************************
485*		Performance stuff		*
486************************************************/
487
488
489static void
490usage(usage_contents show, int exit_status)
491{
492    int     i = 0;
493    static const char *help_message =
494"where options include:\n"
495"    -display <host:display>   the X server to contact\n"
496"    -sync                     do the tests in synchronous mode\n"
497"    -pack                     pack rectangles right next to each other\n"
498"    -repeat <n>               do tests <n> times (default = 5)\n"
499"    -time <s>                 do tests for <s> seconds each (default = 5)\n"
500"    -pause <s>                pause for <s> seconds between each run\n"
501/*
502"    -draw                     draw after each test -- pmax only\n"
503*/
504"    -all                      do all tests\n"
505"    -range <test1>[,<test2>]  like all, but do <test1> to <test2>\n"
506"    -labels                   generate test labels for use by fillblnk\n"
507"    -fg <color-or-pixel>      the foreground color to use\n"
508"    -bg <color-or-pixel>      the background color to use\n"
509"    -clips <default>          default number of clip windows per test\n"
510"    -ddbg <color-or-pixel>    the background color to use for DoubleDash\n"
511"    -rop <rop0 rop1 ...>      use the given rops to draw (default = GXcopy)\n"
512"    -pm <pm0 pm1 ...>         use the given planemasks to draw (default = ~0)\n"
513"    -depth <depth>            use a visual with <depth> planes per pixel\n"
514"    -vclass <class>           the visual class to use (default = root)\n"
515"    -reps <n>                 fix the rep count (default = auto scale)\n"
516"    -subs <s0 s1 ...>         a list of the number of sub-windows to use\n"
517"    -v1.2                     perform only v1.2 tests using old semantics\n"
518"    -v1.3                     perform only v1.3 tests using old semantics\n"
519"    -v1.4                     perform only v1.4 tests using old semantics\n"
520"    -v1.5                     perform only v1.5 tests using old semantics\n"
521"    -v1.6                     perform only v1.6 tests using old semantics\n"
522"    -v1.7                     perform only v1.7 tests using old semantics\n"
523"    -version                  print version and exit\n"
524"    -su                       request save unders on windows\n"
525"    -bs <backing_store_hint>  WhenMapped or Always (default = NotUseful)\n"
526"    -help [options|tests|all] list general options, test options, or both\n"
527;
528
529    fflush(stdout);
530    if (show == USAGE_OPTIONS || show == USAGE_ALL) {
531        fprintf(stderr, "usage: %s [-options ...]\n%s",
532                program_name, help_message);
533    }
534    if (show == USAGE_TESTS || show == USAGE_ALL) {
535        while (test[i].option != NULL) {
536            if (test[i].versions & xparms.version ) {
537                fprintf(stderr, "    %-24s   %s\n",
538                        test[i].option,
539                        test[i].label14 ? test[i].label14 : test[i].label);
540            }
541            i++;
542        }
543    }
544    fprintf(stderr, "\n");
545
546    exit (exit_status);
547}
548
549void
550NullProc(XParms xp, Parms p)
551{
552}
553
554int
555NullInitProc(XParms xp, Parms p, int64_t reps)
556{
557    return reps;
558}
559
560static void
561HardwareSync(XParms xp)
562{
563    /*
564     * Some graphics hardware allows the server to claim it is done,
565     * while in reality the hardware is busily working away.  So fetch
566     * a pixel from the drawable that was drawn to, which should be
567     * enough to make the server wait for the graphics hardware.
568     */
569    XImage *image;
570
571    image = XGetImage(xp->d, xp->p ? xp->p : xp->w, HSx, HSy,
572		      1, 1, ~0, ZPixmap);
573    if (image) XDestroyImage(image);
574}
575
576static void
577DoHardwareSync(XParms xp, Parms p, int64_t reps)
578{
579    for (int i = 0; i != reps; i++) {
580	HardwareSync(xp);
581	CheckAbort ();
582    }
583}
584
585static Test syncTest = {
586    "syncTime", "Internal test for finding how long HardwareSync takes", NULL,
587    NullInitProc, DoHardwareSync, NullProc, NullProc,
588    V1_2FEATURE, NONROP, 0,
589    {1}
590};
591
592
593static Window
594CreatePerfWindow(XParms xp, int x, int y, int width, int height)
595{
596    XSetWindowAttributes xswa;
597    Window w;
598/*
599    Screen *s;
600    int su;
601
602    s = DefaultScreenOfDisplay(xp->d);
603    su = XDoesBackingStore(s);
604    printf("Backing store of screen returns %d\n", su);
605    su = XDoesSaveUnders(s);
606    printf("Save unders of screen returns %d\n", su);
607    su = XPlanesOfScreen(s);
608    printf("Planes of screen returns %d\n", su);
609*/
610    xswa.background_pixel = xp->background;
611    xswa.border_pixel = xp->foreground;
612    xswa.colormap = cmap;
613    xswa.override_redirect = True;
614    xswa.backing_store = xp->backing_store;
615    xswa.save_under = xp->save_under;
616    w = XCreateWindow(xp->d, DefaultRootWindow(xp->d), x, y, width, height, 1,
617        xp->vinfo.depth, CopyFromParent, xp->vinfo.visual,
618	CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect
619	| CWBackingStore | CWSaveUnder, &xswa);
620    XMapWindow (xp->d, w);
621    return w;
622}
623
624
625static void
626CreateClipWindows(XParms xp, int clips)
627{
628    XWindowAttributes    xwa;
629
630    (void) XGetWindowAttributes(xp->d, xp->w, &xwa);
631    if (clips > MAXCLIP) clips = MAXCLIP;
632    for (int j = 0; j != clips; j++) {
633	clipWindows[j] = CreatePerfWindow(xp,
634	    xwa.x + ws[j].x, xwa.y + ws[j].y, ws[j].width, ws[j].height);
635    }
636} /* CreateClipWindows */
637
638
639static void
640DestroyClipWindows(XParms xp, int clips)
641{
642    if (clips > MAXCLIP) clips = MAXCLIP;
643    for (int j = 0; j != clips; j++) {
644	XDestroyWindow(xp->d, clipWindows[j]);
645    }
646} /* DestroyClipWindows */
647
648
649static double
650DoTest(XParms xp, Test *test, int64_t reps)
651{
652    double  time;
653    unsigned int ret_width, ret_height;
654
655    /* Tell screen-saver to restart counting again.  See comments below for the
656       XSetScreenSaver call. */
657    XForceScreenSaver(xp->d, ScreenSaverReset);
658    HardwareSync (xp);
659    InitTimes ();
660    (*test->proc) (xp, &test->parms, reps);
661    HardwareSync(xp);
662
663    time = ElapsedTime(syncTime);
664    if (time < 0.0) time = 0.0;
665    CheckAbort ();
666    if (drawToFakeServer)
667        XQueryBestSize(xp->d, TileShape, tileToQuery,
668		       32, 32, &ret_width, &ret_height);
669    (*test->passCleanup) (xp, &test->parms);
670    return time;
671}
672
673
674static int64_t
675CalibrateTest(XParms xp, Test *test, int seconds, double *usecperobj)
676{
677#define goal    2500000.0   /* Try to get up to 2.5 seconds		    */
678#define enough  2000000.0   /* But settle for 2.0 seconds		    */
679#define tick      10000.0   /* Assume clock not faster than .01 seconds     */
680
681    double  usecs;
682    int64_t reps, didreps;  /* Reps desired, reps performed		    */
683    int     exponent;
684
685    /* Attempt to get an idea how long each rep lasts by getting enough
686       reps to last more tan enough.  Then scale that up to the number of
687       seconds desired.
688
689       If init call to test ever fails, return False and test will be skipped.
690    */
691
692    if (fixedReps != 0) {
693	return fixedReps;
694    }
695    reps = 1;
696    for (;;) {
697	XDestroySubwindows(xp->d, xp->w);
698	XClearWindow(xp->d, xp->w);
699	didreps = (*test->init) (xp, &test->parms, reps);
700	CheckAbort ();
701	if (didreps == 0) {
702	    return 0;
703	}
704	if ( test->clips < clips )
705	  test->clips = clips ;
706	/* Create clip windows if requested */
707	CreateClipWindows(xp, test->clips);
708	HardwareSync(xp);
709	InitTimes();
710	(*test->proc) (xp, &test->parms, reps);
711	HardwareSync(xp);
712	usecs = ElapsedTime(syncTime);
713	(*test->passCleanup) (xp, &test->parms);
714	(*test->cleanup) (xp, &test->parms);
715	DestroyClipWindows(xp, test->clips);
716	CheckAbort ();
717
718	if (didreps != reps) {
719	    /* The test can't do the number of reps as we asked for.
720	       Give up */
721	    *usecperobj =
722		usecs / (double)(didreps * test->parms.objects);
723	    return didreps;
724	}
725	/* Did we go long enough? */
726	if (usecs >= enough) break;
727
728	/* Don't let too short a clock make new reps wildly high */
729	if (usecs <= tick)reps = reps*10;
730	else{
731	    /* Try to get up to goal seconds. */
732	    reps = (int) (goal * (double)reps / usecs) + 1;
733	}
734    }
735
736    *usecperobj = usecs / (double) (reps * test->parms.objects);
737    reps = (int) ((double)seconds * 1000000.0 * (double)reps / usecs) + 1;
738
739    /* Now round reps up to 1 digit accuracy, so we don't get stupid-looking
740       numbers of repetitions. */
741    reps--;
742    exponent = 1;
743    while (reps > 9) {
744	reps /= 10;
745	exponent *= 10;
746    }
747    reps = (reps + 1) * exponent;
748    return reps;
749} /* CalibrateTest */
750
751static void
752CreatePerfGCs(XParms xp, int func, unsigned long pm)
753{
754    XGCValues gcvfg, gcvbg, gcvddbg,gcvddfg;
755    unsigned long	fg, bg, ddbg;
756
757    fg = xp->foreground;
758    bg = xp->background;
759    ddbg = xp->ddbackground;
760    gcvfg.graphics_exposures = False;
761    gcvbg.graphics_exposures = False;
762    gcvddfg.graphics_exposures = False;
763    gcvddbg.graphics_exposures = False;
764    gcvfg.plane_mask = pm;
765    gcvbg.plane_mask = pm;
766    gcvddfg.plane_mask = pm;
767    gcvddbg.plane_mask = pm;
768    gcvfg.function = func;
769    gcvbg.function = func;
770    gcvddfg.function = func;
771    gcvddbg.function = func;
772
773    gcvfg.foreground = fg;
774    gcvfg.background = bg;
775    gcvbg.foreground = bg;
776    gcvbg.background = fg;
777    gcvddfg.foreground = fg;
778    gcvddfg.background = ddbg;
779    gcvddbg.foreground = ddbg;
780    gcvddbg.background = fg;
781    xp->fggc = XCreateGC(xp->d, xp->w,
782	GCForeground | GCBackground | GCGraphicsExposures
783      | GCFunction | GCPlaneMask, &gcvfg);
784    xp->bggc = XCreateGC(xp->d, xp->w,
785	GCForeground | GCBackground | GCGraphicsExposures
786      | GCFunction | GCPlaneMask, &gcvbg);
787    xp->ddfggc = XCreateGC(xp->d, xp->w,
788	GCForeground | GCBackground | GCGraphicsExposures
789      | GCFunction | GCPlaneMask, &gcvddfg);
790    xp->ddbggc = XCreateGC(xp->d, xp->w,
791	GCForeground | GCBackground | GCGraphicsExposures
792      | GCFunction | GCPlaneMask, &gcvddbg);
793}
794
795
796static void
797DestroyPerfGCs(XParms xp)
798{
799    XFreeGC(xp->d, xp->fggc);
800    XFreeGC(xp->d, xp->bggc);
801    XFreeGC(xp->d, xp->ddfggc);
802    XFreeGC(xp->d, xp->ddbggc);
803}
804
805static unsigned long
806AllocateColor(Display *display, const char *name, unsigned long pixel)
807{
808    XColor      color;
809
810    if (name != NULL) {
811	/* Try to parse color name */
812	if (XParseColor(display, cmap, name, &color)) {
813	    if (XAllocColor(display, cmap, &color)) {
814		pixel = color.pixel;
815	    } else {
816		(void) fprintf(stderr,
817		    "Can't allocate colormap entry for color %s\n", name);
818	    }
819	} else {
820	    if(*name >= '0' && *name <= '9')
821		pixel = atoi(name);
822	    else
823		(void) fprintf(stderr, "Can't parse color name %s\n", name);
824	}
825    }
826    return pixel;
827} /* AllocateColor */
828
829
830static void
831DisplayStatus(Display *d, const char *message, const char *test, int try)
832{
833    char    s[500];
834
835    XClearWindow(d, status);
836    sprintf(s, "%d %s %s", try, message, test);
837    /* We should really look at the height, descent of the font, etc. but
838       who cares.  This works. */
839    XDrawString(d, status, tgc, 10, 13, s, strlen(s));
840}
841
842
843static void
844ProcessTest(XParms xp, Test *test, int func, unsigned long pm, char *label)
845{
846    double  time, totalTime;
847    long long reps;
848
849    xp->planemask = pm;
850    xp->func = func;
851    if (test->testType == COMP)
852    {
853	func = GXcopy;
854	pm = ~0L;
855    }
856    CreatePerfGCs(xp, func, pm);
857    DisplayStatus(xp->d, "Calibrating", label, 0);
858    reps = CalibrateTest(xp, test, seconds, &time);
859    if (reps != 0) {
860	XDestroySubwindows(xp->d, xp->w);
861	XClearWindow(xp->d, xp->w);
862	reps = (*test->init) (xp, &test->parms, reps);
863	if (abortTest)
864	    AbortTest ();
865	/*
866	 * if using fixedReps then will not have done CalibrateTest so must
867	 * check result of init for 0 here
868	 */
869	if(reps == 0){
870	    DestroyPerfGCs(xp);
871	    return;
872	}
873	/* Create clip windows if requested */
874	CreateClipWindows(xp, test->clips);
875
876	totalTime = 0.0;
877	for (int j = 0; j != repeat; j++) {
878	    DisplayStatus(xp->d, "Testing", label, j+1);
879	    time = DoTest(xp, test, reps);
880	    if (abortTest)
881		AbortTest ();
882	    totalTime += time;
883	    ReportTimes (time, reps * test->parms.objects,
884		    label, False);
885            if (delay)
886                sleep(delay);
887	}
888	if (repeat > 1) {
889	    ReportTimes(totalTime,
890                        repeat * reps * test->parms.objects,
891                        label, True);
892	}
893	(*test->cleanup) (xp, &test->parms);
894	DestroyClipWindows(xp, test->clips);
895    } else {
896	/* Test failed to initialize properly */
897    }
898    printf ("\n");
899    fflush(stdout);
900    DestroyPerfGCs(xp);
901} /* ProcessTest */
902
903#define Strstr strstr
904
905#define LABELP(i) (test[i].label14 && (xparms.version >= VERSION1_4) \
906		        ? test[i].label14 : test[i].label)
907
908int
909main(int argc, char *argv[])
910{
911    int		i, j, n, skip;
912    int		numTests;       /* Even though the linker knows, we don't. */
913    char	hostname[100];
914    Bool	foundOne = False;
915    Bool	synchronous = False;
916    XGCValues	tgcv;
917    int		screen;
918    int		rop, pm;
919    int		pop, format;
920    int		window_y, window_x;
921    XVisualInfo *vinfolist, vinfotempl;
922    unsigned long vmask;
923
924    /* Save away argv, argc, for usage to print out */
925    saveargc = argc;
926    saveargv = malloc(argc * sizeof(char *));
927    for (i = 0; i != argc; i++) {
928	saveargv[i] = argv[i];
929    }
930
931    xparms.pack = False;
932    xparms.save_under = False;
933    xparms.backing_store = NotUseful;
934
935    /* Count number of tests */
936    ForEachTest(numTests);
937    doit = calloc(numTests, sizeof(Bool));
938
939    /* Parse arguments */
940    program_name = argv[0];
941    displayName = Get_Display_Name (&argc, argv);
942    xparms.version = GetVersion(&argc, argv);
943    for (i = 1; i != argc; i++) {
944	if (strcmp (argv[i], "-all") == 0) {
945	    ForEachTest (j)
946		doit[j] = test[j].versions & xparms.version;
947	    foundOne = True;
948	} else if (strcmp (argv[i], "-labels") == 0) {
949	    labels = True;
950	} else if (strcmp(argv[i], "-range") == 0) {
951	    char *cp1;
952	    char *cp2;
953
954	    if (argc <= ++i)
955		missing_arg(argv[i-1]);
956	    cp1 = argv[i];
957	    if (*cp1 == '-')
958		cp1++;
959	    for (cp2 = cp1; *cp2 != '\0' && *cp2 != ','; cp2++) {};
960	    if (*cp2 == ',') {
961		*cp2++ = '\0';
962		if (*cp2 == '-')
963		    cp2++;
964	    } else {
965		cp2 = "-";
966	    }
967	    ForEachTest (j) {
968		if (strcmp (cp1, (test[j].option) + 1) == 0 &&
969		    (test[j].versions & xparms.version)) {
970		    int k = j;
971		    do {
972			doit[k] = test[j].versions & xparms.version;
973		    } while (!(strcmp(cp2, (test[k].option + 1)) == 0 &&
974			       (test[k].versions & xparms.version)) &&
975			     test[++k].option != NULL);
976		    if (*cp2 != '-' && test[k].option == NULL) {
977			fprintf(stderr, "Error: unknown test %s listed for %s\n",
978				cp2, argv[i-1]);
979			usage(USAGE_OPTIONS, EXIT_FAILURE);
980		    }
981		    break;
982		}
983	    }
984	    if (test[j].option == NULL) {
985		fprintf(stderr, "Error: unknown test %s listed for %s\n",
986			argv[i], argv[i-1]);
987		usage(USAGE_OPTIONS, EXIT_FAILURE);
988	    }
989	    foundOne = True;
990	} else if (strcmp (argv[i], "-sync") == 0) {
991	    synchronous = True;
992	} else if (strcmp (argv[i], "-pack") == 0) {
993	    xparms.pack = True;
994	} else if (strcmp (argv[i], "-draw") == 0) {
995	    drawToFakeServer = True;
996        } else if (strcmp (argv[i], "-falseprecision") == 0) {
997            falsePrecision = True;
998	} else if (strcmp (argv[i], "-repeat") == 0) {
999	    i++;
1000	    if (argc <= i)
1001		missing_arg(argv[i-1]);
1002	    repeat = atoi (argv[i]);
1003	    if (repeat <= 0)
1004		invalid_arg(argv[i], argv[i-1]);
1005	} else if (strcmp (argv[i], "-time") == 0) {
1006	    i++;
1007	    if (argc <= i)
1008		missing_arg(argv[i-1]);
1009	    seconds = atoi (argv[i]);
1010	    if (seconds <= 0)
1011		invalid_arg(argv[i], argv[i-1]);
1012        } else if (strcmp (argv[i], "-pause") == 0) {
1013            ++i;
1014	    if (argc <= i)
1015		missing_arg(argv[i-1]);
1016	    delay = atoi (argv[i]);
1017	    if (delay < 0)
1018                invalid_arg(argv[i], argv[i-1]);
1019	} else if (strcmp(argv[i], "-fg") == 0) {
1020	    i++;
1021	    if (argc <= i)
1022		missing_arg(argv[i-1]);
1023	    foreground = argv[i];
1024        } else if (strcmp(argv[i], "-bg") == 0) {
1025	    i++;
1026	    if (argc <= i)
1027		missing_arg(argv[i-1]);
1028	    background = argv[i];
1029	    if(ddbackground == NULL)
1030		ddbackground = argv[i];
1031	} else if (strcmp(argv[i], "-clips") == 0 ) {
1032	    i++;
1033	    if (argc <= i)
1034		missing_arg(argv[i-1]);
1035	    clips = atoi( argv[i] );
1036	} else if (strcmp(argv[i], "-ddbg") == 0) {
1037	    if (argc <= i)
1038		missing_arg(argv[i-1]);
1039	    i++;
1040	    ddbackground = argv[i];
1041	} else if (strcmp(argv[i], "-rop") == 0) {
1042	    skip = GetRops (i+1, argc, argv, rops, &numRops);
1043	    i += skip;
1044	} else if (strcmp(argv[i], "-pop") == 0) {
1045	    skip = GetPops (i+1, argc, argv, pops, &numPops);
1046	    i += skip;
1047	} else if (strcmp(argv[i], "-format") == 0) {
1048	    skip = GetFormats (i+1, argc, argv, formats, &numFormats);
1049	    i += skip;
1050	} else if (strcmp(argv[i], "-pm") == 0) {
1051	    skip = GetNumbers (i+1, argc, argv, planemasks, &numPlanemasks);
1052	    i += skip;
1053	} else if (strcmp(argv[i], "-xor") == 0) {
1054	    numRops = 1;
1055	    rops[0] = GXxor;
1056	} else if (strcmp (argv[i], "-both") == 0) {
1057	    numRops = 2;
1058	    rops[0] = GXcopy;
1059	    rops[1] = GXxor;
1060	} else if (strcmp(argv[i], "-reps") == 0) {
1061	    i++;
1062	    if (argc <= i)
1063		missing_arg(argv[i-1]);
1064	    fixedReps = atoi (argv[i]);
1065	    if (fixedReps <= 0)
1066		invalid_arg(argv[i], argv[i-1]);
1067        } else if (strcmp(argv[i], "-depth") == 0) {
1068	    i++;
1069	    if (argc <= i)
1070                missing_arg(argv[i-1]);
1071            depth = atoi(argv[i]);
1072            if (depth <= 0)
1073		invalid_arg(argv[i], argv[i-1]);
1074        } else if (strcmp(argv[i], "-vclass") == 0) {
1075	    i++;
1076	    if (argc <= i)
1077                missing_arg(argv[i-1]);
1078	    for (j = StaticGray; j <= DirectColor; j++) {
1079		if (strcmp(argv[i], visualClassNames[j]) == 0) {
1080		    vclass = j;
1081		    break;
1082		}
1083	    }
1084            if (vclass < 0)
1085                invalid_arg(argv[i], argv[i-1]);
1086	} else if (strcmp(argv[i], "-subs") == 0) {
1087	    skip = GetNumbers (i+1, argc, argv, subWindows, &numSubWindows);
1088	    i += skip;
1089	} else if (strcmp(argv[i], "-su") == 0) {
1090	    xparms.save_under = True;
1091	} else if (strcmp(argv[i], "-bs") == 0) {
1092	    i++;
1093	    if (argc <= i)
1094		missing_arg(argv[i-1]);
1095	    if (strcmp(argv[i], "WhenMapped") == 0) {
1096	      xparms.backing_store = WhenMapped;
1097	    } else if (strcmp(argv[i], "Always") == 0) {
1098	      xparms.backing_store = Always;
1099	    } else
1100                invalid_arg(argv[i], argv[i-1]);
1101	} else if ((strcmp(argv[i], "-version") == 0) ||
1102		   (strcmp(argv[i], "--version") == 0)) {
1103	    puts(PACKAGE_STRING);
1104	    exit(EXIT_SUCCESS);
1105	} else if ((strcmp(argv[i], "-help") == 0) ||
1106		   (strcmp(argv[i], "--help") == 0)) {
1107	    i++;
1108	    /* default is to just show general options */
1109	    if (argc <= i || (strcmp(argv[i], "options") == 0)) {
1110		usage (USAGE_OPTIONS, EXIT_SUCCESS);
1111	    }
1112	    else if (strcmp(argv[i], "tests") == 0) {
1113		usage (USAGE_TESTS, EXIT_SUCCESS);
1114	    }
1115	    else if (strcmp(argv[i], "all") == 0) {
1116		usage (USAGE_ALL, EXIT_SUCCESS);
1117	    }
1118	    else {
1119		invalid_arg(argv[i], argv[i-1]);
1120	    }
1121	} else {
1122	    int len,found;
1123	    ForEachTest (j) {
1124		if (strcmp (argv[i], test[j].option) == 0 &&
1125		    (test[j].versions & xparms.version)) {
1126		    doit[j] = True;
1127		    goto LegalOption;
1128		}
1129	    }
1130	    found = False;
1131	    len = strlen(argv[i]);
1132	    if(len>=3)
1133	    ForEachTest (j) {
1134		if (Strstr (test[j].option, argv[i]+1) != NULL) {
1135		    fprintf(stderr,"	-> %s	%s\n", test[j].option, LABELP(j));
1136		    doit[j] = found = True;
1137		}
1138	    }
1139	    if(!found)
1140	    ForEachTest (j) {
1141		if (Strstr (LABELP(j), argv[i]+1) != NULL) {
1142		    fprintf(stderr,"	-> %s	%s\n", test[j].option, LABELP(j));
1143		    doit[j] = found = True;
1144		}
1145	    }
1146	    if (!found) {
1147		fprintf(stderr,
1148			"Error: unrecognized option %s\n", argv[i]);
1149		usage (USAGE_OPTIONS, EXIT_FAILURE);
1150	    }
1151	LegalOption:
1152		foundOne = True;
1153	}
1154    }
1155
1156    if (labels) {
1157	/* Just print out list of tests for use with .sh programs that
1158	   assemble data from different x11perf runs into a nice format */
1159	ForEachTest (i) {
1160	    if (doit[i]) {
1161		switch (test[i].testType) {
1162		    case NONROP:
1163			printf ("%s\n", LABELP(i));
1164			break;
1165
1166		    case ROP:
1167			/* Run it through all specified rops and planemasks */
1168			for (rop = 0; rop < numRops; rop++) {
1169			    for (pm = 0; pm < numPlanemasks; pm++) {
1170				if (planemasks[pm] == ~0) {
1171				    if (rops[rop] == GXcopy) {
1172					printf ("%s\n", LABELP(i));
1173				    } else {
1174					printf ("(%s) %s\n",
1175					    ropNames[rops[rop]].name,
1176					    LABELP(i));
1177				    }
1178				} else {
1179				    printf ("(%s 0x%lx) %s\n",
1180					    ropNames[rops[rop]].name,
1181					    planemasks[pm],
1182					    LABELP(i));
1183				}
1184			    } /* for pm */
1185			} /* for rop */
1186			break;
1187
1188		    case PLANEMASK:
1189			/* Run it through all specified planemasks */
1190			for (pm = 0; pm < numPlanemasks; pm++) {
1191			    if (planemasks[pm] == ~0) {
1192				printf ("%s\n", LABELP(i));
1193			    } else {
1194				printf ("(0x%lx) %s\n",
1195					planemasks[pm],
1196					LABELP(i));
1197			    }
1198			} /* for pm */
1199			break;
1200
1201		    case WINDOW:
1202			for (int child = 0; child != numSubWindows; child++) {
1203			    printf ("%s (%ld kids)\n",
1204				LABELP(i), subWindows[child]);
1205			}
1206			break;
1207		    case COMP:
1208			/* Run it through all specified pops */
1209			for (pop = 0; pop < numPops; pop++) {
1210			    if (pops[pop] == PictOpOver) {
1211				printf ("%s\n", LABELP(i));
1212			    } else {
1213				printf ("(%s) %s\n",
1214					popNames[pops[pop]].name,
1215					LABELP(i));
1216			    }
1217			} /* for pop */
1218			break;
1219		} /* switch */
1220	    }
1221	}
1222	exit(0);
1223    }
1224
1225    if (!foundOne) {
1226	fprintf(stderr, "Error: no argument found for which test(s) to run\n");
1227	usage (USAGE_OPTIONS, EXIT_FAILURE);
1228    }
1229    xparms.d = Open_Display (displayName);
1230    screen = DefaultScreen(xparms.d);
1231
1232    /* get visual info of default visual */
1233    vmask = VisualIDMask | VisualScreenMask;
1234    vinfotempl.visualid = XVisualIDFromVisual(XDefaultVisual(xparms.d, screen));
1235    vinfotempl.screen = screen;
1236    vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n);
1237    if (!vinfolist || n != 1) {
1238	fprintf (stderr, "%s: can't get visual info of default visual\n",
1239	    program_name);
1240	exit(1);
1241    }
1242
1243    if (depth == -1 && vclass == -1) {
1244	/* use the default visual and colormap */
1245	xparms.vinfo = *vinfolist;
1246	cmap = XDefaultColormap(xparms.d, screen);
1247    } else {
1248	/* find the specified visual */
1249	int errorDepth = vinfolist[0].depth;
1250	int errorClass = vinfolist[0].class;
1251
1252	vmask = VisualScreenMask;
1253	vinfotempl.screen = screen;
1254	if (depth >= 0) {
1255	    vinfotempl.depth = depth;
1256	    vmask |= VisualDepthMask;
1257	    errorDepth = depth;
1258	}
1259	if (vclass >= 0) {
1260	    vinfotempl.class = vclass;
1261	    vmask |= VisualClassMask;
1262	    errorClass = vclass;
1263	}
1264	vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n);
1265	if (!vinfolist) {
1266	    fprintf (stderr,
1267		"%s: can't find a visual of depth %d and class %s\n",
1268		program_name, errorDepth, visualClassNames[errorClass]);
1269	    exit(1);
1270	}
1271	xparms.vinfo = *vinfolist;  /* use the first one in list */
1272	if (xparms.vinfo.visualid ==
1273	    XVisualIDFromVisual(XDefaultVisual(xparms.d, screen))) {
1274	    /* matched visual is same as default visual */
1275	    cmap = XDefaultColormap(xparms.d, screen);
1276	} else {
1277	    cmap = XCreateColormap(xparms.d, DefaultRootWindow(xparms.d),
1278		xparms.vinfo.visual, AllocNone);
1279	    /* since this is not default cmap, must force color allocation */
1280	    if (!foreground) foreground = "Black";
1281	    if (!background) background = "White";
1282	    XInstallColormap(xparms.d, cmap);
1283	}
1284    }
1285    xparms.cmap = cmap;
1286
1287    printf("x11perf - X11 performance program, version %s\n",
1288	   xparms.version & VERSION1_5 ? "1.5" :
1289	   xparms.version & VERSION1_4 ? "1.4" :
1290	   xparms.version & VERSION1_3 ? "1.3" :
1291	   "1.2"
1292	   );
1293    XmuGetHostname(hostname, 100);
1294    printf ("%s server version %d on %s\nfrom %s\n",
1295	    ServerVendor (xparms.d), VendorRelease (xparms.d),
1296	    DisplayString (xparms.d), hostname);
1297    PrintTime ();
1298
1299    /* Force screen out of screen-saver mode, grab current data, and set
1300       time to blank to 8 hours.  We should just be able to turn the screen-
1301       saver off, but this causes problems on some servers.  We also reset
1302       the screen-saver timer each test, as 8 hours is about the maximum time
1303       we can use, and that isn't long enough for some X terminals using a
1304       serial protocol to finish all the tests.  As long as the tests run to
1305       completion, the old screen-saver values are restored. */
1306    XForceScreenSaver(xparms.d, ScreenSaverReset);
1307    XGetScreenSaver(xparms.d, &ssTimeout, &ssInterval, &ssPreferBlanking,
1308	&ssAllowExposures);
1309    (void) signal(SIGINT, Cleanup); /* ^C */
1310#ifdef SIGQUIT
1311    (void) signal(SIGQUIT, Cleanup);
1312#endif
1313    (void) signal(SIGTERM, Cleanup);
1314#ifdef SIGHUP
1315    (void) signal(SIGHUP, Cleanup);
1316#endif
1317    XSetScreenSaver(xparms.d, 8 * 3600, ssInterval, ssPreferBlanking,
1318	ssAllowExposures);
1319
1320    if (drawToFakeServer) {
1321        tileToQuery =
1322	    XCreatePixmap(xparms.d, DefaultRootWindow (xparms.d), 32, 32, 1);
1323    }
1324
1325
1326    xparms.foreground =
1327	AllocateColor(xparms.d, foreground, BlackPixel(xparms.d, screen));
1328    xparms.background =
1329	AllocateColor(xparms.d, background, WhitePixel(xparms.d, screen));
1330    xparms.ddbackground =
1331	AllocateColor(xparms.d, ddbackground, WhitePixel(xparms.d, screen));
1332    window_x = 2;
1333    if (DisplayWidth(xparms.d, screen) < WIDTH + window_x + 1)
1334	window_x = -1;
1335    window_y = 2;
1336    if (DisplayHeight(xparms.d, screen) < HEIGHT + window_y + 1)
1337	window_y = -1;
1338    xparms.w = CreatePerfWindow(&xparms, window_x, window_y, WIDTH, HEIGHT);
1339    HSx = WIDTH-1;
1340    if (window_x + 1 + WIDTH > DisplayWidth(xparms.d, screen))
1341	HSx = DisplayWidth(xparms.d, screen) - (1 + window_x + 1);
1342    HSy = HEIGHT-1;
1343    if (window_y + 1 + HEIGHT > DisplayHeight(xparms.d, screen))
1344	HSy = DisplayHeight(xparms.d, screen) - (1 + window_y + 1);
1345    status = CreatePerfWindow(&xparms, window_x, window_y + HEIGHT+3, WIDTH, 20);
1346    tgcv.foreground =
1347	AllocateColor(xparms.d, "black", BlackPixel(xparms.d, screen));
1348    tgcv.background =
1349	AllocateColor(xparms.d, "white", WhitePixel(xparms.d, screen));
1350    tgc = XCreateGC(xparms.d, status, GCForeground | GCBackground, &tgcv);
1351
1352    xparms.p = (Pixmap)0;
1353
1354    if (synchronous)
1355	XSynchronize (xparms.d, True);
1356
1357    /* Get mouse pointer out of the way of the performance window.  On
1358       software cursor machines it will slow graphics performance.  On
1359       all current MIT-derived servers it will slow window
1360       creation/configuration performance. */
1361    XWarpPointer(xparms.d, None, status, 0, 0, 0, 0, WIDTH+32, 20+32);
1362
1363    /* Figure out how long to call HardwareSync, so we can adjust for that
1364       in our total elapsed time */
1365    (void) CalibrateTest(&xparms, &syncTest, 1, &syncTime);
1366    printf("Sync time adjustment is %6.4f msecs.\n\n", syncTime/1000);
1367
1368    ForEachTest (i) {
1369	char label[200];
1370
1371	if (doit[i] && (test[i].versions & xparms.version)) {
1372	    switch (test[i].testType) {
1373	        case NONROP:
1374		    /* Simplest...just run it once */
1375		    strcpy (label, LABELP(i));
1376		    ProcessTest(&xparms, &test[i], GXcopy, ~0L, label);
1377		    break;
1378
1379		case ROP:
1380		    /* Run it through all specified rops and planemasks */
1381		    for (rop = 0; rop < numRops; rop++) {
1382			for (pm = 0; pm < numPlanemasks; pm++) {
1383			    if (planemasks[pm] == ~0) {
1384				if (rops[rop] == GXcopy) {
1385				    sprintf (label, "%s", LABELP(i));
1386				} else {
1387				    sprintf (label, "(%s) %s",
1388					ropNames[rops[rop]].name,
1389					LABELP(i));
1390				}
1391			    } else {
1392				sprintf (label, "(%s 0x%lx) %s",
1393					ropNames[rops[rop]].name,
1394					planemasks[pm],
1395					LABELP(i));
1396			    }
1397			    ProcessTest(&xparms, &test[i], rops[rop],
1398				        planemasks[pm], label);
1399			} /* for pm */
1400		    } /* for rop */
1401		    break;
1402
1403		case PLANEMASK:
1404		    /* Run it through all specified planemasks */
1405		    for (pm = 0; pm < numPlanemasks; pm++) {
1406			if (planemasks[pm] == ~0) {
1407			    sprintf (label, "%s", LABELP(i));
1408			} else {
1409			    sprintf (label, "(0x%lx) %s",
1410				    planemasks[pm],
1411				    LABELP(i));
1412			}
1413			ProcessTest(&xparms, &test[i], GXcopy,
1414				    planemasks[pm], label);
1415		    } /* for pm */
1416		    break;
1417
1418		case WINDOW:
1419		    /* Loop through number of children array */
1420		    for (int child = 0; child != numSubWindows; child++) {
1421			test[i].parms.objects = subWindows[child];
1422			sprintf(label, "%s (%d kids)",
1423			    LABELP(i), test[i].parms.objects);
1424			ProcessTest(&xparms, &test[i], GXcopy, ~0L, label);
1425		    }
1426		    break;
1427	        case COMP:
1428		    /* Loop through the composite operands */
1429		    for (pop = 0; pop < numPops; pop++) {
1430			for (format = 0; format < numFormats; format++) {
1431			    if (formats[format] == PictStandardNative) {
1432				if (pops[pop] == PictOpOver) {
1433				    sprintf (label, "%s", LABELP(i));
1434				} else {
1435				    sprintf (label, "(%s) %s",
1436					     popNames[pops[pop]].name,
1437					     LABELP(i));
1438				}
1439			    } else {
1440				const char *name = NameFromFormat (formats[format]);
1441				sprintf (label, "(%s %s) %s",
1442					 popNames[pops[pop]].name,
1443					 name,
1444					 LABELP(i));
1445			    }
1446			    ProcessTest (&xparms, &test[i], pops[pop], formats[format], label);
1447			}
1448		    }
1449		    break;
1450	    } /* switch */
1451	} /* if doit */
1452    } /* ForEachTest */
1453
1454    XFreeGC(xparms.d, tgc);
1455    XDestroyWindow(xparms.d, xparms.w);
1456    XFree(vinfolist);
1457    if (drawToFakeServer)
1458      XFreePixmap(xparms.d, tileToQuery);
1459    /* Restore ScreenSaver to original state. */
1460    XSetScreenSaver(xparms.d, ssTimeout, ssInterval, ssPreferBlanking,
1461	ssAllowExposures);
1462    XCloseDisplay(xparms.d);
1463    free(saveargv);
1464    free(doit);
1465    exit(0);
1466}
1467
1468static int
1469GetWords (int argi, int argc, char **argv, char **wordsp, int *nump)
1470{
1471    int	    count;
1472
1473    if (argc <= argi)
1474	missing_arg(argv[argi-1]);
1475    count = 0;
1476    while (argv[argi] && *(argv[argi]) != '-') {
1477	*wordsp++ = argv[argi];
1478	++argi;
1479	count++;
1480    }
1481    *nump = count;
1482    return count;
1483}
1484
1485static long
1486atox (char *s)
1487{
1488    long   v, c = 0;
1489
1490    v = 0;
1491    while (*s) {
1492	if ('0' <= *s && *s <= '9')
1493	    c = *s - '0';
1494	else if ('a' <= *s && *s <= 'f')
1495	    c = *s - 'a' + 10;
1496	else if ('A' <= *s && *s <= 'F')
1497	    c = *s - 'A' + 10;
1498	v = v * 16 + c;
1499	s++;
1500    }
1501    return v;
1502}
1503
1504static int
1505GetNumbers (int argi, int argc, char **argv, unsigned long *intsp, int *nump)
1506{
1507    char    *words[256];
1508    int	    count;
1509
1510    count = GetWords (argi, argc, argv, words, nump);
1511    for (int i = 0; i < count; i++) {
1512	int flip = 0;
1513	if (!strncmp (words[i], "~", 1)) {
1514	    words[i]++;
1515	    flip = ~0;
1516	}
1517	if (!strncmp (words[i], "0x", 2))
1518	    intsp[i] = atox(words[i] + 2) ^ flip;
1519	else
1520	    intsp[i] = atoi (words[i]) ^ flip;
1521    }
1522    return count;
1523}
1524
1525static int
1526GetRops (int argi, int argc, char **argv, int *ropsp, int *nump)
1527{
1528    char    *words[256];
1529    int	    count;
1530    int	    rop;
1531
1532    count = GetWords (argi, argc, argv, words, nump);
1533    for (int i = 0; i < count; i++) {
1534	if (!strncmp (words[i], "GX", 2))
1535	    words[i] += 2;
1536	if (!strcmp (words[i], "all")) {
1537	    for (i = 0; i < NUM_ROPS; i++)
1538		ropsp[i] = ropNames[i].rop;
1539	    *nump = NUM_ROPS;
1540	    break;
1541	}
1542	for (rop = 0; rop < NUM_ROPS; rop++) {
1543	    if (!strcmp (words[i], ropNames[rop].name)) {
1544		ropsp[i] = ropNames[rop].rop;
1545		break;
1546	    }
1547	}
1548	if (rop == NUM_ROPS) {
1549	    usage (USAGE_OPTIONS, EXIT_FAILURE);
1550	    fprintf (stderr, "unknown rop name %s\n", words[i]);
1551	}
1552    }
1553    return count;
1554}
1555
1556static int
1557GetPops (int argi, int argc, char **argv, int *popsp, int *nump)
1558{
1559    char    *words[256];
1560    int	    count;
1561    int	    i;
1562    int	    pop;
1563
1564    count = GetWords (argi, argc, argv, words, nump);
1565    for (i = 0; i < count; i++) {
1566	if (!strncmp (words[i], "PictOp", 6))
1567	    words[i] += 6;
1568	if (!strcmp (words[i], "all")) {
1569	    for (i = 0; i < NUM_POPS; i++)
1570		popsp[i] = popNames[i].rop;
1571	    *nump = NUM_POPS;
1572	    break;
1573	}
1574	for (pop = 0; pop < NUM_POPS; pop++) {
1575	    if (!strcmp (words[i], popNames[pop].name)) {
1576		popsp[i] = popNames[pop].rop;
1577		break;
1578	    }
1579	}
1580	if (pop == NUM_POPS) {
1581	    usage (USAGE_OPTIONS, EXIT_FAILURE);
1582	    fprintf (stderr, "unknown picture op name %s\n", words[i]);
1583	}
1584    }
1585    return count;
1586}
1587
1588static int
1589FormatFromName (char *name)
1590{
1591    int i;
1592    for (i = 0; i < NUM_FORMATS; i++)
1593	if (!strcmp (name, formatNames[i].name))
1594	    return formatNames[i].rop;
1595    return -1;
1596}
1597
1598static const char *
1599NameFromFormat (int format)
1600{
1601    for (int i = 0; i < NUM_FORMATS; i++)
1602	if (formatNames[i].rop == format)
1603	    return formatNames[i].name;
1604    return NULL;
1605}
1606
1607static int
1608GetFormats (int argi, int argc, char **argv, int *formatsp, int *nump)
1609{
1610    char    *words[256];
1611    int	    count;
1612    int	    i;
1613
1614    count = GetWords (argi, argc, argv, words, nump);
1615    for (i = 0; i < count; i++) {
1616        int format;
1617
1618	if (!strcmp (words[i], "all")) {
1619	    for (i = 0; i < NUM_FORMATS; i++)
1620		formatsp[i] = formatNames[i].rop;
1621	    *nump = NUM_FORMATS;
1622	    break;
1623	}
1624	format = FormatFromName (words[i]);
1625	if (format < 0) {
1626	    usage (USAGE_OPTIONS, EXIT_FAILURE);
1627	    fprintf (stderr, "unknown format name %s\n", words[i]);
1628	}
1629	formatsp[i] = format;
1630    }
1631    return count;
1632}
1633