x11perf.c revision c37a63b8
1/* $Xorg: x11perf.c,v 1.4 2000/08/17 19:54:10 cpqbld Exp $ */
2/* $XdotOrg: app/x11perf/x11perf.c,v 1.3 2005/07/26 18:55:42 alanc Exp $ */
3/****************************************************************************
4Copyright 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
5
6                        All Rights Reserved
7
8Permission to use, copy, modify, and distribute this software and its
9documentation for any purpose and without fee is hereby granted,
10provided that the above copyright notice appear in all copies and that
11both that copyright notice and this permission notice appear in
12supporting documentation, and that the name of Digital not be
13used in advertising or publicity pertaining to distribution of the
14software without specific, written prior permission.
15
16DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22SOFTWARE.
23
24****************************************************************************/
25/* $XFree86: xc/programs/x11perf/x11perf.c,v 3.6 2001/11/03 21:59:20 dawes Exp $ */
26
27#include <stdio.h>
28#include <ctype.h>
29#include <signal.h>
30
31#ifndef VMS
32#include <X11/Xatom.h>
33#include <X11/Xos.h>
34#else
35#include <decw$include/Xatom.h>
36#endif
37#include "x11perf.h"
38#include <X11/Xmu/SysUtil.h>
39
40#include <time.h>
41#define Time_t time_t
42#include <stdlib.h>
43
44/* Only for working on ``fake'' servers, for hardware that doesn't exist */
45static Bool     drawToFakeServer = False;
46static Pixmap   tileToQuery     = None;
47static char *displayName;
48int	abortTest;
49
50typedef struct _RopNames { char	*name; int  rop; } RopNameRec, *RopNamePtr;
51
52static RopNameRec ropNames[] = {
53	{ "clear",    	  GXclear },		/* 0 */
54	{ "and",	  GXand },		/* src AND dst */
55	{ "andReverse",	  GXandReverse }, 	/* src AND NOT dst */
56	{ "copy",	  GXcopy },		/* src */
57	{ "andInverted",  GXandInverted },	/* NOT src AND dst */
58	{ "noop",	  GXnoop },		/* dst */
59	{ "xor",	  GXxor },		/* src XOR dst */
60	{ "or",		  GXor },		/* src OR dst */
61	{ "nor",	  GXnor },		/* NOT src AND NOT dst */
62	{ "equiv",	  GXequiv },		/* NOT src XOR dst */
63	{ "invert",	  GXinvert },		/* NOT dst */
64	{ "orReverse",	  GXorReverse },	/* src OR NOT dst */
65	{ "copyInverted", GXcopyInverted },	/* NOT src */
66	{ "orInverted",	  GXorInverted },	/* NOT src OR dst */
67	{ "nand",	  GXnand },		/* NOT src OR NOT dst */
68	{ "set",	  GXset }		/* 1 */
69};
70
71static RopNameRec popNames[] = {
72	{ "Clear",    	  PictOpClear },
73	{ "Src",	  PictOpSrc },
74	{ "Dst",	  PictOpDst },
75	{ "Over",	  PictOpOver },
76	{ "OverReverse",  PictOpOverReverse },
77	{ "In",		  PictOpIn },
78	{ "InReverse",	  PictOpInReverse },
79	{ "Out",	  PictOpOut },
80	{ "OutReverse",	  PictOpOutReverse },
81	{ "Atop",	  PictOpAtop },
82	{ "AtopReverse",  PictOpAtopReverse },
83	{ "Xor",	  PictOpXor },
84	{ "Add",	  PictOpAdd },
85	{ "Saturate",	  PictOpSaturate },
86};
87
88static RopNameRec formatNames[] = {
89    { "RGB24",	  PictStandardRGB24 },
90    { "ARGB32",	  PictStandardARGB32 },
91    { "A8",	  PictStandardA8 },
92    { "A4",	  PictStandardA4 },
93    { "A1",	  PictStandardA1 },
94    { "NATIVE",	  PictStandardNative },
95};
96
97static char *(visualClassNames)[] = {
98    "StaticGray",
99    "GrayScale",
100    "StaticColor",
101    "PseudoColor",
102    "TrueColor",
103    "DirectColor"
104};
105
106static Bool     labels		= False;
107static int      repeat		= 5;
108static int	seconds		= 5;
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 char *foreground = NULL;
132static char *background = NULL;
133static 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);
169
170/************************************************
171*	    time related stuff			*
172************************************************/
173
174#ifdef VMS
175
176typedef struct _vms_time {
177    unsigned long low;
178    unsigned long high;
179}vms_time;
180
181struct timeval {
182    long tv_sec;        /* seconds since Jan. 1, 1970 */
183    long tv_usec;  /* and microseconds */
184};
185
186struct timezone {
187    int  tz_minuteswest;     /* of Greenwich */
188    int  tz_dsttime;    /* type of dst correction to apply */
189};
190
191
192static int firsttime = True;
193static vms_time basetime;
194
195int gettimeofday(tp)
196    struct timeval *tp;
197{
198    vms_time current_time, resultant;
199    unsigned long mumble, foo;
200    int status;
201
202    if (firsttime) {
203        sys$gettim(&basetime);
204        firsttime = False;
205    }
206    sys$gettim(&current_time);
207    resultant.high = current_time.high - basetime.high;
208    resultant.low = current_time.low - basetime.low;
209    if (current_time.low < basetime.low) {
210        resultant.high -= 1;
211    }
212    status = lib$ediv( &(10000000), &resultant, &tp->tv_sec, &tp->tv_usec);
213    tp->tv_usec /= 10;
214    return 0;
215}
216
217#endif
218
219static struct  timeval start;
220
221static void
222PrintTime(void)
223{
224    Time_t t;
225
226    t = time((Time_t *)NULL);
227    printf("%s\n", ctime(&t));
228}
229
230static void
231InitTimes(void)
232{
233    X_GETTIMEOFDAY(&start);
234}
235
236static double
237ElapsedTime(double correction)
238{
239    struct timeval stop;
240
241    X_GETTIMEOFDAY(&stop);
242    if (stop.tv_usec < start.tv_usec) {
243        stop.tv_usec += 1000000;
244	stop.tv_sec -= 1;
245    }
246    return  (double)(stop.tv_usec - start.tv_usec) +
247            (1000000.0 * (double)(stop.tv_sec - start.tv_sec)) - correction;
248}
249
250static double
251RoundTo3Digits(double d)
252{
253    /* It's kind of silly to print out things like ``193658.4/sec'' so just
254       junk all but 3 most significant digits. */
255
256    double exponent, sign;
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, int 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("%7d trep @ %8.4f msec (%8.1f/sec): %s\n",
300		    n, msecsperobj, objspersec, str);
301	} else {
302	    printf("%7d reps @ %8.4f msec (%8.1f/sec): %s\n",
303	        n, msecsperobj, objspersec, str);
304	}
305    } else {
306	printf("%6d %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    CheckAbort ();
651    if (drawToFakeServer)
652        XQueryBestSize(xp->d, TileShape, tileToQuery,
653		       32, 32, &ret_width, &ret_height);
654    (*test->passCleanup) (xp, &test->parms);
655    return time;
656}
657
658
659static int
660CalibrateTest(XParms xp, Test *test, int seconds, double *usecperobj)
661{
662#define goal    2500000.0   /* Try to get up to 2.5 seconds		    */
663#define enough  2000000.0   /* But settle for 2.0 seconds		    */
664#define tick      10000.0   /* Assume clock not faster than .01 seconds     */
665
666    double  usecs;
667    int     reps, didreps;  /* Reps desired, reps performed		    */
668    int     exponent;
669
670    /* Attempt to get an idea how long each rep lasts by getting enough
671       reps to last more tan enough.  Then scale that up to the number of
672       seconds desired.
673
674       If init call to test ever fails, return False and test will be skipped.
675    */
676
677    if (fixedReps != 0) {
678	return fixedReps;
679    }
680    reps = 1;
681    for (;;) {
682	XDestroySubwindows(xp->d, xp->w);
683	XClearWindow(xp->d, xp->w);
684	didreps = (*test->init) (xp, &test->parms, reps);
685	CheckAbort ();
686	if (didreps == 0) {
687	    return 0;
688	}
689	if ( test->clips < clips )
690	  test->clips = clips ;
691	/* Create clip windows if requested */
692	CreateClipWindows(xp, test->clips);
693	HardwareSync(xp);
694	InitTimes();
695	(*test->proc) (xp, &test->parms, reps);
696	HardwareSync(xp);
697	usecs = ElapsedTime(syncTime);
698	(*test->passCleanup) (xp, &test->parms);
699	(*test->cleanup) (xp, &test->parms);
700	DestroyClipWindows(xp, test->clips);
701	CheckAbort ();
702
703	if (didreps != reps) {
704	    /* The test can't do the number of reps as we asked for.
705	       Give up */
706	    *usecperobj =
707		usecs / (double)(didreps * test->parms.objects);
708	    return didreps;
709	}
710	/* Did we go long enough? */
711	if (usecs >= enough) break;
712
713	/* Don't let too short a clock make new reps wildly high */
714	if (usecs <= tick)reps = reps*10;
715	else{
716	    /* Try to get up to goal seconds. */
717	    reps = (int) (goal * (double)reps / usecs) + 1;
718	}
719    }
720
721    *usecperobj = usecs / (double) (reps * test->parms.objects);
722    reps = (int) ((double)seconds * 1000000.0 * (double)reps / usecs) + 1;
723
724    /* Now round reps up to 1 digit accuracy, so we don't get stupid-looking
725       numbers of repetitions. */
726    reps--;
727    exponent = 1;
728    while (reps > 9) {
729	reps /= 10;
730	exponent *= 10;
731    }
732    reps = (reps + 1) * exponent;
733    return reps;
734} /* CalibrateTest */
735
736static void
737CreatePerfGCs(XParms xp, int func, unsigned long pm)
738{
739    XGCValues gcvfg, gcvbg, gcvddbg,gcvddfg;
740    unsigned long	fg, bg, ddbg;
741
742    fg = xp->foreground;
743    bg = xp->background;
744    ddbg = xp->ddbackground;
745    gcvfg.graphics_exposures = False;
746    gcvbg.graphics_exposures = False;
747    gcvddfg.graphics_exposures = False;
748    gcvddbg.graphics_exposures = False;
749    gcvfg.plane_mask = pm;
750    gcvbg.plane_mask = pm;
751    gcvddfg.plane_mask = pm;
752    gcvddbg.plane_mask = pm;
753    gcvfg.function = func;
754    gcvbg.function = func;
755    gcvddfg.function = func;
756    gcvddbg.function = func;
757
758    if (func == GXxor) {
759	/* Make test look good visually if possible */
760	gcvbg.foreground = gcvfg.foreground = bg ^ fg;
761	gcvbg.background = gcvfg.background = bg;
762	/* Double Dash GCs (This doesn't make a huge amount of sense) */
763	gcvddbg.foreground = gcvddfg.foreground = bg ^ fg;
764	gcvddbg.background = gcvddfg.foreground = bg ^ ddbg;
765    } else {
766	gcvfg.foreground = fg;
767	gcvfg.background = bg;
768	gcvbg.foreground = bg;
769	gcvbg.background = fg;
770	gcvddfg.foreground = fg;
771	gcvddfg.background = ddbg;
772	gcvddbg.foreground = ddbg;
773	gcvddbg.background = fg;
774    }
775    xp->fggc = XCreateGC(xp->d, xp->w,
776	GCForeground | GCBackground | GCGraphicsExposures
777      | GCFunction | GCPlaneMask, &gcvfg);
778    xp->bggc = XCreateGC(xp->d, xp->w,
779	GCForeground | GCBackground | GCGraphicsExposures
780      | GCFunction | GCPlaneMask, &gcvbg);
781    xp->ddfggc = XCreateGC(xp->d, xp->w,
782	GCForeground | GCBackground | GCGraphicsExposures
783      | GCFunction | GCPlaneMask, &gcvddfg);
784    xp->ddbggc = XCreateGC(xp->d, xp->w,
785	GCForeground | GCBackground | GCGraphicsExposures
786      | GCFunction | GCPlaneMask, &gcvddbg);
787}
788
789
790static void
791DestroyPerfGCs(XParms xp)
792{
793    XFreeGC(xp->d, xp->fggc);
794    XFreeGC(xp->d, xp->bggc);
795    XFreeGC(xp->d, xp->ddfggc);
796    XFreeGC(xp->d, xp->ddbggc);
797}
798
799static unsigned long
800AllocateColor(Display *display, char *name, unsigned long pixel)
801{
802    XColor      color;
803
804    if (name != NULL) {
805	/* Try to parse color name */
806	if (XParseColor(display, cmap, name, &color)) {
807	    if (XAllocColor(display, cmap, &color)) {
808		pixel = color.pixel;
809	    } else {
810		(void) fprintf(stderr,
811		    "Can't allocate colormap entry for color %s\n", name);
812	    }
813	} else {
814	    if(*name >= '0' && *name <= '9')
815		pixel = atoi(name);
816	    else
817		(void) fprintf(stderr, "Can't parse color name %s\n", name);
818	}
819    }
820    return pixel;
821} /* AllocateColor */
822
823
824static void
825DisplayStatus(Display *d, char *message, char *test, int try)
826{
827    char    s[500];
828
829    XClearWindow(d, status);
830    sprintf(s, "%d %s %s", try, message, test);
831    /* We should really look at the height, descent of the font, etc. but
832       who cares.  This works. */
833    XDrawString(d, status, tgc, 10, 13, s, strlen(s));
834}
835
836
837static void
838ProcessTest(XParms xp, Test *test, int func, unsigned long pm, char *label)
839{
840    double  time, totalTime;
841    int     reps;
842    int     j;
843
844    xp->planemask = pm;
845    xp->func = func;
846    if (test->testType == COMP)
847    {
848	func = GXcopy;
849	pm = ~0L;
850    }
851    CreatePerfGCs(xp, func, pm);
852    DisplayStatus(xp->d, "Calibrating", label, 0);
853    reps = CalibrateTest(xp, test, seconds, &time);
854    if (reps != 0) {
855	srand(1);	/* allow reproducible results */
856	XDestroySubwindows(xp->d, xp->w);
857	XClearWindow(xp->d, xp->w);
858	reps = (*test->init) (xp, &test->parms, reps);
859	if (abortTest)
860	    AbortTest ();
861	/*
862	 * if using fixedReps then will not have done CalibrateTest so must
863	 * check result of init for 0 here
864	 */
865	if(reps == 0){
866	    DestroyPerfGCs(xp);
867	    return;
868	}
869	/* Create clip windows if requested */
870	CreateClipWindows(xp, test->clips);
871
872	totalTime = 0.0;
873	for (j = 0; j != repeat; j++) {
874	    DisplayStatus(xp->d, "Testing", label, j+1);
875	    time = DoTest(xp, test, reps);
876	    if (abortTest)
877		AbortTest ();
878	    totalTime += time;
879	    ReportTimes (time, reps * test->parms.objects,
880		    label, False);
881	}
882	if (repeat > 1) {
883	    ReportTimes(totalTime,
884		repeat * reps * test->parms.objects,
885		label, True);
886	}
887	(*test->cleanup) (xp, &test->parms);
888	DestroyClipWindows(xp, test->clips);
889    } else {
890	/* Test failed to initialize properly */
891    }
892    printf ("\n");
893    fflush(stdout);
894    DestroyPerfGCs(xp);
895} /* ProcessTest */
896
897#define Strstr strstr
898
899#define LABELP(i) (test[i].label14 && (xparms.version >= VERSION1_4) \
900		        ? test[i].label14 : test[i].label)
901
902int
903main(int argc, char *argv[])
904{
905    int		i, j, n, skip;
906    int		numTests;       /* Even though the linker knows, we don't. */
907    char	hostname[100];
908    Bool	foundOne = False;
909    Bool	synchronous = False;
910    XGCValues	tgcv;
911    int		screen;
912    int		rop, pm;
913    int		pop, format;
914    int		window_y, window_x;
915    XVisualInfo *vinfolist, vinfotempl;
916    unsigned long vmask;
917
918    /* Save away argv, argc, for usage to print out */
919    saveargc = argc;
920    saveargv = (char **) malloc(argc * sizeof(char *));
921    for (i = 0; i != argc; i++) {
922	saveargv[i] = argv[i];
923    }
924
925    xparms.pack = False;
926    xparms.save_under = False;
927    xparms.backing_store = NotUseful;
928
929    /* Count number of tests */
930    ForEachTest(numTests);
931    doit = (Bool *)calloc(numTests, sizeof(Bool));
932
933    /* Parse arguments */
934    program_name = argv[0];
935    displayName = Get_Display_Name (&argc, argv);
936    xparms.version = GetVersion(&argc, argv);
937    for (i = 1; i != argc; i++) {
938	if (strcmp (argv[i], "-all") == 0) {
939	    ForEachTest (j)
940		doit[j] = test[j].versions & xparms.version;
941	    foundOne = True;
942	} else if (strcmp (argv[i], "-labels") == 0) {
943	    labels = True;
944	} else if (strcmp(argv[i], "-range") == 0) {
945	    char *cp1;
946	    char *cp2;
947
948	    if (argc <= ++i)
949		usage();
950	    cp1 = argv[i];
951	    if (*cp1 == '-')
952		cp1++;
953	    for (cp2 = cp1; *cp2 != '\0' && *cp2 != ','; cp2++) {};
954	    if (*cp2 == ',') {
955		*cp2++ = '\0';
956		if (*cp2 == '-')
957		    cp2++;
958	    } else {
959		cp2 = "-";
960	    }
961	    ForEachTest (j) {
962		if (strcmp (cp1, (test[j].option) + 1) == 0 &&
963		    (test[j].versions & xparms.version)) {
964		    int k = j;
965		    do {
966			doit[k] = test[j].versions & xparms.version;
967		    } while (!(strcmp(cp2, (test[k].option + 1)) == 0 &&
968			       (test[k].versions & xparms.version)) &&
969			     test[++k].option != NULL);
970		    if (*cp2 != '-' && test[k].option == NULL)
971			usage();
972		    break;
973		}
974	    }
975	    if (test[j].option == NULL)
976		usage();
977	    foundOne = True;
978	} else if (strcmp (argv[i], "-sync") == 0) {
979	    synchronous = True;
980	} else if (strcmp(argv[i], "-pack") == 0) {
981	    xparms.pack = True;
982	} else if (strcmp (argv[i], "-draw") == 0) {
983	    drawToFakeServer = True;
984	} else if (strcmp (argv[i], "-repeat") == 0) {
985	    i++;
986	    if (argc <= i)
987		usage ();
988	    repeat = atoi (argv[i]);
989	    if (repeat <= 0)
990	       usage ();
991	} else if (strcmp (argv[i], "-time") == 0) {
992	    i++;
993	    if (argc <= i)
994		usage ();
995	    seconds = atoi (argv[i]);
996	    if (seconds <= 0)
997	       usage ();
998	} else if (strcmp(argv[i], "-fg") == 0) {
999	    i++;
1000	    if (argc <= i)
1001		usage ();
1002	    foreground = argv[i];
1003        } else if (strcmp(argv[i], "-bg") == 0) {
1004	    i++;
1005	    if (argc <= i)
1006		usage ();
1007	    background = argv[i];
1008	    if(ddbackground == NULL)
1009		ddbackground = argv[i];
1010	} else if (strcmp(argv[i], "-clips") == 0 ) {
1011	    i++;
1012	    if (argc <= i)
1013		usage ();
1014	    clips = atoi( argv[i] );
1015	} else if (strcmp(argv[i], "-ddbg") == 0) {
1016	    if (argc <= i)
1017		usage ();
1018	    i++;
1019	    ddbackground = argv[i];
1020	} else if (strcmp(argv[i], "-rop") == 0) {
1021	    skip = GetRops (i+1, argc, argv, rops, &numRops);
1022	    i += skip;
1023	} else if (strcmp(argv[i], "-pop") == 0) {
1024	    skip = GetPops (i+1, argc, argv, pops, &numPops);
1025	    i += skip;
1026	} else if (strcmp(argv[i], "-format") == 0) {
1027	    skip = GetFormats (i+1, argc, argv, formats, &numFormats);
1028	    i += skip;
1029	} else if (strcmp(argv[i], "-pm") == 0) {
1030	    skip = GetNumbers (i+1, argc, argv, planemasks, &numPlanemasks);
1031	    i += skip;
1032	} else if (strcmp(argv[i], "-xor") == 0) {
1033	    numRops = 1;
1034	    rops[0] = GXxor;
1035	} else if (strcmp (argv[i], "-both") == 0) {
1036	    numRops = 2;
1037	    rops[0] = GXcopy;
1038	    rops[1] = GXxor;
1039	} else if (strcmp(argv[i], "-reps") == 0) {
1040	    i++;
1041	    if (argc <= i)
1042		usage ();
1043	    fixedReps = atoi (argv[i]);
1044	    if (fixedReps <= 0)
1045		usage ();
1046        } else if (strcmp(argv[i], "-depth") == 0) {
1047	    i++;
1048	    if (argc <= i)
1049                usage ();
1050            depth = atoi(argv[i]);
1051            if (depth <= 0)
1052		usage ();
1053        } else if (strcmp(argv[i], "-vclass") == 0) {
1054	    i++;
1055	    if (argc <= i)
1056                usage ();
1057	    for (j = StaticGray; j <= DirectColor; j++) {
1058		if (strcmp(argv[i], visualClassNames[j]) == 0) {
1059		    vclass = j;
1060		    break;
1061		}
1062	    }
1063            if (vclass < 0)
1064		usage ();
1065	} else if (strcmp(argv[i], "-subs") == 0) {
1066	    skip = GetNumbers (i+1, argc, argv, subWindows, &numSubWindows);
1067	    i += skip;
1068	} else if (strcmp(argv[i], "-v1.2") == 0) {
1069	    xparms.version = VERSION1_2;
1070	} else if (strcmp(argv[i], "-v1.3") == 0) {
1071	    xparms.version = VERSION1_3;
1072	} else if (strcmp(argv[i], "-su") == 0) {
1073	    xparms.save_under = True;
1074	} else if (strcmp(argv[i], "-bs") == 0) {
1075	    i++;
1076	    if (argc <= i)
1077		usage ();
1078	    if (strcmp(argv[i], "WhenMapped") == 0) {
1079	      xparms.backing_store = WhenMapped;
1080	    } else if (strcmp(argv[i], "Always") == 0) {
1081	      xparms.backing_store = Always;
1082	    } else usage ();
1083	} else {
1084	    int len,found;
1085	    ForEachTest (j) {
1086		if (strcmp (argv[i], test[j].option) == 0 &&
1087		    (test[j].versions & xparms.version)) {
1088		    doit[j] = True;
1089		    goto LegalOption;
1090		}
1091	    }
1092	    found = False;
1093	    len = strlen(argv[i]);
1094	    if(len>=3)
1095	    ForEachTest (j) {
1096		if (Strstr (test[j].option, argv[i]+1) != NULL) {
1097		    fprintf(stderr,"	-> %s	%s\n", test[j].option, LABELP(j));
1098		    doit[j] = found = True;
1099		}
1100	    }
1101	    if(!found)
1102	    ForEachTest (j) {
1103		if (Strstr (LABELP(j), argv[i]+1) != NULL) {
1104		    fprintf(stderr,"	-> %s	%s\n", test[j].option, LABELP(j));
1105		    doit[j] = found = True;
1106		}
1107	    }
1108	    if(!found)
1109		usage ();
1110	LegalOption:
1111		foundOne = True;
1112	}
1113    }
1114
1115    if (labels) {
1116	/* Just print out list of tests for use with .sh programs that
1117	   assemble data from different x11perf runs into a nice format */
1118	ForEachTest (i) {
1119	    int child;
1120	    if (doit[i]) {
1121		switch (test[i].testType) {
1122		    case NONROP:
1123			printf ("%s\n", LABELP(i));
1124			break;
1125
1126		    case ROP:
1127			/* Run it through all specified rops and planemasks */
1128			for (rop = 0; rop < numRops; rop++) {
1129			    for (pm = 0; pm < numPlanemasks; pm++) {
1130				if (planemasks[pm] == ~0) {
1131				    if (rops[rop] == GXcopy) {
1132					printf ("%s\n", LABELP(i));
1133				    } else {
1134					printf ("(%s) %s\n",
1135					    ropNames[rops[rop]].name,
1136					    LABELP(i));
1137				    }
1138				} else {
1139				    printf ("(%s 0x%lx) %s\n",
1140					    ropNames[rops[rop]].name,
1141					    planemasks[pm],
1142					    LABELP(i));
1143				}
1144			    } /* for pm */
1145			} /* for rop */
1146			break;
1147
1148		    case PLANEMASK:
1149			/* Run it through all specified planemasks */
1150			for (pm = 0; pm < numPlanemasks; pm++) {
1151			    if (planemasks[pm] == ~0) {
1152				printf ("%s\n", LABELP(i));
1153			    } else {
1154				printf ("(0x%lx) %s\n",
1155					planemasks[pm],
1156					LABELP(i));
1157			    }
1158			} /* for pm */
1159			break;
1160
1161		    case WINDOW:
1162			for (child = 0; child != numSubWindows; child++) {
1163			    printf ("%s (%ld kids)\n",
1164				LABELP(i), subWindows[child]);
1165			}
1166			break;
1167		    case COMP:
1168			/* Run it through all specified pops */
1169			for (pop = 0; pop < numPops; pop++) {
1170			    if (pops[pop] == PictOpOver) {
1171				printf ("%s\n", LABELP(i));
1172			    } else {
1173				printf ("(%s) %s\n",
1174					popNames[pops[pop]].name,
1175					LABELP(i));
1176			    }
1177			} /* for pop */
1178			break;
1179		} /* switch */
1180	    }
1181	}
1182	exit(0);
1183    }
1184
1185    if (!foundOne)
1186	usage ();
1187    xparms.d = Open_Display (displayName);
1188    screen = DefaultScreen(xparms.d);
1189
1190    /* get visual info of default visual */
1191    vmask = VisualIDMask | VisualScreenMask;
1192    vinfotempl.visualid = XVisualIDFromVisual(XDefaultVisual(xparms.d, screen));
1193    vinfotempl.screen = screen;
1194    vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n);
1195    if (!vinfolist || n != 1) {
1196	fprintf (stderr, "%s: can't get visual info of default visual\n",
1197	    program_name);
1198	exit(1);
1199    }
1200
1201    if (depth == -1 && vclass == -1) {
1202	/* use the default visual and colormap */
1203	xparms.vinfo = *vinfolist;
1204	cmap = XDefaultColormap(xparms.d, screen);
1205    } else {
1206	/* find the specified visual */
1207	int errorDepth = vinfolist[0].depth;
1208	int errorClass = vinfolist[0].class;
1209
1210	vmask = VisualScreenMask;
1211	vinfotempl.screen = screen;
1212	if (depth >= 0) {
1213	    vinfotempl.depth = depth;
1214	    vmask |= VisualDepthMask;
1215	    errorDepth = depth;
1216	}
1217	if (vclass >= 0) {
1218	    vinfotempl.class = vclass;
1219	    vmask |= VisualClassMask;
1220	    errorClass = vclass;
1221	}
1222	vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n);
1223	if (!vinfolist) {
1224	    fprintf (stderr,
1225		"%s: can't find a visual of depth %d and class %s\n",
1226		program_name, errorDepth, visualClassNames[errorClass]);
1227	    exit(1);
1228	}
1229	xparms.vinfo = *vinfolist;  /* use the first one in list */
1230	if (xparms.vinfo.visualid ==
1231	    XVisualIDFromVisual(XDefaultVisual(xparms.d, screen))) {
1232	    /* matched visual is same as default visual */
1233	    cmap = XDefaultColormap(xparms.d, screen);
1234	} else {
1235	    cmap = XCreateColormap(xparms.d, DefaultRootWindow(xparms.d),
1236		xparms.vinfo.visual, AllocNone);
1237	    /* since this is not default cmap, must force color allocation */
1238	    if (!foreground) foreground = "Black";
1239	    if (!background) background = "White";
1240	    XInstallColormap(xparms.d, cmap);
1241	}
1242    }
1243    xparms.cmap = cmap;
1244
1245    printf("x11perf - X11 performance program, version %s\n",
1246	   xparms.version & VERSION1_5 ? "1.5" :
1247	   xparms.version & VERSION1_4 ? "1.4" :
1248	   xparms.version & VERSION1_3 ? "1.3" :
1249	   "1.2"
1250	   );
1251    XmuGetHostname(hostname, 100);
1252    printf ("%s server version %d on %s\nfrom %s\n",
1253	    ServerVendor (xparms.d), VendorRelease (xparms.d),
1254	    DisplayString (xparms.d), hostname);
1255    PrintTime ();
1256
1257    /* Force screen out of screen-saver mode, grab current data, and set
1258       time to blank to 8 hours.  We should just be able to turn the screen-
1259       saver off, but this causes problems on some servers.  We also reset
1260       the screen-saver timer each test, as 8 hours is about the maximum time
1261       we can use, and that isn't long enough for some X terminals using a
1262       serial protocol to finish all the tests.  As long as the tests run to
1263       completion, the old screen-saver values are restored. */
1264    XForceScreenSaver(xparms.d, ScreenSaverReset);
1265    XGetScreenSaver(xparms.d, &ssTimeout, &ssInterval, &ssPreferBlanking,
1266	&ssAllowExposures);
1267    (void) signal(SIGINT, Cleanup); /* ^C */
1268#ifdef SIGQUIT
1269    (void) signal(SIGQUIT, Cleanup);
1270#endif
1271    (void) signal(SIGTERM, Cleanup);
1272#ifdef SIGHUP
1273    (void) signal(SIGHUP, Cleanup);
1274#endif
1275    XSetScreenSaver(xparms.d, 8 * 3600, ssInterval, ssPreferBlanking,
1276	ssAllowExposures);
1277
1278    if (drawToFakeServer) {
1279        tileToQuery =
1280	    XCreatePixmap(xparms.d, DefaultRootWindow (xparms.d), 32, 32, 1);
1281    }
1282
1283
1284    xparms.foreground =
1285	AllocateColor(xparms.d, foreground, BlackPixel(xparms.d, screen));
1286    xparms.background =
1287	AllocateColor(xparms.d, background, WhitePixel(xparms.d, screen));
1288    xparms.ddbackground =
1289	AllocateColor(xparms.d, ddbackground, WhitePixel(xparms.d, screen));
1290    window_x = 2;
1291    if (DisplayWidth(xparms.d, screen) < WIDTH + window_x + 1)
1292	window_x = -1;
1293    window_y = 2;
1294    if (DisplayHeight(xparms.d, screen) < HEIGHT + window_y + 1)
1295	window_y = -1;
1296    xparms.w = CreatePerfWindow(&xparms, window_x, window_y, WIDTH, HEIGHT);
1297    HSx = WIDTH-1;
1298    if (window_x + 1 + WIDTH > DisplayWidth(xparms.d, screen))
1299	HSx = DisplayWidth(xparms.d, screen) - (1 + window_x + 1);
1300    HSy = HEIGHT-1;
1301    if (window_y + 1 + HEIGHT > DisplayHeight(xparms.d, screen))
1302	HSy = DisplayHeight(xparms.d, screen) - (1 + window_y + 1);
1303    status = CreatePerfWindow(&xparms, window_x, HEIGHT+5, WIDTH, 20);
1304    tgcv.foreground =
1305	AllocateColor(xparms.d, "black", BlackPixel(xparms.d, screen));
1306    tgcv.background =
1307	AllocateColor(xparms.d, "white", WhitePixel(xparms.d, screen));
1308    tgc = XCreateGC(xparms.d, status, GCForeground | GCBackground, &tgcv);
1309
1310    xparms.p = (Pixmap)0;
1311
1312    if (synchronous)
1313	XSynchronize (xparms.d, True);
1314
1315    /* Get mouse pointer out of the way of the performance window.  On
1316       software cursor machines it will slow graphics performance.  On
1317       all current MIT-derived servers it will slow window
1318       creation/configuration performance. */
1319    XWarpPointer(xparms.d, None, status, 0, 0, 0, 0, WIDTH+32, 20+32);
1320
1321    /* Figure out how long to call HardwareSync, so we can adjust for that
1322       in our total elapsed time */
1323    (void) CalibrateTest(&xparms, &syncTest, 1, &syncTime);
1324    printf("Sync time adjustment is %6.4f msecs.\n\n", syncTime/1000);
1325
1326    ForEachTest (i) {
1327	int child;
1328	char label[200];
1329
1330	if (doit[i] && (test[i].versions & xparms.version)) {
1331	    switch (test[i].testType) {
1332	        case NONROP:
1333		    /* Simplest...just run it once */
1334		    strcpy (label, LABELP(i));
1335		    ProcessTest(&xparms, &test[i], GXcopy, ~0L, label);
1336		    break;
1337
1338		case ROP:
1339		    /* Run it through all specified rops and planemasks */
1340		    for (rop = 0; rop < numRops; rop++) {
1341			for (pm = 0; pm < numPlanemasks; pm++) {
1342			    if (planemasks[pm] == ~0) {
1343				if (rops[rop] == GXcopy) {
1344				    sprintf (label, "%s", LABELP(i));
1345				} else {
1346				    sprintf (label, "(%s) %s",
1347					ropNames[rops[rop]].name,
1348					LABELP(i));
1349				}
1350			    } else {
1351				sprintf (label, "(%s 0x%lx) %s",
1352					ropNames[rops[rop]].name,
1353					planemasks[pm],
1354					LABELP(i));
1355			    }
1356			    ProcessTest(&xparms, &test[i], rops[rop],
1357				        planemasks[pm], label);
1358			} /* for pm */
1359		    } /* for rop */
1360		    break;
1361
1362		case PLANEMASK:
1363		    /* Run it through all specified planemasks */
1364		    for (pm = 0; pm < numPlanemasks; pm++) {
1365			if (planemasks[pm] == ~0) {
1366			    sprintf (label, "%s", LABELP(i));
1367			} else {
1368			    sprintf (label, "(0x%lx) %s",
1369				    planemasks[pm],
1370				    LABELP(i));
1371			}
1372			ProcessTest(&xparms, &test[i], GXcopy,
1373				    planemasks[pm], label);
1374		    } /* for pm */
1375		    break;
1376
1377		case WINDOW:
1378		    /* Loop through number of children array */
1379		    for (child = 0; child != numSubWindows; child++) {
1380			test[i].parms.objects = subWindows[child];
1381			sprintf(label, "%s (%d kids)",
1382			    LABELP(i), test[i].parms.objects);
1383			ProcessTest(&xparms, &test[i], GXcopy, ~0L, label);
1384		    }
1385		    break;
1386	        case COMP:
1387		    /* Loop through the composite operands */
1388		    for (pop = 0; pop < numPops; pop++) {
1389			for (format = 0; format < numFormats; format++) {
1390			    if (formats[format] == PictStandardNative) {
1391				if (pops[pop] == PictOpOver) {
1392				    sprintf (label, "%s", LABELP(i));
1393				} else {
1394				    sprintf (label, "(%s) %s",
1395					     popNames[pops[pop]].name,
1396					     LABELP(i));
1397				}
1398			    } else {
1399				sprintf (label, "(%s %s) %s",
1400					popNames[pops[pop]].name,
1401					formatNames[formats[format]].name,
1402					LABELP(i));
1403			    }
1404			    ProcessTest (&xparms, &test[i], pops[pop], formats[format], label);
1405			}
1406		    }
1407		    break;
1408	    } /* switch */
1409	} /* if doit */
1410    } /* ForEachTest */
1411
1412    XFreeGC(xparms.d, tgc);
1413    XDestroyWindow(xparms.d, xparms.w);
1414    XFree(vinfolist);
1415    if (drawToFakeServer)
1416      XFreePixmap(xparms.d, tileToQuery);
1417    /* Restore ScreenSaver to original state. */
1418    XSetScreenSaver(xparms.d, ssTimeout, ssInterval, ssPreferBlanking,
1419	ssAllowExposures);
1420    XCloseDisplay(xparms.d);
1421    free(saveargv);
1422    free(doit);
1423    exit(0);
1424}
1425
1426static int
1427GetWords (int argi, int argc, char **argv, char **wordsp, int *nump)
1428{
1429    int	    count;
1430
1431    if (argc <= argi)
1432	usage();
1433    count = 0;
1434    while (argv[argi] && *(argv[argi]) != '-') {
1435	*wordsp++ = argv[argi];
1436	++argi;
1437	count++;
1438    }
1439    *nump = count;
1440    return count;
1441}
1442
1443static long
1444atox (char *s)
1445{
1446    long   v, c = 0;
1447
1448    v = 0;
1449    while (*s) {
1450	if ('0' <= *s && *s <= '9')
1451	    c = *s - '0';
1452	else if ('a' <= *s && *s <= 'f')
1453	    c = *s - 'a' + 10;
1454	else if ('A' <= *s && *s <= 'F')
1455	    c = *s - 'A' + 10;
1456	v = v * 16 + c;
1457	s++;
1458    }
1459    return v;
1460}
1461
1462static int
1463GetNumbers (int argi, int argc, char **argv, unsigned long *intsp, int *nump)
1464{
1465    char    *words[256];
1466    int	    count;
1467    int	    i;
1468    int	    flip;
1469
1470    count = GetWords (argi, argc, argv, words, nump);
1471    for (i = 0; i < count; i++) {
1472	flip = 0;
1473	if (!strncmp (words[i], "~", 1)) {
1474	    words[i]++;
1475	    flip = ~0;
1476	}
1477	if (!strncmp (words[i], "0x", 2))
1478	    intsp[i] = atox(words[i] + 2) ^ flip;
1479	else
1480	    intsp[i] = atoi (words[i]) ^ flip;
1481    }
1482    return count;
1483}
1484
1485static int
1486GetRops (int argi, int argc, char **argv, int *ropsp, int *nump)
1487{
1488    char    *words[256];
1489    int	    count;
1490    int	    i;
1491    int	    rop;
1492
1493    count = GetWords (argi, argc, argv, words, nump);
1494    for (i = 0; i < count; i++) {
1495	if (!strncmp (words[i], "GX", 2))
1496	    words[i] += 2;
1497	if (!strcmp (words[i], "all")) {
1498	    for (i = 0; i < NUM_ROPS; i++)
1499		ropsp[i] = ropNames[i].rop;
1500	    *nump = NUM_ROPS;
1501	    break;
1502	}
1503	for (rop = 0; rop < NUM_ROPS; rop++) {
1504	    if (!strcmp (words[i], ropNames[rop].name)) {
1505		ropsp[i] = ropNames[rop].rop;
1506		break;
1507	    }
1508	}
1509	if (rop == NUM_ROPS) {
1510	    usage ();
1511	    fprintf (stderr, "unknown rop name %s\n", words[i]);
1512	}
1513    }
1514    return count;
1515}
1516
1517static int
1518GetPops (int argi, int argc, char **argv, int *popsp, int *nump)
1519{
1520    char    *words[256];
1521    int	    count;
1522    int	    i;
1523    int	    pop;
1524
1525    count = GetWords (argi, argc, argv, words, nump);
1526    for (i = 0; i < count; i++) {
1527	if (!strncmp (words[i], "PictOp", 6))
1528	    words[i] += 6;
1529	if (!strcmp (words[i], "all")) {
1530	    for (i = 0; i < NUM_POPS; i++)
1531		popsp[i] = popNames[i].rop;
1532	    *nump = NUM_POPS;
1533	    break;
1534	}
1535	for (pop = 0; pop < NUM_POPS; pop++) {
1536	    if (!strcmp (words[i], popNames[pop].name)) {
1537		popsp[i] = popNames[pop].rop;
1538		break;
1539	    }
1540	}
1541	if (pop == NUM_POPS) {
1542	    usage ();
1543	    fprintf (stderr, "unknown picture op name %s\n", words[i]);
1544	}
1545    }
1546    return count;
1547}
1548
1549static int
1550GetFormats (int argi, int argc, char **argv, int *formatsp, int *nump)
1551{
1552    char    *words[256];
1553    int	    count;
1554    int	    i;
1555    int	    format;
1556
1557    count = GetWords (argi, argc, argv, words, nump);
1558    for (i = 0; i < count; i++) {
1559	if (!strcmp (words[i], "all")) {
1560	    for (i = 0; i < NUM_FORMATS; i++)
1561		formatsp[i] = formatNames[i].rop;
1562	    *nump = NUM_FORMATS;
1563	    break;
1564	}
1565	for (format = 0; format < NUM_FORMATS; format++) {
1566	    if (!strcmp (words[i], formatNames[format].name)) {
1567		formatsp[i] = formatNames[format].rop;
1568		break;
1569	    }
1570	}
1571	if (format == NUM_FORMATS) {
1572	    usage ();
1573	    fprintf (stderr, "unknown format name %s\n", words[i]);
1574	}
1575    }
1576    return count;
1577}
1578