1 
2 #include <X11/Xlib.h>
3 #include <X11/Xos.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 
8 class XMoveChecker {
9 	public:
10 		XMoveChecker( unsigned bsize, unsigned avgmove );
11 		virtual ~XMoveChecker();
12 		virtual	void	RollBall() = 0;
13 		double loop( unsigned long secs );
14 
15 	protected:
16 		Display	*dpy;
17 		int		scr;
18 		Window	win;
19 
20 		unsigned bsize;			// Ball-Size
21 		unsigned avgmove;			// durchschnittssprung
22 		unsigned dhelp;
23 };
24 
25 // ==========================================================================
26 
XMoveChecker(unsigned bsize_in,unsigned avg)27 XMoveChecker::XMoveChecker( unsigned bsize_in, unsigned avg )
28 : bsize(bsize_in), avgmove(avg)
29 {
30 XSetWindowAttributes setwinattr;
31 
32 	dpy   = XOpenDisplay( "" );
33 	scr   = DefaultScreen( dpy );
34 
35 	if (avgmove>bsize-1)		avgmove=bsize-1;
36 	dhelp = 2*bsize-1;
37 
38 	win   = XCreateSimpleWindow( dpy, RootWindow( dpy, scr ), 0, 0, dhelp, dhelp,
39 					0, BlackPixel( dpy,scr ), WhitePixel( dpy,scr ) );
40 	setwinattr.override_redirect = True;
41 	XChangeWindowAttributes( dpy, win, CWOverrideRedirect, &setwinattr );
42 
43 	// map window and wait for it to be mapped.
44 XEvent	event;
45 	XSelectInput( dpy, win, ExposureMask );
46 	XMapRaised( dpy, win );
47 	XNextEvent( dpy, &event );
48 }
49 
~XMoveChecker()50 XMoveChecker::~XMoveChecker() {
51 	XDestroyWindow( dpy, win );
52 	XCloseDisplay( dpy );
53 }
54 
loop(unsigned long secs)55 double XMoveChecker::loop( unsigned long secs ) {
56 struct timeval start;
57 struct timeval current;
58 struct timeval	diff;
59 long	count=-1;	// Vorlauf
60 
61 	if (secs<=5) {
62 		XGrabServer(dpy);
63 		XSync(dpy,0);
64 	}
65 
66 	do {
67 		for (int i=0;i<16;i++)		RollBall();
68 		XSync( dpy, 0 );
69 		if (count++<0)	gettimeofday( &start, NULL );
70 		gettimeofday( &current, NULL );
71 		diff.tv_sec = current.tv_sec - start.tv_sec;
72 		if ( current.tv_usec >= start.tv_usec ) {
73 			diff.tv_usec = current.tv_usec - start.tv_usec;
74 		}
75 		else {
76 			diff.tv_usec = 1000000L + current.tv_usec - start.tv_usec;
77 			diff.tv_sec--;
78 		}
79 	} while( diff.tv_sec < secs );
80 
81 	if (secs<=5) {
82 		XUngrabServer(dpy);
83 	}
84 
85 	return ( (double)count / ((double)diff.tv_sec + diff.tv_usec/1000000.0)*(double)secs );
86 }
87 
88 // ==========================================================================
89 
90 
91 class XMoveChecker1 : public XMoveChecker {
92 	public:
93 		XMoveChecker1( unsigned bsize, unsigned avg );
94 		virtual ~XMoveChecker1();
95 		virtual void RollBall();
96 
97 	protected:
98 		Pixmap	help;				// Doublebuffer:		Depth 8  (2*bsize-1)
99 		Pixmap	bpix;				// Ball-Bitmap:		Depth 1     bsize
100 		Pixmap	spix;				// Shadow-Bitmap:		Depth 1     bsize
101 		Pixmap	rpix;				// Ring-Bitmap:		Depth 1     bsize
102 		GC			gc_bclear;		// reset help-pixmap
103 		GC			gc_ballwhite;	// create white ball
104 		GC			gc_lay2;			// add shades to ball
105 		GC			gc_ball;			// add colored rings
106 		GC			gc_bxor;			// copy help pixmap to screen
107 		GC			gc_bit;			// initialize bitmaps
108 };
109 
XMoveChecker1(unsigned bsize_in,unsigned avg)110 XMoveChecker1::XMoveChecker1( unsigned bsize_in, unsigned avg )
111 : XMoveChecker( bsize_in, avg )
112 {
113 	help  = XCreatePixmap(dpy,win,dhelp,dhelp,DefaultDepth(dpy,scr));
114 
115 	bpix  = XCreatePixmap(dpy,win,bsize,bsize,1);
116 	spix  = XCreatePixmap(dpy,win,bsize,bsize,1);
117 	rpix  = XCreatePixmap(dpy,win,bsize,bsize,1);
118 
119 	gc_bit = XCreateGC( dpy, bpix, 0, 0 );
120 	XFillRectangle( dpy, bpix, gc_bit, 0, 0, bsize, bsize );
121 	XFillRectangle( dpy, spix, gc_bit, 0, 0, bsize, bsize );
122 	XFillRectangle( dpy, rpix, gc_bit, 0, 0, bsize, bsize );
123 
124 //
125 // ball_mask:  0x03
126 // shade_mask: 0x04
127 //
128 unsigned long	value_mask;
129 XGCValues		values;
130 
131 	value_mask =	GCPlaneMask | GCForeground | GCBackground | GCFunction
132 					|	GCGraphicsExposures;
133 
134 	values.graphics_exposures = False;
135 	values.fill_style	= FillSolid;
136 	values.background = 0;
137 
138 	values.foreground = 0x00;
139 	values.plane_mask = 0x07;		// Arbeiten in lay2
140 	values.function   = GXclear;
141 	gc_bclear    = XCreateGC( dpy, win, value_mask, &values );
142 	values.function   = GXxor;
143 	gc_bxor      = XCreateGC( dpy, win, value_mask, &values );
144 
145 	values.function	= GXxor;
146 	values.foreground = 0x04;
147 	values.plane_mask = 0x04;
148 	gc_lay2      = XCreateGC( dpy, win, value_mask, &values );
149 
150 	values.function	= GXxor;
151 	values.foreground = 0x01;
152 	values.plane_mask = 0x03;
153 	gc_ballwhite      = XCreateGC( dpy, win, value_mask, &values );
154 	values.foreground = 0x03;
155 	gc_ball           = XCreateGC( dpy, win, value_mask, &values );
156 }
157 
~XMoveChecker1()158 XMoveChecker1::~XMoveChecker1() {
159 	XFreeGC( dpy, gc_ball );
160 	XFreeGC( dpy, gc_ballwhite );
161 	XFreeGC( dpy, gc_lay2 );
162 	XFreeGC( dpy, gc_bxor );
163 	XFreeGC( dpy, gc_bclear );
164 	XFreePixmap( dpy, help );
165 	XFreePixmap( dpy, bpix );
166 	XFreePixmap( dpy, spix );
167 	XFreePixmap( dpy, rpix );
168 }
169 
170 // XMoveChecker1: simulates the original algorithm that consists of
171 //	- clearing the double buffer pixmap of depth 8
172 //	- copying old ball, constisting of 3 layers of depth 1
173 //	- copying new ball, consisting of 3 layers of depth 1
174 //	- copying the double buffer to the screen
175 // - 8 X-calls
176 
RollBall()177 void XMoveChecker1::RollBall() {
178 
179 int	d  = bsize;
180 int	dx = avgmove;
181 int	dy = avgmove;
182 
183 int absx = (dx>0)?dx:-dx;
184 int absy = (dy>0)?dy:-dy;
185 
186 	int	width = d+absx;		// tats�chlicher Ausschnittgr��e der Pixmap
187 	int	height= d+absy;
188 	int	ox = (dx>0)?0:absx;	// relativer Abstand alte Position
189 	int	oy = (dy>0)?0:absy;
190 	int	nx = (dx>0)?absx:0;	// relativer Abstand neue Position
191 	int	ny = (dy>0)?absy:0;
192 
193 	XFillRectangle(dpy,help,gc_bclear,0,0,width,height);
194 
195 	XCopyPlane(dpy,bpix,help,gc_ballwhite,0,0,d,d,ox,oy,1);
196 	XCopyPlane(dpy,spix,help,gc_lay2,0,0,d,d,ox,oy,1);
197 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,ox,oy,1);
198 
199 	XCopyPlane(dpy,bpix,help,gc_ballwhite,0,0,d,d,nx,ny,1);
200 	XCopyPlane(dpy,spix,help,gc_lay2,0,0,d,d,nx,ny,1);
201 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,nx,ny,1);
202 
203 	XCopyArea(dpy,help,win,gc_bxor,0,0,width,height,0,0 );
204 }
205 
206 // ==========================================================================
207 
208 class XMoveChecker2 : public XMoveChecker {
209 	public:
210 		XMoveChecker2( unsigned bsize, unsigned avg );
211 		virtual ~XMoveChecker2();
212 		virtual void RollBall();
213 
214 	protected:
215 		Pixmap	help;				// Doublebuffer:			Depth 8  (2*bsize-1)
216 		Pixmap	bpix;				// Ball/Shade-Bitmap:	Depth 8     bsize
217 		Pixmap	rpix;				// Ring-Bitmap:			Depth 1     bsize
218 		GC			gc_bcopy;		// preset help-pixmap
219 		GC			gc_ball;			// add colored rings
220 		GC			gc_bxor;			// copy help pixmap to screen
221 		GC			gc_bit;			// initialize bitmaps
222 };
223 
XMoveChecker2(unsigned bsize_in,unsigned avg)224 XMoveChecker2::XMoveChecker2( unsigned bsize_in, unsigned avg )
225 : XMoveChecker( bsize_in, avg )
226 {
227 	help  = XCreatePixmap(dpy,win,dhelp,dhelp,DefaultDepth(dpy,scr));
228 	bpix  = XCreatePixmap(dpy,win,dhelp,dhelp,DefaultDepth(dpy,scr));
229 	XFillRectangle( dpy, bpix, DefaultGC(dpy,scr), 0, 0, dhelp, dhelp );
230 
231 	rpix  = XCreatePixmap(dpy,win,bsize,bsize,1);
232 
233 	gc_bit = XCreateGC( dpy, rpix, 0, 0 );
234 	XFillRectangle( dpy, rpix, gc_bit, 0, 0, bsize, bsize );
235 
236 //
237 // ball_mask:  0x03
238 // shade_mask: 0x04
239 //
240 unsigned long	value_mask;
241 XGCValues		values;
242 
243 	value_mask =	GCPlaneMask | GCForeground | GCBackground | GCFunction
244 					|	GCGraphicsExposures;
245 
246 	values.graphics_exposures = False;
247 	values.fill_style	= FillSolid;
248 	values.background = 0;
249 
250 	values.foreground = 0x00;
251 	values.plane_mask = 0x07;
252 	values.function   = GXcopy;
253 	gc_bcopy     = XCreateGC( dpy, win, value_mask, &values );
254 	values.function   = GXxor;
255 	gc_bxor      = XCreateGC( dpy, win, value_mask, &values );
256 
257 	values.function	= GXxor;
258 	values.plane_mask = 0x03;
259 	values.foreground = 0x03;
260 	gc_ball           = XCreateGC( dpy, win, value_mask, &values );
261 }
262 
~XMoveChecker2()263 XMoveChecker2::~XMoveChecker2() {
264 	XFreeGC( dpy, gc_ball );
265 	XFreeGC( dpy, gc_bxor );
266 	XFreeGC( dpy, gc_bcopy );
267 	XFreePixmap( dpy, help );
268 	XFreePixmap( dpy, bpix );
269 	XFreePixmap( dpy, rpix );
270 }
271 
272 
273 // XMoveChecker2: simulates the enhanced algorithm that consists of
274 //	- initialisation the double buffer with an oversized 8 bit shadowed image of the old ball
275 //   (a lot more memory is need in this approach than in the next similare one)
276 //	- copying the 8 bit shadow image of the new ball
277 //	- copying 2 bitmaps with the rings of the ball with 1 bit each
278 //	- copying the double buffer to the screen
279 //	- 5 X-calls
280 
RollBall()281 void XMoveChecker2::RollBall() {
282 
283 int	d  = bsize;
284 int	dx = avgmove;
285 int	dy = avgmove;
286 
287 int absx = (dx>0)?dx:-dx;
288 int absy = (dy>0)?dy:-dy;
289 
290 	int	width = d+absx;		// tats�chlicher Ausschnittgr��e der Pixmap
291 	int	height= d+absy;
292 	int	ox = (dx>0)?0:absx;	// relativer Abstand alte Position
293 	int	oy = (dy>0)?0:absy;
294 	int	nx = (dx>0)?absx:0;	// relativer Abstand neue Position
295 	int	ny = (dy>0)?absy:0;
296 
297 	XCopyArea(dpy,bpix,help,gc_bcopy,0,0,width,height,0,0);
298 	XCopyArea(dpy,bpix,help,gc_bxor,0,0,d,d,nx,ny);
299 
300 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,ox,oy,1);
301 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,nx,ny,1);
302 
303 	XCopyArea(dpy,help,win,gc_bxor,0,0,width,height,0,0 );
304 }
305 
306 // ==========================================================================
307 
308 class XMoveChecker3 : public XMoveChecker2 {
309 	public:
310 		XMoveChecker3( unsigned bsize, unsigned avg );
311 		virtual ~XMoveChecker3();
312 		virtual void RollBall();
313 };
314 
XMoveChecker3(unsigned bsize_in,unsigned avg)315 XMoveChecker3::XMoveChecker3( unsigned bsize_in, unsigned avg )
316 : XMoveChecker2( bsize_in, avg ) {
317 }
318 
~XMoveChecker3()319 XMoveChecker3::~XMoveChecker3() {
320 }
321 
322 // XMoveChecker3: simulates the enhanced algorithm that consists of
323 //	- clearing the double buffer pixmap of depth 8
324 //	- copying the 8 bit shadow image of the balls with 8 bits each
325 //	- copying 2 bitmaps with the rings of the ball with 1 bit each
326 //	- copying the double buffer to the screen
327 //	- 6 X-calls
328 
RollBall()329 void XMoveChecker3::RollBall() {
330 
331 int	d  = bsize;
332 int	dx = avgmove;
333 int	dy = avgmove;
334 
335 int absx = (dx>0)?dx:-dx;
336 int absy = (dy>0)?dy:-dy;
337 
338 	int	width = d+absx;		// tats�chlicher Ausschnittgr��e der Pixmap
339 	int	height= d+absy;
340 	int	ox = (dx>0)?0:absx;	// relativer Abstand alte Position
341 	int	oy = (dy>0)?0:absy;
342 	int	nx = (dx>0)?absx:0;	// relativer Abstand neue Position
343 	int	ny = (dy>0)?absy:0;
344 
345 	XFillRectangle(dpy,help,gc_bcopy,0,0,width,height);
346 
347 	XCopyArea(dpy,bpix,help,gc_bxor,0,0,d,d,ox,oy);
348 	XCopyArea(dpy,bpix,help,gc_bxor,0,0,d,d,nx,ny);
349 
350 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,ox,oy,1);
351 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,nx,ny,1);
352 
353 	XCopyArea(dpy,help,win,gc_bxor,0,0,width,height,0,0 );
354 }
355 
356 // ==========================================================================
357 
358 class XMoveChecker4 : public XMoveChecker2 {
359 	public:
360 		XMoveChecker4( unsigned bsize, unsigned avg );
361 		virtual ~XMoveChecker4();
362 		virtual void RollBall();
363 };
364 
XMoveChecker4(unsigned bsize_in,unsigned avg)365 XMoveChecker4::XMoveChecker4( unsigned bsize_in, unsigned avg )
366 : XMoveChecker2( bsize_in, avg ) {
367 }
368 
~XMoveChecker4()369 XMoveChecker4::~XMoveChecker4() {
370 }
371 
372 // XMoveChecker4: simulates the enhanced algorithm that consists of
373 //	- initialisation of double-buffer parts, not covered from old ball
374 //	- initialisaion of the double-buffer part containing old ball (8 bit)
375 //	- copying the 8 bit shadow image of the new ball (8 bit)
376 //	- copying 2 bitmaps with the rings of the ball with 1 bit each
377 //	- copying the double buffer to the screen
378 //	- 6 X-calls
379 
RollBall()380 void XMoveChecker4::RollBall() {
381 
382 int	d  = bsize;
383 int	dx = avgmove;
384 int	dy = avgmove;
385 
386 int absx = (dx>0)?dx:-dx;
387 int absy = (dy>0)?dy:-dy;
388 
389 	int	width = d+absx;		// tats�chlicher Ausschnittgr��e der Pixmap
390 	int	height= d+absy;
391 	int	ox = (dx>0)?0:absx;	// relativer Abstand alte Position
392 	int	oy = (dy>0)?0:absy;
393 	int	nx = (dx>0)?absx:0;	// relativer Abstand neue Position
394 	int	ny = (dy>0)?absy:0;
395 
396 	XFillRectangle(dpy,help,gc_bcopy,0,d,width-d,height-d);
397 	XFillRectangle(dpy,help,gc_bcopy,d,0,width-d,height);
398 
399 	XCopyArea(dpy,bpix,help,gc_bcopy,0,0,d,d,ox,oy);
400 	XCopyArea(dpy,bpix,help,gc_bxor,0,0,d,d,nx,ny);
401 
402 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,ox,oy,1);
403 	XCopyPlane(dpy,rpix,help,gc_ball,0,0,d,d,nx,ny,1);
404 
405 	XCopyArea(dpy,help,win,gc_bxor,0,0,width,height,0,0 );
406 }
407 
408 // ==========================================================================
409 
410 
main_xbench(int argc,char ** argv)411 void main_xbench(int argc, char **argv)
412 {
413 XMoveChecker	*xm=0;
414 unsigned	bsize   = 24;
415 unsigned avgmove = 8;
416 unsigned count = 3;
417 unsigned secs  = 3;
418 
419 	for (int i=1;i<argc;i++) {
420 		if (!strncmp(argv[i],"-n",2))				count = atoi(argv[i]+2);
421 		else if (!strncmp(argv[i],"-s",2))		secs  = atoi(argv[i]+2);
422 		else if (!strncmp(argv[i],"-b",2))		bsize = atoi(argv[i]+2);
423 		else if (!strncmp(argv[i],"-m",2))		avgmove = atoi(argv[i]+2);
424 		else {
425 			printf( "usage: bench [-options]\n" );
426 			printf( "       -n<n>  number of tests       (def: %d)\n", count );
427 			printf( "       -s<n>  seconds of test       (def: %d)\n", secs );
428 			printf( "       -b<n>  size of pixmap        (def: %d)\n", bsize );
429 			printf( "       -m<n>  average move distance (def: %d)\n", avgmove );
430 			exit(0);
431 		}
432 	}
433 
434 	printf( "\nBenchmark for different animation modes of flying -deluxe\n" );
435 	printf( "Mode 2 usually turns out to be the fastest and\n" );
436 	printf( "therefore is turned on by default in the game.\n\n" );
437 	printf( "    Mode 1        Mode 2       Mode 3\n" );
438 	printf( "------------------------------------------\n" );
439 	fflush( stdout );
440 	while( count-- > 0 ) {
441 		for (int j=1;j<=3;j++) {
442 			switch(j) {
443 			case 1: xm = new XMoveChecker1( bsize, avgmove );	break;
444 			case 2: xm = new XMoveChecker2( bsize, avgmove );	break;
445 			case 3: xm = new XMoveChecker3( bsize, avgmove );	break;
446 			case 4: xm = new XMoveChecker4( bsize, avgmove );	break;
447 			}
448 
449 			printf( "%6.2f pics/s ", xm->loop(secs)/(double)secs );
450 			fflush(stdout);
451 			delete xm;
452 		}
453 		printf( "\n" );
454 	}
455 	printf("\nThe benchmark computes the number frames per second by\n" );
456 	printf( "assuming that all 16 balls are moving at constant speed.\n" );
457 
458 	printf("\nby Helmut H�nig, May 1995\n\n" );
459 }
460