Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

glxswapcontrol.c 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /*
  2. * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
  3. *
  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:
  10. *
  11. * The above copyright notice and this permission notice shall be included
  12. * in all copies or substantial portions of the Software.
  13. *
  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.
  20. */
  21. /*
  22. * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
  23. * Port by Brian Paul 23 March 2001
  24. *
  25. * Modified by Ian Romanick <idr@us.ibm.com> 09 April 2003 to support
  26. * GLX_{MESA,SGI}_swap_control and GLX_OML_sync_control.
  27. *
  28. * Command line options:
  29. * -display Name of the display to use.
  30. * -info print GL implementation information
  31. * -swap N Attempt to set the swap interval to 1/N second
  32. * -forcegetrate Get the display refresh rate even if the required GLX
  33. * extension is not supported.
  34. */
  35. #include <math.h>
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <X11/Xlib.h>
  40. #include <X11/keysym.h>
  41. #ifndef __VMS
  42. /*# include <stdint.h>*/
  43. #endif
  44. # define GLX_GLXEXT_PROTOTYPES
  45. #include <GL/gl.h>
  46. #include <GL/glx.h>
  47. #ifndef GLX_MESA_swap_control
  48. typedef GLint ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
  49. typedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC) ( void );
  50. #endif
  51. #if !defined( GLX_OML_sync_control ) && defined( _STDINT_H )
  52. #define GLX_OML_sync_control 1
  53. typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
  54. #endif
  55. #ifndef GLX_MESA_swap_frame_usage
  56. #define GLX_MESA_swap_frame_usage 1
  57. typedef int ( * PFNGLXGETFRAMEUSAGEMESAPROC) (Display *dpy, GLXDrawable drawable, float * usage );
  58. #endif
  59. #define BENCHMARK
  60. PFNGLXGETFRAMEUSAGEMESAPROC get_frame_usage = NULL;
  61. #ifdef BENCHMARK
  62. /* XXX this probably isn't very portable */
  63. #include <sys/time.h>
  64. #include <unistd.h>
  65. #define NUL '\0'
  66. /* return current time (in seconds) */
  67. static int
  68. current_time(void)
  69. {
  70. struct timeval tv;
  71. #ifdef __VMS
  72. (void) gettimeofday(&tv, NULL );
  73. #else
  74. struct timezone tz;
  75. (void) gettimeofday(&tv, &tz);
  76. #endif
  77. return (int) tv.tv_sec;
  78. }
  79. #else /*BENCHMARK*/
  80. /* dummy */
  81. static int
  82. current_time(void)
  83. {
  84. return 0;
  85. }
  86. #endif /*BENCHMARK*/
  87. #ifndef M_PI
  88. #define M_PI 3.14159265
  89. #endif
  90. static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
  91. static GLint gear1, gear2, gear3;
  92. static GLfloat angle = 0.0;
  93. static GLboolean has_OML_sync_control = GL_FALSE;
  94. static GLboolean has_SGI_swap_control = GL_FALSE;
  95. static GLboolean has_MESA_swap_control = GL_FALSE;
  96. static GLboolean has_MESA_swap_frame_usage = GL_FALSE;
  97. static char ** extension_table = NULL;
  98. static unsigned num_extensions;
  99. static GLboolean use_ztrick = GL_FALSE;
  100. static GLfloat aspectX = 1.0f, aspectY = 1.0f;
  101. /*
  102. *
  103. * Draw a gear wheel. You'll probably want to call this function when
  104. * building a display list since we do a lot of trig here.
  105. *
  106. * Input: inner_radius - radius of hole at center
  107. * outer_radius - radius at center of teeth
  108. * width - width of gear
  109. * teeth - number of teeth
  110. * tooth_depth - depth of tooth
  111. */
  112. static void
  113. gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
  114. GLint teeth, GLfloat tooth_depth)
  115. {
  116. GLint i;
  117. GLfloat r0, r1, r2;
  118. GLfloat angle, da;
  119. GLfloat u, v, len;
  120. r0 = inner_radius;
  121. r1 = outer_radius - tooth_depth / 2.0;
  122. r2 = outer_radius + tooth_depth / 2.0;
  123. da = 2.0 * M_PI / teeth / 4.0;
  124. glShadeModel(GL_FLAT);
  125. glNormal3f(0.0, 0.0, 1.0);
  126. /* draw front face */
  127. glBegin(GL_QUAD_STRIP);
  128. for (i = 0; i <= teeth; i++) {
  129. angle = i * 2.0 * M_PI / teeth;
  130. glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
  131. glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
  132. if (i < teeth) {
  133. glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
  134. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  135. width * 0.5);
  136. }
  137. }
  138. glEnd();
  139. /* draw front sides of teeth */
  140. glBegin(GL_QUADS);
  141. da = 2.0 * M_PI / teeth / 4.0;
  142. for (i = 0; i < teeth; i++) {
  143. angle = i * 2.0 * M_PI / teeth;
  144. glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
  145. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
  146. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  147. width * 0.5);
  148. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  149. width * 0.5);
  150. }
  151. glEnd();
  152. glNormal3f(0.0, 0.0, -1.0);
  153. /* draw back face */
  154. glBegin(GL_QUAD_STRIP);
  155. for (i = 0; i <= teeth; i++) {
  156. angle = i * 2.0 * M_PI / teeth;
  157. glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
  158. glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
  159. if (i < teeth) {
  160. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  161. -width * 0.5);
  162. glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
  163. }
  164. }
  165. glEnd();
  166. /* draw back sides of teeth */
  167. glBegin(GL_QUADS);
  168. da = 2.0 * M_PI / teeth / 4.0;
  169. for (i = 0; i < teeth; i++) {
  170. angle = i * 2.0 * M_PI / teeth;
  171. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  172. -width * 0.5);
  173. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  174. -width * 0.5);
  175. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
  176. glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
  177. }
  178. glEnd();
  179. /* draw outward faces of teeth */
  180. glBegin(GL_QUAD_STRIP);
  181. for (i = 0; i < teeth; i++) {
  182. angle = i * 2.0 * M_PI / teeth;
  183. glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
  184. glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
  185. u = r2 * cos(angle + da) - r1 * cos(angle);
  186. v = r2 * sin(angle + da) - r1 * sin(angle);
  187. len = sqrt(u * u + v * v);
  188. u /= len;
  189. v /= len;
  190. glNormal3f(v, -u, 0.0);
  191. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
  192. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
  193. glNormal3f(cos(angle), sin(angle), 0.0);
  194. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  195. width * 0.5);
  196. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  197. -width * 0.5);
  198. u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
  199. v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
  200. glNormal3f(v, -u, 0.0);
  201. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  202. width * 0.5);
  203. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  204. -width * 0.5);
  205. glNormal3f(cos(angle), sin(angle), 0.0);
  206. }
  207. glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
  208. glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
  209. glEnd();
  210. glShadeModel(GL_SMOOTH);
  211. /* draw inside radius cylinder */
  212. glBegin(GL_QUAD_STRIP);
  213. for (i = 0; i <= teeth; i++) {
  214. angle = i * 2.0 * M_PI / teeth;
  215. glNormal3f(-cos(angle), -sin(angle), 0.0);
  216. glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
  217. glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
  218. }
  219. glEnd();
  220. }
  221. static void
  222. draw(void)
  223. {
  224. if ( use_ztrick ) {
  225. static GLboolean flip = GL_FALSE;
  226. static const GLfloat vert[4][3] = {
  227. { -1, -1, -0.999 },
  228. { 1, -1, -0.999 },
  229. { 1, 1, -0.999 },
  230. { -1, 1, -0.999 }
  231. };
  232. static const GLfloat col[4][3] = {
  233. { 1.0, 0.6, 0.0 },
  234. { 1.0, 0.6, 0.0 },
  235. { 0.0, 0.0, 0.0 },
  236. { 0.0, 0.0, 0.0 },
  237. };
  238. if ( flip ) {
  239. glDepthRange(0, 0.5);
  240. glDepthFunc(GL_LEQUAL);
  241. }
  242. else {
  243. glDepthRange(1.0, 0.4999);
  244. glDepthFunc(GL_GEQUAL);
  245. }
  246. flip = !flip;
  247. /* The famous Quake "Z trick" only works when the whole screen is
  248. * re-drawn each frame.
  249. */
  250. glMatrixMode(GL_MODELVIEW);
  251. glLoadIdentity();
  252. glMatrixMode(GL_PROJECTION);
  253. glLoadIdentity();
  254. glOrtho(-1, 1, -1, 1, -1, 1);
  255. glDisable(GL_LIGHTING);
  256. glShadeModel(GL_SMOOTH);
  257. glEnableClientState( GL_VERTEX_ARRAY );
  258. glEnableClientState( GL_COLOR_ARRAY );
  259. glVertexPointer( 3, GL_FLOAT, 0, vert );
  260. glColorPointer( 3, GL_FLOAT, 0, col );
  261. glDrawArrays( GL_POLYGON, 0, 4 );
  262. glDisableClientState( GL_COLOR_ARRAY );
  263. glDisableClientState( GL_VERTEX_ARRAY );
  264. glMatrixMode(GL_PROJECTION);
  265. glLoadIdentity();
  266. glFrustum(-aspectX, aspectX, -aspectY, aspectY, 5.0, 60.0);
  267. glEnable(GL_LIGHTING);
  268. glMatrixMode(GL_MODELVIEW);
  269. glLoadIdentity();
  270. glTranslatef(0.0, 0.0, -45.0);
  271. }
  272. else {
  273. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  274. }
  275. glPushMatrix();
  276. glRotatef(view_rotx, 1.0, 0.0, 0.0);
  277. glRotatef(view_roty, 0.0, 1.0, 0.0);
  278. glRotatef(view_rotz, 0.0, 0.0, 1.0);
  279. glPushMatrix();
  280. glTranslatef(-3.0, -2.0, 0.0);
  281. glRotatef(angle, 0.0, 0.0, 1.0);
  282. glCallList(gear1);
  283. glPopMatrix();
  284. glPushMatrix();
  285. glTranslatef(3.1, -2.0, 0.0);
  286. glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
  287. glCallList(gear2);
  288. glPopMatrix();
  289. glPushMatrix();
  290. glTranslatef(-3.1, 4.2, 0.0);
  291. glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
  292. glCallList(gear3);
  293. glPopMatrix();
  294. glPopMatrix();
  295. }
  296. /* new window size or exposure */
  297. static void
  298. reshape(int width, int height)
  299. {
  300. if (width > height) {
  301. aspectX = (GLfloat) width / (GLfloat) height;
  302. aspectY = 1.0;
  303. }
  304. else {
  305. aspectX = 1.0;
  306. aspectY = (GLfloat) height / (GLfloat) width;
  307. }
  308. glViewport(0, 0, (GLint) width, (GLint) height);
  309. glMatrixMode(GL_PROJECTION);
  310. glLoadIdentity();
  311. glFrustum(-aspectX, aspectX, -aspectY, aspectY, 5.0, 60.0);
  312. glMatrixMode(GL_MODELVIEW);
  313. glLoadIdentity();
  314. glTranslatef(0.0, 0.0, -45.0);
  315. }
  316. static void
  317. init(void)
  318. {
  319. static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
  320. static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
  321. static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
  322. static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
  323. glLightfv(GL_LIGHT0, GL_POSITION, pos);
  324. glEnable(GL_CULL_FACE);
  325. glEnable(GL_LIGHTING);
  326. glEnable(GL_LIGHT0);
  327. glEnable(GL_DEPTH_TEST);
  328. /* make the gears */
  329. gear1 = glGenLists(1);
  330. glNewList(gear1, GL_COMPILE);
  331. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
  332. gear(1.0, 4.0, 1.0, 20, 0.7);
  333. glEndList();
  334. gear2 = glGenLists(1);
  335. glNewList(gear2, GL_COMPILE);
  336. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
  337. gear(0.5, 2.0, 2.0, 10, 0.7);
  338. glEndList();
  339. gear3 = glGenLists(1);
  340. glNewList(gear3, GL_COMPILE);
  341. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
  342. gear(1.3, 2.0, 0.5, 10, 0.7);
  343. glEndList();
  344. glEnable(GL_NORMALIZE);
  345. }
  346. /**
  347. * Remove window border/decorations.
  348. */
  349. static void
  350. no_border( Display *dpy, Window w)
  351. {
  352. static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
  353. static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
  354. typedef struct
  355. {
  356. unsigned long flags;
  357. unsigned long functions;
  358. unsigned long decorations;
  359. long inputMode;
  360. unsigned long status;
  361. } PropMotifWmHints;
  362. PropMotifWmHints motif_hints;
  363. Atom prop, proptype;
  364. unsigned long flags = 0;
  365. /* setup the property */
  366. motif_hints.flags = MWM_HINTS_DECORATIONS;
  367. motif_hints.decorations = flags;
  368. /* get the atom for the property */
  369. prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
  370. if (!prop) {
  371. /* something went wrong! */
  372. return;
  373. }
  374. /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
  375. proptype = prop;
  376. XChangeProperty( dpy, w, /* display, window */
  377. prop, proptype, /* property, type */
  378. 32, /* format: 32-bit datums */
  379. PropModeReplace, /* mode */
  380. (unsigned char *) &motif_hints, /* data */
  381. PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
  382. );
  383. }
  384. /*
  385. * Create an RGB, double-buffered window.
  386. * Return the window and context handles.
  387. */
  388. static void
  389. make_window( Display *dpy, const char *name,
  390. int x, int y, int width, int height, GLboolean fullscreen,
  391. Window *winRet, GLXContext *ctxRet)
  392. {
  393. int attrib[] = { GLX_RGBA,
  394. GLX_RED_SIZE, 1,
  395. GLX_GREEN_SIZE, 1,
  396. GLX_BLUE_SIZE, 1,
  397. GLX_DOUBLEBUFFER,
  398. GLX_DEPTH_SIZE, 1,
  399. None };
  400. int scrnum;
  401. XSetWindowAttributes attr;
  402. unsigned long mask;
  403. Window root;
  404. Window win;
  405. GLXContext ctx;
  406. XVisualInfo *visinfo;
  407. scrnum = DefaultScreen( dpy );
  408. root = RootWindow( dpy, scrnum );
  409. if (fullscreen) {
  410. x = y = 0;
  411. width = DisplayWidth( dpy, scrnum );
  412. height = DisplayHeight( dpy, scrnum );
  413. }
  414. visinfo = glXChooseVisual( dpy, scrnum, attrib );
  415. if (!visinfo) {
  416. printf("Error: couldn't get an RGB, Double-buffered visual\n");
  417. exit(1);
  418. }
  419. /* window attributes */
  420. attr.background_pixel = 0;
  421. attr.border_pixel = 0;
  422. attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
  423. attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
  424. mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
  425. win = XCreateWindow( dpy, root, 0, 0, width, height,
  426. 0, visinfo->depth, InputOutput,
  427. visinfo->visual, mask, &attr );
  428. /* set hints and properties */
  429. {
  430. XSizeHints sizehints;
  431. sizehints.x = x;
  432. sizehints.y = y;
  433. sizehints.width = width;
  434. sizehints.height = height;
  435. sizehints.flags = USSize | USPosition;
  436. XSetNormalHints(dpy, win, &sizehints);
  437. XSetStandardProperties(dpy, win, name, name,
  438. None, (char **)NULL, 0, &sizehints);
  439. }
  440. if (fullscreen)
  441. no_border(dpy, win);
  442. ctx = glXCreateContext( dpy, visinfo, NULL, True );
  443. if (!ctx) {
  444. printf("Error: glXCreateContext failed\n");
  445. exit(1);
  446. }
  447. XFree(visinfo);
  448. *winRet = win;
  449. *ctxRet = ctx;
  450. }
  451. static void
  452. event_loop(Display *dpy, Window win)
  453. {
  454. float frame_usage = 0.0;
  455. while (1) {
  456. while (XPending(dpy) > 0) {
  457. XEvent event;
  458. XNextEvent(dpy, &event);
  459. switch (event.type) {
  460. case Expose:
  461. /* we'll redraw below */
  462. break;
  463. case ConfigureNotify:
  464. reshape(event.xconfigure.width, event.xconfigure.height);
  465. break;
  466. case KeyPress:
  467. {
  468. char buffer[10];
  469. int r, code;
  470. code = XLookupKeysym(&event.xkey, 0);
  471. if (code == XK_Left) {
  472. view_roty += 5.0;
  473. }
  474. else if (code == XK_Right) {
  475. view_roty -= 5.0;
  476. }
  477. else if (code == XK_Up) {
  478. view_rotx += 5.0;
  479. }
  480. else if (code == XK_Down) {
  481. view_rotx -= 5.0;
  482. }
  483. else {
  484. r = XLookupString(&event.xkey, buffer, sizeof(buffer),
  485. NULL, NULL);
  486. if (buffer[0] == 27) {
  487. /* escape */
  488. return;
  489. }
  490. }
  491. }
  492. }
  493. }
  494. /* next frame */
  495. angle += 2.0;
  496. draw();
  497. glXSwapBuffers(dpy, win);
  498. if ( get_frame_usage != NULL ) {
  499. GLfloat temp;
  500. (*get_frame_usage)( dpy, win, & temp );
  501. frame_usage += temp;
  502. }
  503. /* calc framerate */
  504. {
  505. static int t0 = -1;
  506. static int frames = 0;
  507. int t = current_time();
  508. if (t0 < 0)
  509. t0 = t;
  510. frames++;
  511. if (t - t0 >= 5.0) {
  512. GLfloat seconds = t - t0;
  513. GLfloat fps = frames / seconds;
  514. if ( get_frame_usage != NULL ) {
  515. printf("%d frames in %3.1f seconds = %6.3f FPS (%3.1f%% usage)\n",
  516. frames, seconds, fps,
  517. (frame_usage * 100.0) / (float) frames );
  518. }
  519. else {
  520. printf("%d frames in %3.1f seconds = %6.3f FPS\n",
  521. frames, seconds, fps);
  522. }
  523. t0 = t;
  524. frames = 0;
  525. frame_usage = 0.0;
  526. }
  527. }
  528. }
  529. }
  530. /**
  531. * Display the refresh rate of the display using the GLX_OML_sync_control
  532. * extension.
  533. */
  534. static void
  535. show_refresh_rate( Display * dpy )
  536. {
  537. #if defined(GLX_OML_sync_control) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
  538. PFNGLXGETMSCRATEOMLPROC get_msc_rate;
  539. int32_t n;
  540. int32_t d;
  541. get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetMscRateOML" );
  542. if ( get_msc_rate != NULL ) {
  543. (*get_msc_rate)( dpy, glXGetCurrentDrawable(), &n, &d );
  544. printf( "refresh rate: %.1fHz\n", (float) n / d );
  545. return;
  546. }
  547. #endif
  548. printf( "glXGetMscRateOML not supported.\n" );
  549. }
  550. /**
  551. * Fill in the table of extension strings from a supplied extensions string
  552. * (as returned by glXQueryExtensionsString).
  553. *
  554. * \param string String of GLX extensions.
  555. * \sa is_extension_supported
  556. */
  557. static void
  558. make_extension_table( const char * string )
  559. {
  560. char ** string_tab;
  561. unsigned num_strings;
  562. unsigned base;
  563. unsigned idx;
  564. unsigned i;
  565. /* Count the number of spaces in the string. That gives a base-line
  566. * figure for the number of extension in the string.
  567. */
  568. num_strings = 1;
  569. for ( i = 0 ; string[i] != NUL ; i++ ) {
  570. if ( string[i] == ' ' ) {
  571. num_strings++;
  572. }
  573. }
  574. string_tab = (char **) malloc( sizeof( char * ) * num_strings );
  575. if ( string_tab == NULL ) {
  576. return;
  577. }
  578. base = 0;
  579. idx = 0;
  580. while ( string[ base ] != NUL ) {
  581. /* Determine the length of the next extension string.
  582. */
  583. for ( i = 0
  584. ; (string[ base + i ] != NUL) && (string[ base + i ] != ' ')
  585. ; i++ ) {
  586. /* empty */ ;
  587. }
  588. if ( i > 0 ) {
  589. /* If the string was non-zero length, add it to the table. We
  590. * can get zero length strings if there is a space at the end of
  591. * the string or if there are two (or more) spaces next to each
  592. * other in the string.
  593. */
  594. string_tab[ idx ] = malloc( sizeof( char ) * (i + 1) );
  595. if ( string_tab[ idx ] == NULL ) {
  596. return;
  597. }
  598. (void) memcpy( string_tab[ idx ], & string[ base ], i );
  599. string_tab[ idx ][i] = NUL;
  600. idx++;
  601. }
  602. /* Skip to the start of the next extension string.
  603. */
  604. for ( base += i
  605. ; (string[ base ] == ' ') && (string[ base ] != NUL)
  606. ; base++ ) {
  607. /* empty */ ;
  608. }
  609. }
  610. extension_table = string_tab;
  611. num_extensions = idx;
  612. }
  613. /**
  614. * Determine of an extension is supported. The extension string table
  615. * must have already be initialized by calling \c make_extension_table.
  616. *
  617. * \praram ext Extension to be tested.
  618. * \return GL_TRUE of the extension is supported, GL_FALSE otherwise.
  619. * \sa make_extension_table
  620. */
  621. static GLboolean
  622. is_extension_supported( const char * ext )
  623. {
  624. unsigned i;
  625. for ( i = 0 ; i < num_extensions ; i++ ) {
  626. if ( strcmp( ext, extension_table[i] ) == 0 ) {
  627. return GL_TRUE;
  628. }
  629. }
  630. return GL_FALSE;
  631. }
  632. int
  633. main(int argc, char *argv[])
  634. {
  635. Display *dpy;
  636. Window win;
  637. GLXContext ctx;
  638. char *dpyName = NULL;
  639. int swap_interval = 1;
  640. GLboolean do_swap_interval = GL_FALSE;
  641. GLboolean force_get_rate = GL_FALSE;
  642. GLboolean fullscreen = GL_FALSE;
  643. GLboolean printInfo = GL_FALSE;
  644. int i;
  645. PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL;
  646. PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL;
  647. int width = 300, height = 300;
  648. for (i = 1; i < argc; i++) {
  649. if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
  650. dpyName = argv[i+1];
  651. i++;
  652. }
  653. else if (strcmp(argv[i], "-info") == 0) {
  654. printInfo = GL_TRUE;
  655. }
  656. else if (strcmp(argv[i], "-swap") == 0 && i + 1 < argc) {
  657. swap_interval = atoi( argv[i+1] );
  658. do_swap_interval = GL_TRUE;
  659. i++;
  660. }
  661. else if (strcmp(argv[i], "-forcegetrate") == 0) {
  662. /* This option was put in because some DRI drivers don't support the
  663. * full GLX_OML_sync_control extension, but they do support
  664. * glXGetMscRateOML.
  665. */
  666. force_get_rate = GL_TRUE;
  667. }
  668. else if (strcmp(argv[i], "-fullscreen") == 0) {
  669. fullscreen = GL_TRUE;
  670. }
  671. else if (strcmp(argv[i], "-ztrick") == 0) {
  672. use_ztrick = GL_TRUE;
  673. }
  674. else if (strcmp(argv[i], "-help") == 0) {
  675. printf("Usage:\n");
  676. printf(" gears [options]\n");
  677. printf("Options:\n");
  678. printf(" -help Print this information\n");
  679. printf(" -display displayName Specify X display\n");
  680. printf(" -info Display GL information\n");
  681. printf(" -swap N Swap no more than once per N vertical refreshes\n");
  682. printf(" -forcegetrate Try to use glXGetMscRateOML function\n");
  683. printf(" -fullscreen Full-screen window\n");
  684. return 0;
  685. }
  686. }
  687. dpy = XOpenDisplay(dpyName);
  688. if (!dpy) {
  689. printf("Error: couldn't open display %s\n", XDisplayName(dpyName));
  690. return -1;
  691. }
  692. make_window(dpy, "glxgears", 0, 0, width, height, fullscreen, &win, &ctx);
  693. XMapWindow(dpy, win);
  694. glXMakeCurrent(dpy, win, ctx);
  695. make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) );
  696. has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" );
  697. has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" );
  698. has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" );
  699. has_MESA_swap_frame_usage = is_extension_supported( "GLX_MESA_swap_frame_usage" );
  700. if ( has_MESA_swap_control ) {
  701. set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalMESA" );
  702. get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetSwapIntervalMESA" );
  703. }
  704. else if ( has_SGI_swap_control ) {
  705. set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalSGI" );
  706. }
  707. if ( has_MESA_swap_frame_usage ) {
  708. get_frame_usage = (PFNGLXGETFRAMEUSAGEMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetFrameUsageMESA" );
  709. }
  710. if (printInfo) {
  711. printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
  712. printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
  713. printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
  714. printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
  715. if ( has_OML_sync_control || force_get_rate ) {
  716. show_refresh_rate( dpy );
  717. }
  718. if ( get_swap_interval != NULL ) {
  719. printf("Default swap interval = %d\n", (*get_swap_interval)() );
  720. }
  721. }
  722. if ( do_swap_interval ) {
  723. if ( set_swap_interval != NULL ) {
  724. if ( ((swap_interval == 0) && !has_MESA_swap_control)
  725. || (swap_interval < 0) ) {
  726. printf( "Swap interval must be non-negative or greater than zero "
  727. "if GLX_MESA_swap_control is not supported.\n" );
  728. }
  729. else {
  730. (*set_swap_interval)( swap_interval );
  731. }
  732. if ( printInfo && (get_swap_interval != NULL) ) {
  733. printf("Current swap interval = %d\n", (*get_swap_interval)() );
  734. }
  735. }
  736. else {
  737. printf("Unable to set swap-interval. Neither GLX_SGI_swap_control "
  738. "nor GLX_MESA_swap_control are supported.\n" );
  739. }
  740. }
  741. init();
  742. /* Set initial projection/viewing transformation.
  743. * same as glxgears.c
  744. */
  745. reshape(width, height);
  746. event_loop(dpy, win);
  747. glXDestroyContext(dpy, ctx);
  748. XDestroyWindow(dpy, win);
  749. XCloseDisplay(dpy);
  750. return 0;
  751. }