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