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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. /*
  2. * Copyright (C) 1999-2006 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 program is a work-alike of the IRIX glxinfo program.
  23. * Command line options:
  24. * -t print wide table
  25. * -v print verbose information
  26. * -display DisplayName specify the X display to interogate
  27. * -b only print ID of "best" visual on screen 0
  28. * -i use indirect rendering connection only
  29. * -l print interesting OpenGL limits (added 5 Sep 2002)
  30. *
  31. * Brian Paul 26 January 2000
  32. */
  33. #define GLX_GLXEXT_PROTOTYPES
  34. #include <X11/Xlib.h>
  35. #include <X11/Xutil.h>
  36. #include <GL/gl.h>
  37. #include <GL/glx.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <stdlib.h>
  41. #ifndef GLX_NONE_EXT
  42. #define GLX_NONE_EXT 0x8000
  43. #endif
  44. #ifndef GLX_TRANSPARENT_RGB
  45. #define GLX_TRANSPARENT_RGB 0x8008
  46. #endif
  47. typedef enum
  48. {
  49. Normal,
  50. Wide,
  51. Verbose
  52. } InfoMode;
  53. struct visual_attribs
  54. {
  55. /* X visual attribs */
  56. int id;
  57. int klass;
  58. int depth;
  59. int redMask, greenMask, blueMask;
  60. int colormapSize;
  61. int bitsPerRGB;
  62. /* GL visual attribs */
  63. int supportsGL;
  64. int transparentType;
  65. int transparentRedValue;
  66. int transparentGreenValue;
  67. int transparentBlueValue;
  68. int transparentAlphaValue;
  69. int transparentIndexValue;
  70. int bufferSize;
  71. int level;
  72. int rgba;
  73. int doubleBuffer;
  74. int stereo;
  75. int auxBuffers;
  76. int redSize, greenSize, blueSize, alphaSize;
  77. int depthSize;
  78. int stencilSize;
  79. int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
  80. int numSamples, numMultisample;
  81. int visualCaveat;
  82. };
  83. /*
  84. * Print a list of extensions, with word-wrapping.
  85. */
  86. static void
  87. print_extension_list(const char *ext)
  88. {
  89. const char *indentString = " ";
  90. const int indent = 4;
  91. const int max = 79;
  92. int width, i, j;
  93. if (!ext || !ext[0])
  94. return;
  95. width = indent;
  96. printf(indentString);
  97. i = j = 0;
  98. while (1) {
  99. if (ext[j] == ' ' || ext[j] == 0) {
  100. /* found end of an extension name */
  101. const int len = j - i;
  102. if (width + len > max) {
  103. /* start a new line */
  104. printf("\n");
  105. width = indent;
  106. printf(indentString);
  107. }
  108. /* print the extension name between ext[i] and ext[j] */
  109. while (i < j) {
  110. printf("%c", ext[i]);
  111. i++;
  112. }
  113. /* either we're all done, or we'll continue with next extension */
  114. width += len + 1;
  115. if (ext[j] == 0) {
  116. break;
  117. }
  118. else {
  119. i++;
  120. j++;
  121. if (ext[j] == 0)
  122. break;
  123. printf(", ");
  124. width += 2;
  125. }
  126. }
  127. j++;
  128. }
  129. printf("\n");
  130. }
  131. static void
  132. print_display_info(Display *dpy)
  133. {
  134. printf("name of display: %s\n", DisplayString(dpy));
  135. }
  136. /**
  137. * Print interesting limits for vertex/fragment programs.
  138. */
  139. static void
  140. print_program_limits(GLenum target)
  141. {
  142. #if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program)
  143. struct token_name {
  144. GLenum token;
  145. const char *name;
  146. };
  147. static const struct token_name limits[] = {
  148. { GL_MAX_PROGRAM_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_INSTRUCTIONS_ARB" },
  149. { GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB" },
  150. { GL_MAX_PROGRAM_TEMPORARIES_ARB, "GL_MAX_PROGRAM_TEMPORARIES_ARB" },
  151. { GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB" },
  152. { GL_MAX_PROGRAM_PARAMETERS_ARB, "GL_MAX_PROGRAM_PARAMETERS_ARB" },
  153. { GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB" },
  154. { GL_MAX_PROGRAM_ATTRIBS_ARB, "GL_MAX_PROGRAM_ATTRIBS_ARB" },
  155. { GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB" },
  156. { GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB" },
  157. { GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" },
  158. { GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB" },
  159. { GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB" },
  160. { GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB" },
  161. { GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB" },
  162. { GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB" },
  163. { GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" },
  164. { GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" },
  165. { GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" },
  166. { (GLenum) 0, NULL }
  167. };
  168. PFNGLGETPROGRAMIVARBPROC GetProgramivARB_func = (PFNGLGETPROGRAMIVARBPROC)
  169. glXGetProcAddressARB((GLubyte *) "glGetProgramivARB");
  170. GLint max[1];
  171. int i;
  172. if (target == GL_VERTEX_PROGRAM_ARB) {
  173. printf(" GL_VERTEX_PROGRAM_ARB:\n");
  174. }
  175. else if (target == GL_FRAGMENT_PROGRAM_ARB) {
  176. printf(" GL_FRAGMENT_PROGRAM_ARB:\n");
  177. }
  178. else {
  179. return; /* something's wrong */
  180. }
  181. for (i = 0; limits[i].token; i++) {
  182. GetProgramivARB_func(target, limits[i].token, max);
  183. if (glGetError() == GL_NO_ERROR) {
  184. printf(" %s = %d\n", limits[i].name, max[0]);
  185. }
  186. }
  187. #endif /* GL_ARB_vertex_program / GL_ARB_fragment_program */
  188. }
  189. /**
  190. * Print interesting limits for vertex/fragment shaders.
  191. */
  192. static void
  193. print_shader_limits(GLenum target)
  194. {
  195. struct token_name {
  196. GLenum token;
  197. const char *name;
  198. };
  199. #if defined(GL_ARB_vertex_shader)
  200. static const struct token_name vertex_limits[] = {
  201. { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB" },
  202. { GL_MAX_VARYING_FLOATS_ARB, "GL_MAX_VARYING_FLOATS_ARB" },
  203. { GL_MAX_VERTEX_ATTRIBS_ARB, "GL_MAX_VERTEX_ATTRIBS_ARB" },
  204. { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
  205. { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB" },
  206. { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB" },
  207. { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" },
  208. { (GLenum) 0, NULL }
  209. };
  210. #endif
  211. #if defined(GL_ARB_fragment_shader)
  212. static const struct token_name fragment_limits[] = {
  213. { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB" },
  214. { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" },
  215. { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
  216. { (GLenum) 0, NULL }
  217. };
  218. #endif
  219. GLint max[1];
  220. int i;
  221. #if defined(GL_ARB_vertex_shader)
  222. if (target == GL_VERTEX_SHADER_ARB) {
  223. printf(" GL_VERTEX_SHADER_ARB:\n");
  224. for (i = 0; vertex_limits[i].token; i++) {
  225. glGetIntegerv(vertex_limits[i].token, max);
  226. if (glGetError() == GL_NO_ERROR) {
  227. printf(" %s = %d\n", vertex_limits[i].name, max[0]);
  228. }
  229. }
  230. }
  231. #endif
  232. #if defined(GL_ARB_fragment_shader)
  233. if (target == GL_FRAGMENT_SHADER_ARB) {
  234. printf(" GL_FRAGMENT_SHADER_ARB:\n");
  235. for (i = 0; fragment_limits[i].token; i++) {
  236. glGetIntegerv(fragment_limits[i].token, max);
  237. if (glGetError() == GL_NO_ERROR) {
  238. printf(" %s = %d\n", fragment_limits[i].name, max[0]);
  239. }
  240. }
  241. }
  242. #endif
  243. }
  244. /**
  245. * Print interesting OpenGL implementation limits.
  246. */
  247. static void
  248. print_limits(const char *extensions)
  249. {
  250. struct token_name {
  251. GLuint count;
  252. GLenum token;
  253. const char *name;
  254. };
  255. static const struct token_name limits[] = {
  256. { 1, GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH" },
  257. { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH" },
  258. { 1, GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES" },
  259. { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "GL_MAX_COLOR_MATRIX_STACK_DEPTH" },
  260. { 1, GL_MAX_ELEMENTS_VERTICES, "GL_MAX_ELEMENTS_VERTICES" },
  261. { 1, GL_MAX_ELEMENTS_INDICES, "GL_MAX_ELEMENTS_INDICES" },
  262. { 1, GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER" },
  263. { 1, GL_MAX_LIGHTS, "GL_MAX_LIGHTS" },
  264. { 1, GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING" },
  265. { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH" },
  266. { 1, GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH" },
  267. { 1, GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE" },
  268. { 1, GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH" },
  269. { 1, GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH" },
  270. { 1, GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE" },
  271. { 1, GL_MAX_3D_TEXTURE_SIZE, "GL_MAX_3D_TEXTURE_SIZE" },
  272. { 2, GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS" },
  273. { 2, GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE" },
  274. { 2, GL_SMOOTH_LINE_WIDTH_RANGE, "GL_SMOOTH_LINE_WIDTH_RANGE" },
  275. { 2, GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE" },
  276. { 2, GL_SMOOTH_POINT_SIZE_RANGE, "GL_SMOOTH_POINT_SIZE_RANGE" },
  277. #if defined(GL_ARB_texture_cube_map)
  278. { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB" },
  279. #endif
  280. #if defined(GLX_NV_texture_rectangle)
  281. { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV" },
  282. #endif
  283. #if defined(GL_ARB_texture_compression)
  284. { 1, GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, "GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB" },
  285. #endif
  286. #if defined(GL_ARB_multitexture)
  287. { 1, GL_MAX_TEXTURE_UNITS_ARB, "GL_MAX_TEXTURE_UNITS_ARB" },
  288. #endif
  289. #if defined(GL_EXT_texture_lod_bias)
  290. { 1, GL_MAX_TEXTURE_LOD_BIAS_EXT, "GL_MAX_TEXTURE_LOD_BIAS_EXT" },
  291. #endif
  292. #if defined(GL_EXT_texture_filter_anisotropic)
  293. { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" },
  294. #endif
  295. #if defined(GL_ARB_draw_buffers)
  296. { 1, GL_MAX_DRAW_BUFFERS_ARB, "GL_MAX_DRAW_BUFFERS_ARB" },
  297. #endif
  298. { 0, (GLenum) 0, NULL }
  299. };
  300. GLint i, max[2];
  301. printf("OpenGL limits:\n");
  302. for (i = 0; limits[i].count; i++) {
  303. glGetIntegerv(limits[i].token, max);
  304. if (glGetError() == GL_NO_ERROR) {
  305. if (limits[i].count == 1)
  306. printf(" %s = %d\n", limits[i].name, max[0]);
  307. else /* XXX fix if we ever query something with more than 2 values */
  308. printf(" %s = %d, %d\n", limits[i].name, max[0], max[1]);
  309. }
  310. }
  311. /* these don't fit into the above mechanism, unfortunately */
  312. glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_WIDTH, max);
  313. glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_HEIGHT, max+1);
  314. if (glGetError() == GL_NONE) {
  315. printf(" GL_MAX_CONVOLUTION_WIDTH/HEIGHT = %d, %d\n", max[0], max[1]);
  316. }
  317. #if defined(GL_ARB_vertex_program)
  318. if (strstr(extensions, "GL_ARB_vertex_program")) {
  319. print_program_limits(GL_VERTEX_PROGRAM_ARB);
  320. }
  321. #endif
  322. #if defined(GL_ARB_fragment_program)
  323. if (strstr(extensions, "GL_ARB_fragment_program")) {
  324. print_program_limits(GL_FRAGMENT_PROGRAM_ARB);
  325. }
  326. #endif
  327. #if defined(GL_ARB_vertex_shader)
  328. if (strstr(extensions, "GL_ARB_vertex_shader")) {
  329. print_shader_limits(GL_VERTEX_SHADER_ARB);
  330. }
  331. #endif
  332. #if defined(GL_ARB_fragment_shader)
  333. if (strstr(extensions, "GL_ARB_fragment_shader")) {
  334. print_shader_limits(GL_FRAGMENT_SHADER_ARB);
  335. }
  336. #endif
  337. }
  338. static void
  339. print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits)
  340. {
  341. Window win;
  342. int attribSingle[] = {
  343. GLX_RGBA,
  344. GLX_RED_SIZE, 1,
  345. GLX_GREEN_SIZE, 1,
  346. GLX_BLUE_SIZE, 1,
  347. None };
  348. int attribDouble[] = {
  349. GLX_RGBA,
  350. GLX_RED_SIZE, 1,
  351. GLX_GREEN_SIZE, 1,
  352. GLX_BLUE_SIZE, 1,
  353. GLX_DOUBLEBUFFER,
  354. None };
  355. XSetWindowAttributes attr;
  356. unsigned long mask;
  357. Window root;
  358. GLXContext ctx;
  359. XVisualInfo *visinfo;
  360. int width = 100, height = 100;
  361. root = RootWindow(dpy, scrnum);
  362. visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
  363. if (!visinfo) {
  364. visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
  365. if (!visinfo) {
  366. fprintf(stderr, "Error: couldn't find RGB GLX visual\n");
  367. return;
  368. }
  369. }
  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;
  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. ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
  379. if (!ctx) {
  380. fprintf(stderr, "Error: glXCreateContext failed\n");
  381. XFree(visinfo);
  382. XDestroyWindow(dpy, win);
  383. return;
  384. }
  385. if (glXMakeCurrent(dpy, win, ctx)) {
  386. const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
  387. const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
  388. const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
  389. const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
  390. const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
  391. const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
  392. const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
  393. const char *glVendor = (const char *) glGetString(GL_VENDOR);
  394. const char *glRenderer = (const char *) glGetString(GL_RENDERER);
  395. const char *glVersion = (const char *) glGetString(GL_VERSION);
  396. const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
  397. int glxVersionMajor;
  398. int glxVersionMinor;
  399. char *displayName = NULL;
  400. char *colon = NULL, *period = NULL;
  401. if (! glXQueryVersion( dpy, & glxVersionMajor, & glxVersionMinor )) {
  402. fprintf(stderr, "Error: glXQueryVersion failed\n");
  403. exit(1);
  404. }
  405. /* Strip the screen number from the display name, if present. */
  406. if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
  407. fprintf(stderr, "Error: malloc() failed\n");
  408. exit(1);
  409. }
  410. strcpy(displayName, DisplayString(dpy));
  411. colon = strrchr(displayName, ':');
  412. if (colon) {
  413. period = strchr(colon, '.');
  414. if (period)
  415. *period = '\0';
  416. }
  417. printf("display: %s screen: %d\n", displayName, scrnum);
  418. free(displayName);
  419. printf("direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
  420. printf("server glx vendor string: %s\n", serverVendor);
  421. printf("server glx version string: %s\n", serverVersion);
  422. printf("server glx extensions:\n");
  423. print_extension_list(serverExtensions);
  424. printf("client glx vendor string: %s\n", clientVendor);
  425. printf("client glx version string: %s\n", clientVersion);
  426. printf("client glx extensions:\n");
  427. print_extension_list(clientExtensions);
  428. printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor);
  429. printf("GLX extensions:\n");
  430. print_extension_list(glxExtensions);
  431. printf("OpenGL vendor string: %s\n", glVendor);
  432. printf("OpenGL renderer string: %s\n", glRenderer);
  433. printf("OpenGL version string: %s\n", glVersion);
  434. printf("OpenGL extensions:\n");
  435. print_extension_list(glExtensions);
  436. if (limits)
  437. print_limits(glExtensions);
  438. }
  439. else {
  440. fprintf(stderr, "Error: glXMakeCurrent failed\n");
  441. }
  442. glXDestroyContext(dpy, ctx);
  443. XFree(visinfo);
  444. XDestroyWindow(dpy, win);
  445. }
  446. static const char *
  447. visual_class_name(int cls)
  448. {
  449. switch (cls) {
  450. case StaticColor:
  451. return "StaticColor";
  452. case PseudoColor:
  453. return "PseudoColor";
  454. case StaticGray:
  455. return "StaticGray";
  456. case GrayScale:
  457. return "GrayScale";
  458. case TrueColor:
  459. return "TrueColor";
  460. case DirectColor:
  461. return "DirectColor";
  462. default:
  463. return "";
  464. }
  465. }
  466. static const char *
  467. visual_class_abbrev(int cls)
  468. {
  469. switch (cls) {
  470. case StaticColor:
  471. return "sc";
  472. case PseudoColor:
  473. return "pc";
  474. case StaticGray:
  475. return "sg";
  476. case GrayScale:
  477. return "gs";
  478. case TrueColor:
  479. return "tc";
  480. case DirectColor:
  481. return "dc";
  482. default:
  483. return "";
  484. }
  485. }
  486. static void
  487. get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
  488. struct visual_attribs *attribs)
  489. {
  490. const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
  491. memset(attribs, 0, sizeof(struct visual_attribs));
  492. attribs->id = vInfo->visualid;
  493. #if defined(__cplusplus) || defined(c_plusplus)
  494. attribs->klass = vInfo->c_class;
  495. #else
  496. attribs->klass = vInfo->class;
  497. #endif
  498. attribs->depth = vInfo->depth;
  499. attribs->redMask = vInfo->red_mask;
  500. attribs->greenMask = vInfo->green_mask;
  501. attribs->blueMask = vInfo->blue_mask;
  502. attribs->colormapSize = vInfo->colormap_size;
  503. attribs->bitsPerRGB = vInfo->bits_per_rgb;
  504. if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0)
  505. return;
  506. glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
  507. glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
  508. glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba);
  509. glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
  510. glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
  511. glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
  512. glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
  513. glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
  514. glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
  515. glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
  516. glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
  517. glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
  518. glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
  519. glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
  520. glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
  521. glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
  522. /* get transparent pixel stuff */
  523. glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
  524. if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
  525. glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
  526. glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
  527. glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
  528. glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
  529. }
  530. else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
  531. glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
  532. }
  533. /* multisample attribs */
  534. #ifdef GLX_ARB_multisample
  535. if (ext && strstr(ext, "GLX_ARB_multisample") == 0) {
  536. glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
  537. glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
  538. }
  539. #endif
  540. else {
  541. attribs->numSamples = 0;
  542. attribs->numMultisample = 0;
  543. }
  544. #if defined(GLX_EXT_visual_rating)
  545. if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
  546. glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
  547. }
  548. else {
  549. attribs->visualCaveat = GLX_NONE_EXT;
  550. }
  551. #else
  552. attribs->visualCaveat = 0;
  553. #endif
  554. }
  555. static void
  556. print_visual_attribs_verbose(const struct visual_attribs *attribs)
  557. {
  558. printf("Visual ID: %x depth=%d class=%s\n",
  559. attribs->id, attribs->depth, visual_class_name(attribs->klass));
  560. printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
  561. attribs->bufferSize, attribs->level, attribs->rgba ? "rgba" : "ci",
  562. attribs->doubleBuffer, attribs->stereo);
  563. printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
  564. attribs->redSize, attribs->greenSize,
  565. attribs->blueSize, attribs->alphaSize);
  566. printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n",
  567. attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
  568. printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
  569. attribs->accumRedSize, attribs->accumGreenSize,
  570. attribs->accumBlueSize, attribs->accumAlphaSize);
  571. printf(" multiSample=%d multiSampleBuffers=%d\n",
  572. attribs->numSamples, attribs->numMultisample);
  573. #ifdef GLX_EXT_visual_rating
  574. if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
  575. printf(" visualCaveat=None\n");
  576. else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
  577. printf(" visualCaveat=Slow\n");
  578. else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
  579. printf(" visualCaveat=Nonconformant\n");
  580. #endif
  581. if (attribs->transparentType == GLX_NONE) {
  582. printf(" Opaque.\n");
  583. }
  584. else if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
  585. printf(" Transparent RGB: Red=%d Green=%d Blue=%d Alpha=%d\n",attribs->transparentRedValue,attribs->transparentGreenValue,attribs->transparentBlueValue,attribs->transparentAlphaValue);
  586. }
  587. else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
  588. printf(" Transparent index=%d\n",attribs->transparentIndexValue);
  589. }
  590. }
  591. static void
  592. print_visual_attribs_short_header(void)
  593. {
  594. printf(" visual x bf lv rg d st colorbuffer ax dp st accumbuffer ms cav\n");
  595. printf(" id dep cl sp sz l ci b ro r g b a bf th cl r g b a ns b eat\n");
  596. printf("----------------------------------------------------------------------\n");
  597. }
  598. static void
  599. print_visual_attribs_short(const struct visual_attribs *attribs)
  600. {
  601. char *caveat = NULL;
  602. #ifdef GLX_EXT_visual_rating
  603. if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
  604. caveat = "None";
  605. else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
  606. caveat = "Slow";
  607. else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
  608. caveat = "Ncon";
  609. else
  610. caveat = "None";
  611. #else
  612. caveat = "None";
  613. #endif
  614. printf("0x%2x %2d %2s %2d %2d %2d %1s %2s %2s %2d %2d %2d %2d %2d %2d %2d",
  615. attribs->id,
  616. attribs->depth,
  617. visual_class_abbrev(attribs->klass),
  618. attribs->transparentType != GLX_NONE,
  619. attribs->bufferSize,
  620. attribs->level,
  621. attribs->rgba ? "r" : "c",
  622. attribs->doubleBuffer ? "y" : ".",
  623. attribs->stereo ? "y" : ".",
  624. attribs->redSize, attribs->greenSize,
  625. attribs->blueSize, attribs->alphaSize,
  626. attribs->auxBuffers,
  627. attribs->depthSize,
  628. attribs->stencilSize
  629. );
  630. printf(" %2d %2d %2d %2d %2d %1d %s\n",
  631. attribs->accumRedSize, attribs->accumGreenSize,
  632. attribs->accumBlueSize, attribs->accumAlphaSize,
  633. attribs->numSamples, attribs->numMultisample,
  634. caveat
  635. );
  636. }
  637. static void
  638. print_visual_attribs_long_header(void)
  639. {
  640. printf("Vis Vis Visual Trans buff lev render DB ste r g b a aux dep ste accum buffers MS MS\n");
  641. printf(" ID Depth Type parent size el type reo sz sz sz sz buf th ncl r g b a num bufs\n");
  642. printf("----------------------------------------------------------------------------------------------------\n");
  643. }
  644. static void
  645. print_visual_attribs_long(const struct visual_attribs *attribs)
  646. {
  647. printf("0x%2x %2d %-11s %2d %2d %2d %4s %3d %3d %3d %3d %3d %3d",
  648. attribs->id,
  649. attribs->depth,
  650. visual_class_name(attribs->klass),
  651. attribs->transparentType != GLX_NONE,
  652. attribs->bufferSize,
  653. attribs->level,
  654. attribs->rgba ? "rgba" : "ci ",
  655. attribs->doubleBuffer,
  656. attribs->stereo,
  657. attribs->redSize, attribs->greenSize,
  658. attribs->blueSize, attribs->alphaSize
  659. );
  660. printf(" %3d %4d %2d %3d %3d %3d %3d %2d %2d\n",
  661. attribs->auxBuffers,
  662. attribs->depthSize,
  663. attribs->stencilSize,
  664. attribs->accumRedSize, attribs->accumGreenSize,
  665. attribs->accumBlueSize, attribs->accumAlphaSize,
  666. attribs->numSamples, attribs->numMultisample
  667. );
  668. }
  669. static void
  670. print_visual_info(Display *dpy, int scrnum, InfoMode mode)
  671. {
  672. XVisualInfo theTemplate;
  673. XVisualInfo *visuals;
  674. int numVisuals;
  675. long mask;
  676. int i;
  677. /* get list of all visuals on this screen */
  678. theTemplate.screen = scrnum;
  679. mask = VisualScreenMask;
  680. visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
  681. if (mode == Verbose) {
  682. for (i = 0; i < numVisuals; i++) {
  683. struct visual_attribs attribs;
  684. get_visual_attribs(dpy, &visuals[i], &attribs);
  685. print_visual_attribs_verbose(&attribs);
  686. }
  687. }
  688. else if (mode == Normal) {
  689. print_visual_attribs_short_header();
  690. for (i = 0; i < numVisuals; i++) {
  691. struct visual_attribs attribs;
  692. get_visual_attribs(dpy, &visuals[i], &attribs);
  693. print_visual_attribs_short(&attribs);
  694. }
  695. }
  696. else if (mode == Wide) {
  697. print_visual_attribs_long_header();
  698. for (i = 0; i < numVisuals; i++) {
  699. struct visual_attribs attribs;
  700. get_visual_attribs(dpy, &visuals[i], &attribs);
  701. print_visual_attribs_long(&attribs);
  702. }
  703. }
  704. XFree(visuals);
  705. }
  706. /*
  707. * Stand-alone Mesa doesn't really implement the GLX protocol so it
  708. * doesn't really know the GLX attributes associated with an X visual.
  709. * The first time a visual is presented to Mesa's pseudo-GLX it
  710. * attaches ancilliary buffers to it (like depth and stencil).
  711. * But that usually only works if glXChooseVisual is used.
  712. * This function calls glXChooseVisual() to sort of "prime the pump"
  713. * for Mesa's GLX so that the visuals that get reported actually
  714. * reflect what applications will see.
  715. * This has no effect when using true GLX.
  716. */
  717. static void
  718. mesa_hack(Display *dpy, int scrnum)
  719. {
  720. static int attribs[] = {
  721. GLX_RGBA,
  722. GLX_RED_SIZE, 1,
  723. GLX_GREEN_SIZE, 1,
  724. GLX_BLUE_SIZE, 1,
  725. GLX_DEPTH_SIZE, 1,
  726. GLX_STENCIL_SIZE, 1,
  727. GLX_ACCUM_RED_SIZE, 1,
  728. GLX_ACCUM_GREEN_SIZE, 1,
  729. GLX_ACCUM_BLUE_SIZE, 1,
  730. GLX_ACCUM_ALPHA_SIZE, 1,
  731. GLX_DOUBLEBUFFER,
  732. None
  733. };
  734. XVisualInfo *visinfo;
  735. visinfo = glXChooseVisual(dpy, scrnum, attribs);
  736. if (visinfo)
  737. XFree(visinfo);
  738. }
  739. /*
  740. * Examine all visuals to find the so-called best one.
  741. * We prefer deepest RGBA buffer with depth, stencil and accum
  742. * that has no caveats.
  743. */
  744. static int
  745. find_best_visual(Display *dpy, int scrnum)
  746. {
  747. XVisualInfo theTemplate;
  748. XVisualInfo *visuals;
  749. int numVisuals;
  750. long mask;
  751. int i;
  752. struct visual_attribs bestVis;
  753. /* get list of all visuals on this screen */
  754. theTemplate.screen = scrnum;
  755. mask = VisualScreenMask;
  756. visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
  757. /* init bestVis with first visual info */
  758. get_visual_attribs(dpy, &visuals[0], &bestVis);
  759. /* try to find a "better" visual */
  760. for (i = 1; i < numVisuals; i++) {
  761. struct visual_attribs vis;
  762. get_visual_attribs(dpy, &visuals[i], &vis);
  763. /* always skip visuals with caveats */
  764. if (vis.visualCaveat != GLX_NONE_EXT)
  765. continue;
  766. /* see if this vis is better than bestVis */
  767. if ((!bestVis.supportsGL && vis.supportsGL) ||
  768. (bestVis.visualCaveat != GLX_NONE_EXT) ||
  769. (!bestVis.rgba && vis.rgba) ||
  770. (!bestVis.doubleBuffer && vis.doubleBuffer) ||
  771. (bestVis.redSize < vis.redSize) ||
  772. (bestVis.greenSize < vis.greenSize) ||
  773. (bestVis.blueSize < vis.blueSize) ||
  774. (bestVis.alphaSize < vis.alphaSize) ||
  775. (bestVis.depthSize < vis.depthSize) ||
  776. (bestVis.stencilSize < vis.stencilSize) ||
  777. (bestVis.accumRedSize < vis.accumRedSize)) {
  778. /* found a better visual */
  779. bestVis = vis;
  780. }
  781. }
  782. XFree(visuals);
  783. return bestVis.id;
  784. }
  785. static void
  786. usage(void)
  787. {
  788. printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-display <dname>]\n");
  789. printf("\t-v: Print visuals info in verbose form.\n");
  790. printf("\t-t: Print verbose table.\n");
  791. printf("\t-display <dname>: Print GLX visuals on specified server.\n");
  792. printf("\t-h: This information.\n");
  793. printf("\t-i: Force an indirect rendering context.\n");
  794. printf("\t-b: Find the 'best' visual and print it's number.\n");
  795. printf("\t-l: Print interesting OpenGL limits.\n");
  796. }
  797. int
  798. main(int argc, char *argv[])
  799. {
  800. char *displayName = NULL;
  801. Display *dpy;
  802. int numScreens, scrnum;
  803. InfoMode mode = Normal;
  804. GLboolean findBest = GL_FALSE;
  805. GLboolean limits = GL_FALSE;
  806. Bool allowDirect = True;
  807. int i;
  808. for (i = 1; i < argc; i++) {
  809. if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
  810. displayName = argv[i + 1];
  811. i++;
  812. }
  813. else if (strcmp(argv[i], "-t") == 0) {
  814. mode = Wide;
  815. }
  816. else if (strcmp(argv[i], "-v") == 0) {
  817. mode = Verbose;
  818. }
  819. else if (strcmp(argv[i], "-b") == 0) {
  820. findBest = GL_TRUE;
  821. }
  822. else if (strcmp(argv[i], "-i") == 0) {
  823. allowDirect = False;
  824. }
  825. else if (strcmp(argv[i], "-l") == 0) {
  826. limits = GL_TRUE;
  827. }
  828. else if (strcmp(argv[i], "-h") == 0) {
  829. usage();
  830. return 0;
  831. }
  832. else {
  833. printf("Unknown option `%s'\n", argv[i]);
  834. usage();
  835. return 0;
  836. }
  837. }
  838. dpy = XOpenDisplay(displayName);
  839. if (!dpy) {
  840. fprintf(stderr, "Error: unable to open display %s\n", displayName);
  841. return -1;
  842. }
  843. if (findBest) {
  844. int b;
  845. mesa_hack(dpy, 0);
  846. b = find_best_visual(dpy, 0);
  847. printf("%d\n", b);
  848. }
  849. else {
  850. numScreens = ScreenCount(dpy);
  851. print_display_info(dpy);
  852. for (scrnum = 0; scrnum < numScreens; scrnum++) {
  853. mesa_hack(dpy, scrnum);
  854. print_screen_info(dpy, scrnum, allowDirect, limits);
  855. printf("\n");
  856. print_visual_info(dpy, scrnum, mode);
  857. if (scrnum + 1 < numScreens)
  858. printf("\n\n");
  859. }
  860. }
  861. XCloseDisplay(dpy);
  862. return 0;
  863. }