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.
23 * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
24 * Port by Brian Paul 23 March 2001
26 * Modified by Ian Romanick <idr@us.ibm.com> 09 April 2003 to support
27 * GLX_{MESA,SGI}_swap_control and GLX_OML_sync_control.
29 * Command line options:
30 * -display Name of the display to use.
31 * -info print GL implementation information
32 * -swap N Attempt to set the swap interval to 1/N second
33 * -forcegetrate Get the display refresh rate even if the required GLX
34 * extension is not supported.
43 #include <X11/keysym.h>
45 /*# include <stdint.h>*/
47 # define GLX_GLXEXT_PROTOTYPES
51 #ifndef GLX_MESA_swap_control
52 typedef GLint ( * PFNGLXSWAPINTERVALMESAPROC
) (unsigned interval
);
53 typedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC
) ( void );
56 #if !defined( GLX_OML_sync_control ) && defined( _STDINT_H )
57 #define GLX_OML_sync_control 1
58 typedef Bool ( * PFNGLXGETMSCRATEOMLPROC
) (Display
*dpy
, GLXDrawable drawable
, int32_t *numerator
, int32_t *denominator
);
61 #ifndef GLX_MESA_swap_frame_usage
62 #define GLX_MESA_swap_frame_usage 1
63 typedef int ( * PFNGLXGETFRAMEUSAGEMESAPROC
) (Display
*dpy
, GLXDrawable drawable
, float * usage
);
68 PFNGLXGETFRAMEUSAGEMESAPROC get_frame_usage
= NULL
;
72 /* XXX this probably isn't very portable */
79 /* return current time (in seconds) */
85 (void) gettimeofday(&tv
, NULL
);
88 (void) gettimeofday(&tv
, &tz
);
90 return (int) tv
.tv_sec
;
107 #define M_PI 3.14159265
111 static GLfloat view_rotx
= 20.0, view_roty
= 30.0, view_rotz
= 0.0;
112 static GLint gear1
, gear2
, gear3
;
113 static GLfloat angle
= 0.0;
115 static GLboolean has_OML_sync_control
= GL_FALSE
;
116 static GLboolean has_SGI_swap_control
= GL_FALSE
;
117 static GLboolean has_MESA_swap_control
= GL_FALSE
;
118 static GLboolean has_MESA_swap_frame_usage
= GL_FALSE
;
120 static char ** extension_table
= NULL
;
121 static unsigned num_extensions
;
123 static GLboolean use_ztrick
= GL_FALSE
;
124 static GLfloat aspectX
= 1.0f
, aspectY
= 1.0f
;
128 * Draw a gear wheel. You'll probably want to call this function when
129 * building a display list since we do a lot of trig here.
131 * Input: inner_radius - radius of hole at center
132 * outer_radius - radius at center of teeth
133 * width - width of gear
134 * teeth - number of teeth
135 * tooth_depth - depth of tooth
138 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
139 GLint teeth
, GLfloat tooth_depth
)
147 r1
= outer_radius
- tooth_depth
/ 2.0;
148 r2
= outer_radius
+ tooth_depth
/ 2.0;
150 da
= 2.0 * M_PI
/ teeth
/ 4.0;
152 glShadeModel(GL_FLAT
);
154 glNormal3f(0.0, 0.0, 1.0);
156 /* draw front face */
157 glBegin(GL_QUAD_STRIP
);
158 for (i
= 0; i
<= teeth
; i
++) {
159 angle
= i
* 2.0 * M_PI
/ teeth
;
160 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
161 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
163 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
164 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
170 /* draw front sides of teeth */
172 da
= 2.0 * M_PI
/ teeth
/ 4.0;
173 for (i
= 0; i
< teeth
; i
++) {
174 angle
= i
* 2.0 * M_PI
/ teeth
;
176 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
177 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
178 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
180 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
185 glNormal3f(0.0, 0.0, -1.0);
188 glBegin(GL_QUAD_STRIP
);
189 for (i
= 0; i
<= teeth
; i
++) {
190 angle
= i
* 2.0 * M_PI
/ teeth
;
191 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
192 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
194 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
196 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
201 /* draw back sides of teeth */
203 da
= 2.0 * M_PI
/ teeth
/ 4.0;
204 for (i
= 0; i
< teeth
; i
++) {
205 angle
= i
* 2.0 * M_PI
/ teeth
;
207 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
209 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
211 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
212 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
216 /* draw outward faces of teeth */
217 glBegin(GL_QUAD_STRIP
);
218 for (i
= 0; i
< teeth
; i
++) {
219 angle
= i
* 2.0 * M_PI
/ teeth
;
221 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
222 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
223 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
224 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
225 len
= sqrt(u
* u
+ v
* v
);
228 glNormal3f(v
, -u
, 0.0);
229 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
230 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
231 glNormal3f(cos(angle
), sin(angle
), 0.0);
232 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
234 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
236 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
237 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
238 glNormal3f(v
, -u
, 0.0);
239 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
241 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
243 glNormal3f(cos(angle
), sin(angle
), 0.0);
246 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
247 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
251 glShadeModel(GL_SMOOTH
);
253 /* draw inside radius cylinder */
254 glBegin(GL_QUAD_STRIP
);
255 for (i
= 0; i
<= teeth
; i
++) {
256 angle
= i
* 2.0 * M_PI
/ teeth
;
257 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
258 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
259 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
269 static GLboolean flip
= GL_FALSE
;
270 static const GLfloat vert
[4][3] = {
276 static const GLfloat col
[4][3] = {
284 glDepthRange(0, 0.5);
285 glDepthFunc(GL_LEQUAL
);
288 glDepthRange(1.0, 0.4999);
289 glDepthFunc(GL_GEQUAL
);
294 /* The famous Quake "Z trick" only works when the whole screen is
295 * re-drawn each frame.
298 glMatrixMode(GL_MODELVIEW
);
300 glMatrixMode(GL_PROJECTION
);
302 glOrtho(-1, 1, -1, 1, -1, 1);
303 glDisable(GL_LIGHTING
);
304 glShadeModel(GL_SMOOTH
);
306 glEnableClientState( GL_VERTEX_ARRAY
);
307 glEnableClientState( GL_COLOR_ARRAY
);
308 glVertexPointer( 3, GL_FLOAT
, 0, vert
);
309 glColorPointer( 3, GL_FLOAT
, 0, col
);
310 glDrawArrays( GL_POLYGON
, 0, 4 );
311 glDisableClientState( GL_COLOR_ARRAY
);
312 glDisableClientState( GL_VERTEX_ARRAY
);
314 glMatrixMode(GL_PROJECTION
);
316 glFrustum(-aspectX
, aspectX
, -aspectY
, aspectY
, 5.0, 60.0);
318 glEnable(GL_LIGHTING
);
320 glMatrixMode(GL_MODELVIEW
);
322 glTranslatef(0.0, 0.0, -45.0);
325 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
329 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
330 glRotatef(view_roty
, 0.0, 1.0, 0.0);
331 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
334 glTranslatef(-3.0, -2.0, 0.0);
335 glRotatef(angle
, 0.0, 0.0, 1.0);
340 glTranslatef(3.1, -2.0, 0.0);
341 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
346 glTranslatef(-3.1, 4.2, 0.0);
347 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
355 /* new window size or exposure */
357 reshape(int width
, int height
)
359 if (width
> height
) {
360 aspectX
= (GLfloat
) width
/ (GLfloat
) height
;
365 aspectY
= (GLfloat
) height
/ (GLfloat
) width
;
368 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
369 glMatrixMode(GL_PROJECTION
);
372 glFrustum(-aspectX
, aspectX
, -aspectY
, aspectY
, 5.0, 60.0);
373 glMatrixMode(GL_MODELVIEW
);
375 glTranslatef(0.0, 0.0, -45.0);
382 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
383 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
384 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 1.0 };
385 static GLfloat blue
[4] = { 0.2, 0.2, 1.0, 1.0 };
387 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
388 glEnable(GL_CULL_FACE
);
389 glEnable(GL_LIGHTING
);
391 glEnable(GL_DEPTH_TEST
);
394 gear1
= glGenLists(1);
395 glNewList(gear1
, GL_COMPILE
);
396 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
397 gear(1.0, 4.0, 1.0, 20, 0.7);
400 gear2
= glGenLists(1);
401 glNewList(gear2
, GL_COMPILE
);
402 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
403 gear(0.5, 2.0, 2.0, 10, 0.7);
406 gear3
= glGenLists(1);
407 glNewList(gear3
, GL_COMPILE
);
408 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, blue
);
409 gear(1.3, 2.0, 0.5, 10, 0.7);
412 glEnable(GL_NORMALIZE
);
417 * Remove window border/decorations.
420 no_border( Display
*dpy
, Window w
)
422 static const unsigned MWM_HINTS_DECORATIONS
= (1 << 1);
423 static const int PROP_MOTIF_WM_HINTS_ELEMENTS
= 5;
428 unsigned long functions
;
429 unsigned long decorations
;
431 unsigned long status
;
434 PropMotifWmHints motif_hints
;
436 unsigned long flags
= 0;
438 /* setup the property */
439 motif_hints
.flags
= MWM_HINTS_DECORATIONS
;
440 motif_hints
.decorations
= flags
;
442 /* get the atom for the property */
443 prop
= XInternAtom( dpy
, "_MOTIF_WM_HINTS", True
);
445 /* something went wrong! */
449 /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
452 XChangeProperty( dpy
, w
, /* display, window */
453 prop
, proptype
, /* property, type */
454 32, /* format: 32-bit datums */
455 PropModeReplace
, /* mode */
456 (unsigned char *) &motif_hints
, /* data */
457 PROP_MOTIF_WM_HINTS_ELEMENTS
/* nelements */
463 * Create an RGB, double-buffered window.
464 * Return the window and context handles.
467 make_window( Display
*dpy
, const char *name
,
468 int x
, int y
, int width
, int height
, GLboolean fullscreen
,
469 Window
*winRet
, GLXContext
*ctxRet
)
471 int attrib
[] = { GLX_RGBA
,
479 XSetWindowAttributes attr
;
484 XVisualInfo
*visinfo
;
486 scrnum
= DefaultScreen( dpy
);
487 root
= RootWindow( dpy
, scrnum
);
491 width
= DisplayWidth( dpy
, scrnum
);
492 height
= DisplayHeight( dpy
, scrnum
);
495 visinfo
= glXChooseVisual( dpy
, scrnum
, attrib
);
497 printf("Error: couldn't get an RGB, Double-buffered visual\n");
501 /* window attributes */
502 attr
.background_pixel
= 0;
503 attr
.border_pixel
= 0;
504 attr
.colormap
= XCreateColormap( dpy
, root
, visinfo
->visual
, AllocNone
);
505 attr
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
506 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
508 win
= XCreateWindow( dpy
, root
, 0, 0, width
, height
,
509 0, visinfo
->depth
, InputOutput
,
510 visinfo
->visual
, mask
, &attr
);
512 /* set hints and properties */
514 XSizeHints sizehints
;
517 sizehints
.width
= width
;
518 sizehints
.height
= height
;
519 sizehints
.flags
= USSize
| USPosition
;
520 XSetNormalHints(dpy
, win
, &sizehints
);
521 XSetStandardProperties(dpy
, win
, name
, name
,
522 None
, (char **)NULL
, 0, &sizehints
);
528 ctx
= glXCreateContext( dpy
, visinfo
, NULL
, True
);
530 printf("Error: glXCreateContext failed\n");
542 event_loop(Display
*dpy
, Window win
)
544 float frame_usage
= 0.0;
547 while (XPending(dpy
) > 0) {
549 XNextEvent(dpy
, &event
);
550 switch (event
.type
) {
552 /* we'll redraw below */
554 case ConfigureNotify
:
555 reshape(event
.xconfigure
.width
, event
.xconfigure
.height
);
561 code
= XLookupKeysym(&event
.xkey
, 0);
562 if (code
== XK_Left
) {
565 else if (code
== XK_Right
) {
568 else if (code
== XK_Up
) {
571 else if (code
== XK_Down
) {
575 r
= XLookupString(&event
.xkey
, buffer
, sizeof(buffer
),
577 if (buffer
[0] == 27) {
591 glXSwapBuffers(dpy
, win
);
593 if ( get_frame_usage
!= NULL
) {
596 (*get_frame_usage
)( dpy
, win
, & temp
);
603 static int frames
= 0;
604 int t
= current_time();
612 GLfloat seconds
= t
- t0
;
613 GLfloat fps
= frames
/ seconds
;
614 if ( get_frame_usage
!= NULL
) {
615 printf("%d frames in %3.1f seconds = %6.3f FPS (%3.1f%% usage)\n",
616 frames
, seconds
, fps
,
617 (frame_usage
* 100.0) / (float) frames
);
620 printf("%d frames in %3.1f seconds = %6.3f FPS\n",
621 frames
, seconds
, fps
);
634 * Display the refresh rate of the display using the GLX_OML_sync_control
638 show_refresh_rate( Display
* dpy
)
640 #if defined(GLX_OML_sync_control) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
641 PFNGLXGETMSCRATEOMLPROC get_msc_rate
;
645 get_msc_rate
= (PFNGLXGETMSCRATEOMLPROC
) glXGetProcAddressARB( (const GLubyte
*) "glXGetMscRateOML" );
646 if ( get_msc_rate
!= NULL
) {
647 (*get_msc_rate
)( dpy
, glXGetCurrentDrawable(), &n
, &d
);
648 printf( "refresh rate: %.1fHz\n", (float) n
/ d
);
652 printf( "glXGetMscRateOML not supported.\n" );
657 * Fill in the table of extension strings from a supplied extensions string
658 * (as returned by glXQueryExtensionsString).
660 * \param string String of GLX extensions.
661 * \sa is_extension_supported
664 make_extension_table( const char * string
)
667 unsigned num_strings
;
672 /* Count the number of spaces in the string. That gives a base-line
673 * figure for the number of extension in the string.
677 for ( i
= 0 ; string
[i
] != NUL
; i
++ ) {
678 if ( string
[i
] == ' ' ) {
683 string_tab
= (char **) malloc( sizeof( char * ) * num_strings
);
684 if ( string_tab
== NULL
) {
691 while ( string
[ base
] != NUL
) {
692 /* Determine the length of the next extension string.
696 ; (string
[ base
+ i
] != NUL
) && (string
[ base
+ i
] != ' ')
702 /* If the string was non-zero length, add it to the table. We
703 * can get zero length strings if there is a space at the end of
704 * the string or if there are two (or more) spaces next to each
705 * other in the string.
708 string_tab
[ idx
] = malloc( sizeof( char ) * (i
+ 1) );
709 if ( string_tab
[ idx
] == NULL
) {
713 (void) memcpy( string_tab
[ idx
], & string
[ base
], i
);
714 string_tab
[ idx
][i
] = NUL
;
719 /* Skip to the start of the next extension string.
723 ; (string
[ base
] == ' ') && (string
[ base
] != NUL
)
729 extension_table
= string_tab
;
730 num_extensions
= idx
;
735 * Determine of an extension is supported. The extension string table
736 * must have already be initialized by calling \c make_extension_table.
738 * \praram ext Extension to be tested.
739 * \return GL_TRUE of the extension is supported, GL_FALSE otherwise.
740 * \sa make_extension_table
743 is_extension_supported( const char * ext
)
747 for ( i
= 0 ; i
< num_extensions
; i
++ ) {
748 if ( strcmp( ext
, extension_table
[i
] ) == 0 ) {
758 main(int argc
, char *argv
[])
763 char *dpyName
= NULL
;
764 int swap_interval
= 1;
765 GLboolean do_swap_interval
= GL_FALSE
;
766 GLboolean force_get_rate
= GL_FALSE
;
767 GLboolean fullscreen
= GL_FALSE
;
768 GLboolean printInfo
= GL_FALSE
;
770 PFNGLXSWAPINTERVALMESAPROC set_swap_interval
= NULL
;
771 PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval
= NULL
;
772 int width
= 300, height
= 300;
774 for (i
= 1; i
< argc
; i
++) {
775 if (strcmp(argv
[i
], "-display") == 0 && i
+ 1 < argc
) {
779 else if (strcmp(argv
[i
], "-info") == 0) {
782 else if (strcmp(argv
[i
], "-swap") == 0 && i
+ 1 < argc
) {
783 swap_interval
= atoi( argv
[i
+1] );
784 do_swap_interval
= GL_TRUE
;
787 else if (strcmp(argv
[i
], "-forcegetrate") == 0) {
788 /* This option was put in because some DRI drivers don't support the
789 * full GLX_OML_sync_control extension, but they do support
792 force_get_rate
= GL_TRUE
;
794 else if (strcmp(argv
[i
], "-fullscreen") == 0) {
795 fullscreen
= GL_TRUE
;
797 else if (strcmp(argv
[i
], "-ztrick") == 0) {
798 use_ztrick
= GL_TRUE
;
800 else if (strcmp(argv
[i
], "-help") == 0) {
802 printf(" gears [options]\n");
803 printf("Options:\n");
804 printf(" -help Print this information\n");
805 printf(" -display displayName Specify X display\n");
806 printf(" -info Display GL information\n");
807 printf(" -swap N Swap no more than once per N vertical refreshes\n");
808 printf(" -forcegetrate Try to use glXGetMscRateOML function\n");
809 printf(" -fullscreen Full-screen window\n");
814 dpy
= XOpenDisplay(dpyName
);
816 printf("Error: couldn't open display %s\n", XDisplayName(dpyName
));
820 make_window(dpy
, "glxgears", 0, 0, width
, height
, fullscreen
, &win
, &ctx
);
821 XMapWindow(dpy
, win
);
822 glXMakeCurrent(dpy
, win
, ctx
);
824 make_extension_table( (char *) glXQueryExtensionsString(dpy
,DefaultScreen(dpy
)) );
825 has_OML_sync_control
= is_extension_supported( "GLX_OML_sync_control" );
826 has_SGI_swap_control
= is_extension_supported( "GLX_SGI_swap_control" );
827 has_MESA_swap_control
= is_extension_supported( "GLX_MESA_swap_control" );
828 has_MESA_swap_frame_usage
= is_extension_supported( "GLX_MESA_swap_frame_usage" );
830 if ( has_MESA_swap_control
) {
831 set_swap_interval
= (PFNGLXSWAPINTERVALMESAPROC
) glXGetProcAddressARB( (const GLubyte
*) "glXSwapIntervalMESA" );
832 get_swap_interval
= (PFNGLXGETSWAPINTERVALMESAPROC
) glXGetProcAddressARB( (const GLubyte
*) "glXGetSwapIntervalMESA" );
834 else if ( has_SGI_swap_control
) {
835 set_swap_interval
= (PFNGLXSWAPINTERVALMESAPROC
) glXGetProcAddressARB( (const GLubyte
*) "glXSwapIntervalSGI" );
839 if ( has_MESA_swap_frame_usage
) {
840 get_frame_usage
= (PFNGLXGETFRAMEUSAGEMESAPROC
) glXGetProcAddressARB( (const GLubyte
*) "glXGetFrameUsageMESA" );
845 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
846 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
847 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
848 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
849 if ( has_OML_sync_control
|| force_get_rate
) {
850 show_refresh_rate( dpy
);
853 if ( get_swap_interval
!= NULL
) {
854 printf("Default swap interval = %d\n", (*get_swap_interval
)() );
858 if ( do_swap_interval
) {
859 if ( set_swap_interval
!= NULL
) {
860 if ( ((swap_interval
== 0) && !has_MESA_swap_control
)
861 || (swap_interval
< 0) ) {
862 printf( "Swap interval must be non-negative or greater than zero "
863 "if GLX_MESA_swap_control is not supported.\n" );
866 (*set_swap_interval
)( swap_interval
);
869 if ( printInfo
&& (get_swap_interval
!= NULL
) ) {
870 printf("Current swap interval = %d\n", (*get_swap_interval
)() );
874 printf("Unable to set swap-interval. Neither GLX_SGI_swap_control "
875 "nor GLX_MESA_swap_control are supported.\n" );
881 /* Set initial projection/viewing transformation.
884 reshape(width
, height
);
886 event_loop(dpy
, win
);
888 glXDestroyContext(dpy
, ctx
);
889 XDestroyWindow(dpy
, win
);