2 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 /* $XFree86: xc/programs/glxgears/glxgears.c,v 1.3tsi Exp $ */
24 * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
25 * Port by Brian Paul 23 March 2001
27 * Exact timing added by Behdad Esfahbod to achieve a fixed speed regardless
28 * of frame rate. November 2003
30 * Printer support added by Roland Mainz <roland.mainz@nrubsig.org>. April 2004
32 * This version modified by Ian Smith, 30 Sept 2007, to make ubgears.
33 * ubgears is cusoimised for use in the UnixBench benchmarking suite.
34 * Some redundant stuff is gone, and the -time option is added.
35 * Mainly it's forked so we don't use the host's version, which could change
36 * from platform to platform.
38 * Command line options:
39 * -display Set X11 display for output.
40 * -info Print additional GLX information.
41 * -time <t> Run for <t> seconds and produce a performance report.
42 * -h Print this help page.
49 #include <X11/Xutil.h>
50 #include <X11/keysym.h>
62 #define M_PI 3.14159265
65 /* Turn a NULL pointer string into an empty string */
66 #define NULLSTR(x) (((x)!=NULL)?(x):(""))
67 #define Log(x) { if(verbose) printf x; }
68 #define Msg(x) { printf x; }
71 /* program name (from argv[0]) */
72 static const char *ProgramName
;
74 /* verbose output what the program is doing */
75 static Bool verbose
= False
;
77 /* time in microseconds to run for; -1 means forever. */
78 static int runTime
= -1;
80 /* Time at which start_time(void) was called. */
81 static struct timeval clockStart
;
83 /* XXX this probably isn't very portable */
85 /* return current time (in seconds) */
89 (void) gettimeofday(&clockStart
, 0);
93 * return time (in microseconds) since start_time(void) was called.
95 * The older version of this function randomly returned negative results.
96 * This version won't, up to 2000 seconds and some.
104 (void) gettimeofday(&tv
, 0);
106 secs
= tv
.tv_sec
- clockStart
.tv_sec
;
107 micros
= tv
.tv_usec
- clockStart
.tv_usec
;
112 return secs
* 1000000 + micros
;
118 fprintf (stderr
, "usage: %s [options]\n", ProgramName
);
119 fprintf (stderr
, "-display\tSet X11 display for output.\n");
120 fprintf (stderr
, "-info\t\tPrint additional GLX information.\n");
121 fprintf (stderr
, "-time t\t\tRun for t seconds and report performance.\n");
122 fprintf (stderr
, "-h\t\tPrint this help page.\n");
123 fprintf (stderr
, "-v\t\tVerbose output.\n");
124 fprintf (stderr
, "\n");
129 static GLfloat view_rotx
= 20.0, view_roty
= 30.0, view_rotz
= 0.0;
130 static GLint gear1
, gear2
, gear3
;
131 static GLfloat angle
= 0.0;
132 static GLint speed
= 60;
133 static GLboolean printInfo
= GL_FALSE
;
137 * Draw a gear wheel. You'll probably want to call this function when
138 * building a display list since we do a lot of trig here.
140 * Input: inner_radius - radius of hole at center
141 * outer_radius - radius at center of teeth
142 * width - width of gear
143 * teeth - number of teeth
144 * tooth_depth - depth of tooth
147 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
148 GLint teeth
, GLfloat tooth_depth
)
151 GLfloat r0
, r1
, r2
, maxr2
, minr2
;
156 r1
= outer_radius
- tooth_depth
/ 2.0;
157 maxr2
= r2
= outer_radius
+ tooth_depth
/ 2.0;
160 da
= 2.0 * M_PI
/ teeth
/ 4.0;
162 glShadeModel(GL_FLAT
);
164 glNormal3f(0.0, 0.0, 1.0);
166 /* draw front face */
167 glBegin(GL_QUAD_STRIP
);
168 for (i
= 0; i
<= teeth
; i
++) {
169 angle
= i
* 2.0 * M_PI
/ teeth
;
170 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
171 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
173 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
174 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
180 /* draw front sides of teeth */
182 for (i
= 0; i
< teeth
; i
++) {
183 angle
= i
* 2.0 * M_PI
/ teeth
;
185 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
186 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
187 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
189 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
196 glNormal3f(0.0, 0.0, -1.0);
199 glBegin(GL_QUAD_STRIP
);
200 for (i
= 0; i
<= teeth
; i
++) {
201 angle
= i
* 2.0 * M_PI
/ teeth
;
202 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
203 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
205 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
207 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
212 /* draw back sides of teeth */
214 da
= 2.0 * M_PI
/ teeth
/ 4.0;
215 for (i
= 0; i
< teeth
; i
++) {
216 angle
= i
* 2.0 * M_PI
/ teeth
;
218 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
220 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
222 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
223 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
229 /* draw outward faces of teeth */
230 glBegin(GL_QUAD_STRIP
);
231 for (i
= 0; i
< teeth
; i
++) {
232 angle
= i
* 2.0 * M_PI
/ teeth
;
234 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
235 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
236 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
237 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
238 len
= sqrt(u
* u
+ v
* v
);
241 glNormal3f(v
, -u
, 0.0);
242 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
243 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
244 glNormal3f(cos(angle
+ 1.5 * da
), sin(angle
+ 1.5 * da
), 0.0);
245 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
247 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
249 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
250 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
251 glNormal3f(v
, -u
, 0.0);
252 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
254 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
256 glNormal3f(cos(angle
+ 3.5 * da
), sin(angle
+ 3.5 * da
), 0.0);
261 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
262 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
266 glShadeModel(GL_SMOOTH
);
268 /* draw inside radius cylinder */
269 glBegin(GL_QUAD_STRIP
);
270 for (i
= 0; i
<= teeth
; i
++) {
271 angle
= i
* 2.0 * M_PI
/ teeth
;
272 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
273 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
274 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
283 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
286 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
287 glRotatef(view_roty
, 0.0, 1.0, 0.0);
288 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
291 glTranslatef(-3.0, -2.0, 0.0);
292 glRotatef(angle
, 0.0, 0.0, 1.0);
297 glTranslatef(3.1, -2.0, 0.0);
298 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
303 glTranslatef(-3.1, 4.2, 0.0);
304 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
312 /* new window size or exposure */
314 reshape(int width
, int height
)
316 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
318 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
319 glMatrixMode(GL_PROJECTION
);
321 /* fit width and height */
323 glFrustum(-1.0, 1.0, -h
, h
, 5.0, 60.0);
325 glFrustum(-1.0/h
, 1.0/h
, -1.0, 1.0, 5.0, 60.0);
326 glMatrixMode(GL_MODELVIEW
);
328 glTranslatef(0.0, 0.0, -40.0);
335 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
336 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
337 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 1.0 };
338 static GLfloat blue
[4] = { 0.2, 0.2, 1.0, 1.0 };
340 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
341 glEnable(GL_CULL_FACE
);
342 glEnable(GL_LIGHTING
);
344 glEnable(GL_DEPTH_TEST
);
347 gear1
= glGenLists(1);
348 glNewList(gear1
, GL_COMPILE
);
349 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
350 gear(1.0, 4.0, 1.0, 20, 0.7);
353 gear2
= glGenLists(1);
354 glNewList(gear2
, GL_COMPILE
);
355 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
356 gear(0.5, 2.0, 2.0, 10, 0.7);
359 gear3
= glGenLists(1);
360 glNewList(gear3
, GL_COMPILE
);
361 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, blue
);
362 gear(1.3, 2.0, 0.5, 10, 0.7);
365 glEnable(GL_NORMALIZE
);
370 * Create an RGB, double-buffered window.
371 * Return the window and context handles.
374 make_window( Display
*dpy
, Screen
*scr
,
376 int x
, int y
, int width
, int height
,
377 Window
*winRet
, GLXContext
*ctxRet
)
379 int attrib
[] = { GLX_RGBA
,
387 XSetWindowAttributes attr
;
392 XVisualInfo
*visinfo
;
393 GLint max
[2] = { 0, 0 };
395 scrnum
= XScreenNumberOfScreen(scr
);
396 root
= XRootWindow(dpy
, scrnum
);
398 visinfo
= glXChooseVisual( dpy
, scrnum
, attrib
);
400 fprintf(stderr
, "%s: Error: couldn't get an RGB, Double-buffered visual.\n", ProgramName
);
404 /* window attributes */
405 attr
.background_pixel
= 0;
406 attr
.border_pixel
= 0;
407 attr
.colormap
= XCreateColormap( dpy
, root
, visinfo
->visual
, AllocNone
);
408 attr
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
409 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
411 win
= XCreateWindow( dpy
, root
, x
, y
, width
, height
,
412 0, visinfo
->depth
, InputOutput
,
413 visinfo
->visual
, mask
, &attr
);
415 /* set hints and properties */
417 XSizeHints sizehints
;
420 sizehints
.width
= width
;
421 sizehints
.height
= height
;
422 sizehints
.flags
= USSize
| USPosition
;
423 XSetNormalHints(dpy
, win
, &sizehints
);
424 XSetStandardProperties(dpy
, win
, name
, name
,
425 None
, (char **)NULL
, 0, &sizehints
);
428 ctx
= glXCreateContext( dpy
, visinfo
, NULL
, True
);
430 fprintf(stderr
, "%s: Error: glXCreateContext failed.\n", ProgramName
);
436 XMapWindow(dpy
, win
);
437 glXMakeCurrent(dpy
, win
, ctx
);
439 /* Check for maximum size supported by the GL rasterizer */
440 glGetIntegerv(GL_MAX_VIEWPORT_DIMS
, max
);
442 printf("GL_MAX_VIEWPORT_DIMS=%d/%d\n", (int)max
[0], (int)max
[1]);
443 if (width
> max
[0] || height
> max
[1]) {
444 fprintf(stderr
, "%s: Error: Requested window size (%d/%d) larger than "
445 "maximum supported by GL engine (%d/%d).\n",
446 ProgramName
, width
, height
, (int)max
[0], (int)max
[1]);
455 event_loop(Display
*dpy
, Window win
)
458 /* Process interactive events */
459 while (XPending(dpy
) > 0) {
461 XNextEvent(dpy
, &event
);
462 switch (event
.type
) {
464 Log(("Event: Expose\n"));
465 /* we'll redraw below */
467 case ConfigureNotify
:
468 Log(("Event: ConfigureNotify\n"));
469 reshape(event
.xconfigure
.width
, event
.xconfigure
.height
);
475 /* Time at which we started measuring. */
476 static long startTime
= 0;
478 /* Time of the previous frame. */
479 static long lastFrame
= 0;
481 /* Time of the previous FPS report. */
482 static long lastFps
= 0;
484 /* Number of frames we've done. */
485 static int frames
= 0;
487 /* Number of frames we've done in the measured run. */
488 static long runFrames
= 0;
490 long t
= current_time();
498 /* How many microseconds since the previous frame? */
499 useconds
= t
- lastFrame
;
500 if (!useconds
) /* assume 100FPS if we don't have timer */
503 /* Calculate how far the gears need to move and redraw. */
504 angle
= angle
+ ((double)speed
* useconds
) / 1000000.0;
506 angle
= angle
- 360.0; /* don't lose precision! */
508 glXSwapBuffers(dpy
, win
);
510 /* Done this frame. */
514 /* Every 5 seconds, print the FPS. */
515 if (t
- lastFps
>= 5000000L) {
516 GLfloat seconds
= (t
- lastFps
) / 1000000.0;
517 GLfloat fps
= frames
/ seconds
;
519 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames
, seconds
,
525 * Set the start time now -- ie. after one report. This
526 * gives us pump-priming time before we start for real.
528 if (runTime
> 0 && startTime
== 0) {
529 printf("Start timing!\n");
537 /* If our run time is done, finish. */
538 if (runTime
> 0 && startTime
> 0 && t
- startTime
> runTime
) {
539 double time
= (double) (t
- startTime
) / 1000000.0;
540 fprintf(stderr
, "COUNT|%ld|1|fps\n", runFrames
);
541 fprintf(stderr
, "TIME|%.1f\n", time
);
545 /* Need to give cpu away in order to get precise timing next cycle,
546 * otherwise, gettimeofday would return almost the same value. */
554 main(int argc
, char *argv
[])
556 Bool use_threadsafe_api
= False
;
561 char *dpyName
= NULL
;
565 ProgramName
= argv
[0];
567 for (i
= 1; i
< argc
; i
++) {
568 const char *arg
= argv
[i
];
569 int len
= strlen(arg
);
571 if (strcmp(argv
[i
], "-display") == 0) {
576 else if (strcmp(argv
[i
], "-info") == 0) {
579 else if (strcmp(argv
[i
], "-time") == 0) {
582 runTime
= atoi(argv
[i
]) * 1000000;
584 else if (!strncmp("-v", arg
, len
)) {
588 else if( !strncmp("-debug_use_threadsafe_api", arg
, len
) )
590 use_threadsafe_api
= True
;
592 else if (!strcmp(argv
[i
], "-h")) {
597 fprintf(stderr
, "%s: Unsupported option '%s'.\n", ProgramName
, argv
[i
]);
602 /* Init X threading API on demand (for debugging) */
603 if( use_threadsafe_api
)
605 if( !XInitThreads() )
607 fprintf(stderr
, "%s: XInitThreads() failure.\n", ProgramName
);
612 dpy
= XOpenDisplay(dpyName
);
614 fprintf(stderr
, "%s: Error: couldn't open display '%s'\n", ProgramName
, dpyName
);
618 screen
= XDefaultScreenOfDisplay(dpy
);
623 winrect
.height
= 300;
625 Log(("Window x=%d, y=%d, width=%d, height=%d\n",
626 (int)winrect
.x
, (int)winrect
.y
, (int)winrect
.width
, (int)winrect
.height
));
628 make_window(dpy
, screen
, "ubgears", winrect
.x
, winrect
.y
, winrect
.width
, winrect
.height
, &win
, &ctx
);
629 reshape(winrect
.width
, winrect
.height
);
632 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
633 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
634 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
635 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
641 event_loop(dpy
, win
);
643 glXDestroyContext(dpy
, ctx
);
645 XDestroyWindow(dpy
, win
);