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 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  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 aspect;
  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. glEnable( GL_VERTEX_ARRAY );
  258. glEnable( GL_COLOR_ARRAY );
  259. glVertexPointer( 3, GL_FLOAT, 0, vert );
  260. glColorPointer( 3, GL_FLOAT, 0, col );
  261. glDrawArrays( GL_POLYGON, 0, 4 );
  262. glDisable( GL_COLOR_ARRAY );
  263. glDisable( GL_VERTEX_ARRAY );
  264. glMatrixMode(GL_PROJECTION);
  265. glLoadIdentity();
  266. glFrustum(-1.0, 1.0, -aspect, aspect, 5.0, 60.0);
  267. glEnable(GL_LIGHTING);
  268. glMatrixMode(GL_MODELVIEW);
  269. glLoadIdentity();
  270. glTranslatef(0.0, 0.0, -40.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. aspect = (GLfloat) height / (GLfloat) width;
  301. glViewport(0, 0, (GLint) width, (GLint) height);
  302. glMatrixMode(GL_PROJECTION);
  303. glLoadIdentity();
  304. glFrustum(-1.0, 1.0, -aspect, aspect, 5.0, 60.0);
  305. glMatrixMode(GL_MODELVIEW);
  306. glLoadIdentity();
  307. glTranslatef(0.0, 0.0, -40.0);
  308. }
  309. static void
  310. init(void)
  311. {
  312. static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
  313. static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
  314. static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
  315. static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
  316. glLightfv(GL_LIGHT0, GL_POSITION, pos);
  317. glEnable(GL_CULL_FACE);
  318. glEnable(GL_LIGHTING);
  319. glEnable(GL_LIGHT0);
  320. glEnable(GL_DEPTH_TEST);
  321. /* make the gears */
  322. gear1 = glGenLists(1);
  323. glNewList(gear1, GL_COMPILE);
  324. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
  325. gear(1.0, 4.0, 1.0, 20, 0.7);
  326. glEndList();
  327. gear2 = glGenLists(1);
  328. glNewList(gear2, GL_COMPILE);
  329. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
  330. gear(0.5, 2.0, 2.0, 10, 0.7);
  331. glEndList();
  332. gear3 = glGenLists(1);
  333. glNewList(gear3, GL_COMPILE);
  334. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
  335. gear(1.3, 2.0, 0.5, 10, 0.7);
  336. glEndList();
  337. glEnable(GL_NORMALIZE);
  338. }
  339. /*
  340. * Create an RGB, double-buffered window.
  341. * Return the window and context handles.
  342. */
  343. static void
  344. make_window( Display *dpy, const char *name,
  345. int x, int y, int width, int height,
  346. Window *winRet, GLXContext *ctxRet)
  347. {
  348. int attrib[] = { GLX_RGBA,
  349. GLX_RED_SIZE, 1,
  350. GLX_GREEN_SIZE, 1,
  351. GLX_BLUE_SIZE, 1,
  352. GLX_DOUBLEBUFFER,
  353. GLX_DEPTH_SIZE, 1,
  354. None };
  355. int scrnum;
  356. XSetWindowAttributes attr;
  357. unsigned long mask;
  358. Window root;
  359. Window win;
  360. GLXContext ctx;
  361. XVisualInfo *visinfo;
  362. scrnum = DefaultScreen( dpy );
  363. root = RootWindow( dpy, scrnum );
  364. visinfo = glXChooseVisual( dpy, scrnum, attrib );
  365. if (!visinfo) {
  366. printf("Error: couldn't get an RGB, Double-buffered visual\n");
  367. exit(1);
  368. }
  369. /* window attributes */
  370. attr.background_pixel = 0;
  371. attr.border_pixel = 0;
  372. attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
  373. attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
  374. mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
  375. win = XCreateWindow( dpy, root, 0, 0, width, height,
  376. 0, visinfo->depth, InputOutput,
  377. visinfo->visual, mask, &attr );
  378. /* set hints and properties */
  379. {
  380. XSizeHints sizehints;
  381. sizehints.x = x;
  382. sizehints.y = y;
  383. sizehints.width = width;
  384. sizehints.height = height;
  385. sizehints.flags = USSize | USPosition;
  386. XSetNormalHints(dpy, win, &sizehints);
  387. XSetStandardProperties(dpy, win, name, name,
  388. None, (char **)NULL, 0, &sizehints);
  389. }
  390. ctx = glXCreateContext( dpy, visinfo, NULL, True );
  391. if (!ctx) {
  392. printf("Error: glXCreateContext failed\n");
  393. exit(1);
  394. }
  395. XFree(visinfo);
  396. *winRet = win;
  397. *ctxRet = ctx;
  398. }
  399. static void
  400. event_loop(Display *dpy, Window win)
  401. {
  402. float frame_usage = 0.0;
  403. while (1) {
  404. while (XPending(dpy) > 0) {
  405. XEvent event;
  406. XNextEvent(dpy, &event);
  407. switch (event.type) {
  408. case Expose:
  409. /* we'll redraw below */
  410. break;
  411. case ConfigureNotify:
  412. reshape(event.xconfigure.width, event.xconfigure.height);
  413. break;
  414. case KeyPress:
  415. {
  416. char buffer[10];
  417. int r, code;
  418. code = XLookupKeysym(&event.xkey, 0);
  419. if (code == XK_Left) {
  420. view_roty += 5.0;
  421. }
  422. else if (code == XK_Right) {
  423. view_roty -= 5.0;
  424. }
  425. else if (code == XK_Up) {
  426. view_rotx += 5.0;
  427. }
  428. else if (code == XK_Down) {
  429. view_rotx -= 5.0;
  430. }
  431. else {
  432. r = XLookupString(&event.xkey, buffer, sizeof(buffer),
  433. NULL, NULL);
  434. if (buffer[0] == 27) {
  435. /* escape */
  436. return;
  437. }
  438. }
  439. }
  440. }
  441. }
  442. /* next frame */
  443. angle += 2.0;
  444. draw();
  445. if ( get_frame_usage != NULL ) {
  446. GLfloat temp;
  447. (*get_frame_usage)( dpy, win, & temp );
  448. frame_usage += temp;
  449. }
  450. glXSwapBuffers(dpy, win);
  451. /* calc framerate */
  452. {
  453. static int t0 = -1;
  454. static int frames = 0;
  455. int t = current_time();
  456. if (t0 < 0)
  457. t0 = t;
  458. frames++;
  459. if (t - t0 >= 5.0) {
  460. GLfloat seconds = t - t0;
  461. GLfloat fps = frames / seconds;
  462. if ( get_frame_usage != NULL ) {
  463. printf("%d frames in %3.1f seconds = %6.3f FPS (%3.1f%% usage)\n",
  464. frames, seconds, fps,
  465. (frame_usage * 100.0) / (float) frames );
  466. }
  467. else {
  468. printf("%d frames in %3.1f seconds = %6.3f FPS\n",
  469. frames, seconds, fps);
  470. }
  471. t0 = t;
  472. frames = 0;
  473. frame_usage = 0.0;
  474. }
  475. }
  476. }
  477. }
  478. /**
  479. * Display the refresh rate of the display using the GLX_OML_sync_control
  480. * extension.
  481. */
  482. static void
  483. show_refresh_rate( Display * dpy )
  484. {
  485. #if defined(GLX_OML_sync_control) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
  486. PFNGLXGETMSCRATEOMLPROC get_msc_rate;
  487. int32_t n;
  488. int32_t d;
  489. get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetMscRateOML" );
  490. if ( get_msc_rate != NULL ) {
  491. (*get_msc_rate)( dpy, glXGetCurrentDrawable(), &n, &d );
  492. printf( "refresh rate: %.1fHz\n", (float) n / d );
  493. return;
  494. }
  495. #endif
  496. printf( "glXGetMscRateOML not supported.\n" );
  497. }
  498. /**
  499. * Fill in the table of extension strings from a supplied extensions string
  500. * (as returned by glXQueryExtensionsString).
  501. *
  502. * \param string String of GLX extensions.
  503. * \sa is_extension_supported
  504. */
  505. static void
  506. make_extension_table( const char * string )
  507. {
  508. char ** string_tab;
  509. unsigned num_strings;
  510. unsigned base;
  511. unsigned idx;
  512. unsigned i;
  513. /* Count the number of spaces in the string. That gives a base-line
  514. * figure for the number of extension in the string.
  515. */
  516. num_strings = 1;
  517. for ( i = 0 ; string[i] != NUL ; i++ ) {
  518. if ( string[i] == ' ' ) {
  519. num_strings++;
  520. }
  521. }
  522. string_tab = (char **) malloc( sizeof( char * ) * num_strings );
  523. if ( string_tab == NULL ) {
  524. return;
  525. }
  526. base = 0;
  527. idx = 0;
  528. while ( string[ base ] != NUL ) {
  529. /* Determine the length of the next extension string.
  530. */
  531. for ( i = 0
  532. ; (string[ base + i ] != NUL) && (string[ base + i ] != ' ')
  533. ; i++ ) {
  534. /* empty */ ;
  535. }
  536. if ( i > 0 ) {
  537. /* If the string was non-zero length, add it to the table. We
  538. * can get zero length strings if there is a space at the end of
  539. * the string or if there are two (or more) spaces next to each
  540. * other in the string.
  541. */
  542. string_tab[ idx ] = malloc( sizeof( char ) * (i + 1) );
  543. if ( string_tab[ idx ] == NULL ) {
  544. return;
  545. }
  546. (void) memcpy( string_tab[ idx ], & string[ base ], i );
  547. string_tab[ idx ][i] = NUL;
  548. idx++;
  549. }
  550. /* Skip to the start of the next extension string.
  551. */
  552. for ( base += i
  553. ; (string[ base ] == ' ') && (string[ base ] != NUL)
  554. ; base++ ) {
  555. /* empty */ ;
  556. }
  557. }
  558. extension_table = string_tab;
  559. num_extensions = idx;
  560. }
  561. /**
  562. * Determine of an extension is supported. The extension string table
  563. * must have already be initialized by calling \c make_extension_table.
  564. *
  565. * \praram ext Extension to be tested.
  566. * \return GL_TRUE of the extension is supported, GL_FALSE otherwise.
  567. * \sa make_extension_table
  568. */
  569. static GLboolean
  570. is_extension_supported( const char * ext )
  571. {
  572. unsigned i;
  573. for ( i = 0 ; i < num_extensions ; i++ ) {
  574. if ( strcmp( ext, extension_table[i] ) == 0 ) {
  575. return GL_TRUE;
  576. }
  577. }
  578. return GL_FALSE;
  579. }
  580. int
  581. main(int argc, char *argv[])
  582. {
  583. Display *dpy;
  584. Window win;
  585. GLXContext ctx;
  586. char *dpyName = ":0";
  587. int swap_interval = 1;
  588. GLboolean do_swap_interval = GL_FALSE;
  589. GLboolean force_get_rate = GL_FALSE;
  590. GLboolean printInfo = GL_FALSE;
  591. int i;
  592. PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL;
  593. PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL;
  594. for (i = 1; i < argc; i++) {
  595. if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
  596. dpyName = argv[i+1];
  597. i++;
  598. }
  599. else if (strcmp(argv[i], "-info") == 0) {
  600. printInfo = GL_TRUE;
  601. }
  602. else if (strcmp(argv[i], "-swap") == 0 && i + 1 < argc) {
  603. swap_interval = atoi( argv[i+1] );
  604. do_swap_interval = GL_TRUE;
  605. i++;
  606. }
  607. else if (strcmp(argv[i], "-forcegetrate") == 0) {
  608. /* This option was put in because some DRI drivers don't support the
  609. * full GLX_OML_sync_control extension, but they do support
  610. * glXGetMscRateOML.
  611. */
  612. force_get_rate = GL_TRUE;
  613. }
  614. else if (strcmp(argv[i], "-ztrick") == 0) {
  615. use_ztrick = GL_TRUE;
  616. }
  617. else if (strcmp(argv[i], "-help") == 0) {
  618. printf("Usage:\n");
  619. printf(" gears [options]\n");
  620. printf("Options:\n");
  621. printf(" -help Print this information\n");
  622. printf(" -display displayName Specify X display\n");
  623. printf(" -info Display GL information\n");
  624. printf(" -swap N Swap no more than once per N vertical refreshes\n");
  625. printf(" -forcegetrate Try to use glXGetMscRateOML function\n");
  626. return 0;
  627. }
  628. }
  629. dpy = XOpenDisplay(dpyName);
  630. if (!dpy) {
  631. printf("Error: couldn't open display %s\n", dpyName);
  632. return -1;
  633. }
  634. make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &ctx);
  635. XMapWindow(dpy, win);
  636. glXMakeCurrent(dpy, win, ctx);
  637. make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) );
  638. has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" );
  639. has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" );
  640. has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" );
  641. has_MESA_swap_frame_usage = is_extension_supported( "GLX_MESA_swap_frame_usage" );
  642. if ( has_MESA_swap_control ) {
  643. set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalMESA" );
  644. get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetSwapIntervalMESA" );
  645. }
  646. else if ( has_SGI_swap_control ) {
  647. set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalSGI" );
  648. }
  649. if ( has_MESA_swap_frame_usage ) {
  650. get_frame_usage = (PFNGLXGETFRAMEUSAGEMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetFrameUsageMESA" );
  651. }
  652. if (printInfo) {
  653. printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
  654. printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
  655. printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
  656. printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
  657. if ( has_OML_sync_control || force_get_rate ) {
  658. show_refresh_rate( dpy );
  659. }
  660. if ( get_swap_interval != NULL ) {
  661. printf("Default swap interval = %d\n", (*get_swap_interval)() );
  662. }
  663. }
  664. if ( do_swap_interval ) {
  665. if ( set_swap_interval != NULL ) {
  666. if ( ((swap_interval == 0) && !has_MESA_swap_control)
  667. || (swap_interval < 0) ) {
  668. printf( "Swap interval must be non-negative or greater than zero "
  669. "if GLX_MESA_swap_control is not supported.\n" );
  670. }
  671. else {
  672. (*set_swap_interval)( swap_interval );
  673. }
  674. if ( printInfo && (get_swap_interval != NULL) ) {
  675. printf("Current swap interval = %d\n", (*get_swap_interval)() );
  676. }
  677. }
  678. else {
  679. printf("Unable to set swap-interval. Neither GLX_SGI_swap_control "
  680. "nor GLX_MESA_swap_control are supported.\n" );
  681. }
  682. }
  683. init();
  684. event_loop(dpy, win);
  685. glXDestroyContext(dpy, ctx);
  686. XDestroyWindow(dpy, win);
  687. XCloseDisplay(dpy);
  688. return 0;
  689. }