1/* 2 * Copyright (C) 1999-2014 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#include <assert.h> 23#include <ctype.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include "glinfo_common.h" 28 29#ifdef _WIN32 30#define snprintf _snprintf 31#endif 32 33#ifndef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 34#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 35#endif 36#ifndef GL_CONTEXT_FLAG_DEBUG_BIT 37#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 38#endif 39#ifndef GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 40#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 41#endif 42#ifndef GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 43#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 44#endif 45 46/** 47 * Return the GL enum name for a numeric value. 48 * We really only care about the compressed texture formats for now. 49 */ 50static const char * 51enum_name(GLenum val) 52{ 53 static const struct { 54 const char *name; 55 GLenum val; 56 } enums [] = { 57 { "GL_COMPRESSED_ALPHA", 0x84E9 }, 58 { "GL_COMPRESSED_LUMINANCE", 0x84EA }, 59 { "GL_COMPRESSED_LUMINANCE_ALPHA", 0x84EB }, 60 { "GL_COMPRESSED_INTENSITY", 0x84EC }, 61 { "GL_COMPRESSED_RGB", 0x84ED }, 62 { "GL_COMPRESSED_RGBA", 0x84EE }, 63 { "GL_COMPRESSED_TEXTURE_FORMATS", 0x86A3 }, 64 { "GL_COMPRESSED_RGB", 0x84ED }, 65 { "GL_COMPRESSED_RGBA", 0x84EE }, 66 { "GL_COMPRESSED_TEXTURE_FORMATS", 0x86A3 }, 67 { "GL_COMPRESSED_ALPHA", 0x84E9 }, 68 { "GL_COMPRESSED_LUMINANCE", 0x84EA }, 69 { "GL_COMPRESSED_LUMINANCE_ALPHA", 0x84EB }, 70 { "GL_COMPRESSED_INTENSITY", 0x84EC }, 71 { "GL_COMPRESSED_SRGB", 0x8C48 }, 72 { "GL_COMPRESSED_SRGB_ALPHA", 0x8C49 }, 73 { "GL_COMPRESSED_SLUMINANCE", 0x8C4A }, 74 { "GL_COMPRESSED_SLUMINANCE_ALPHA", 0x8C4B }, 75 { "GL_COMPRESSED_RED", 0x8225 }, 76 { "GL_COMPRESSED_RG", 0x8226 }, 77 { "GL_COMPRESSED_RED_RGTC1", 0x8DBB }, 78 { "GL_COMPRESSED_SIGNED_RED_RGTC1", 0x8DBC }, 79 { "GL_COMPRESSED_RG_RGTC2", 0x8DBD }, 80 { "GL_COMPRESSED_SIGNED_RG_RGTC2", 0x8DBE }, 81 { "GL_COMPRESSED_RGB8_ETC2", 0x9274 }, 82 { "GL_COMPRESSED_SRGB8_ETC2", 0x9275 }, 83 { "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2", 0x9276 }, 84 { "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2", 0x9277 }, 85 { "GL_COMPRESSED_RGBA8_ETC2_EAC", 0x9278 }, 86 { "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC", 0x9279 }, 87 { "GL_COMPRESSED_R11_EAC", 0x9270 }, 88 { "GL_COMPRESSED_SIGNED_R11_EAC", 0x9271 }, 89 { "GL_COMPRESSED_RG11_EAC", 0x9272 }, 90 { "GL_COMPRESSED_SIGNED_RG11_EAC", 0x9273 }, 91 { "GL_COMPRESSED_ALPHA_ARB", 0x84E9 }, 92 { "GL_COMPRESSED_LUMINANCE_ARB", 0x84EA }, 93 { "GL_COMPRESSED_LUMINANCE_ALPHA_ARB", 0x84EB }, 94 { "GL_COMPRESSED_INTENSITY_ARB", 0x84EC }, 95 { "GL_COMPRESSED_RGB_ARB", 0x84ED }, 96 { "GL_COMPRESSED_RGBA_ARB", 0x84EE }, 97 { "GL_COMPRESSED_TEXTURE_FORMATS_ARB", 0x86A3 }, 98 { "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB", 0x8E8C }, 99 { "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB", 0x8E8D }, 100 { "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB", 0x8E8E }, 101 { "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB", 0x8E8F }, 102 { "GL_COMPRESSED_RGBA_ASTC_4x4_KHR", 0x93B0 }, 103 { "GL_COMPRESSED_RGBA_ASTC_5x4_KHR", 0x93B1 }, 104 { "GL_COMPRESSED_RGBA_ASTC_5x5_KHR", 0x93B2 }, 105 { "GL_COMPRESSED_RGBA_ASTC_6x5_KHR", 0x93B3 }, 106 { "GL_COMPRESSED_RGBA_ASTC_6x6_KHR", 0x93B4 }, 107 { "GL_COMPRESSED_RGBA_ASTC_8x5_KHR", 0x93B5 }, 108 { "GL_COMPRESSED_RGBA_ASTC_8x6_KHR", 0x93B6 }, 109 { "GL_COMPRESSED_RGBA_ASTC_8x8_KHR", 0x93B7 }, 110 { "GL_COMPRESSED_RGBA_ASTC_10x5_KHR", 0x93B8 }, 111 { "GL_COMPRESSED_RGBA_ASTC_10x6_KHR", 0x93B9 }, 112 { "GL_COMPRESSED_RGBA_ASTC_10x8_KHR", 0x93BA }, 113 { "GL_COMPRESSED_RGBA_ASTC_10x10_KHR", 0x93BB }, 114 { "GL_COMPRESSED_RGBA_ASTC_12x10_KHR", 0x93BC }, 115 { "GL_COMPRESSED_RGBA_ASTC_12x12_KHR", 0x93BD }, 116 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR", 0x93D0 }, 117 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR", 0x93D1 }, 118 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR", 0x93D2 }, 119 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR", 0x93D3 }, 120 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR", 0x93D4 }, 121 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR", 0x93D5 }, 122 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR", 0x93D6 }, 123 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR", 0x93D7 }, 124 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR", 0x93D8 }, 125 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR", 0x93D9 }, 126 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR", 0x93DA }, 127 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR", 0x93DB }, 128 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR", 0x93DC }, 129 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR", 0x93DD }, 130 { "GL_COMPRESSED_RGB_FXT1_3DFX", 0x86B0 }, 131 { "GL_COMPRESSED_RGBA_FXT1_3DFX", 0x86B1 }, 132 { "GL_COMPRESSED_LUMINANCE_LATC1_EXT", 0x8C70 }, 133 { "GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT", 0x8C71 }, 134 { "GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT", 0x8C72 }, 135 { "GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT", 0x8C73 }, 136 { "GL_COMPRESSED_RED_RGTC1_EXT", 0x8DBB }, 137 { "GL_COMPRESSED_SIGNED_RED_RGTC1_EXT", 0x8DBC }, 138 { "GL_COMPRESSED_RED_GREEN_RGTC2_EXT", 0x8DBD }, 139 { "GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT", 0x8DBE }, 140 { "GL_COMPRESSED_RGB_S3TC_DXT1_EXT", 0x83F0 }, 141 { "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT", 0x83F1 }, 142 { "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT", 0x83F2 }, 143 { "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT", 0x83F3 }, 144 { "GL_COMPRESSED_SRGB_EXT", 0x8C48 }, 145 { "GL_COMPRESSED_SRGB_ALPHA_EXT", 0x8C49 }, 146 { "GL_COMPRESSED_SLUMINANCE_EXT", 0x8C4A }, 147 { "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT", 0x8C4B }, 148 { "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT", 0x8C4C }, 149 { "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT", 0x8C4D }, 150 { "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT", 0x8C4E }, 151 { "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT", 0x8C4F }, 152 { "GL_PALETTE4_RGB8_OES", 0x8B90 }, 153 { "GL_PALETTE4_RGBA8_OES", 0x8B91 }, 154 { "GL_PALETTE4_R5_G6_B5_OES", 0x8B92 }, 155 { "GL_PALETTE4_RGBA4_OES", 0x8B93 }, 156 { "GL_PALETTE4_RGB5_A1_OES", 0x8B94 }, 157 { "GL_PALETTE8_RGB8_OES", 0x8B95 }, 158 { "GL_PALETTE8_RGBA8_OES", 0x8B96 }, 159 { "GL_PALETTE8_R5_G6_B5_OES", 0x8B97 }, 160 { "GL_PALETTE8_RGBA4_OES", 0x8B98 }, 161 { "GL_PALETTE8_RGB5_A1_OES", 0x8B99 } 162 }; 163 const int n = sizeof(enums) / sizeof(enums[0]); 164 static char buffer[100]; 165 int i; 166 for (i = 0; i < n; i++) { 167 if (enums[i].val == val) { 168 return enums[i].name; 169 } 170 } 171 /* enum val not found, just print hexadecimal value into static buffer */ 172 snprintf(buffer, sizeof(buffer), "0x%x", val); 173 return buffer; 174} 175 176 177/* 178 * qsort callback for string comparison. 179 */ 180static int 181compare_string_ptr(const void *p1, const void *p2) 182{ 183 return strcmp(* (char * const *) p1, * (char * const *) p2); 184} 185 186/* 187 * Print a list of extensions, with word-wrapping. 188 */ 189void 190print_extension_list(const char *ext, GLboolean singleLine) 191{ 192 char **extensions; 193 int num_extensions; 194 const char *indentString = " "; 195 const int indent = 4; 196 const int max = 79; 197 int width, i, j, k; 198 199 if (!ext || !ext[0]) 200 return; 201 202 /* count the number of extensions, ignoring successive spaces */ 203 num_extensions = 0; 204 j = 1; 205 do { 206 if ((ext[j] == ' ' || ext[j] == 0) && ext[j - 1] != ' ') { 207 ++num_extensions; 208 } 209 } while(ext[j++]); 210 211 /* copy individual extensions to an array */ 212 extensions = malloc(num_extensions * sizeof *extensions); 213 if (!extensions) { 214 fprintf(stderr, "Error: malloc() failed\n"); 215 exit(1); 216 } 217 i = j = k = 0; 218 while (1) { 219 if (ext[j] == ' ' || ext[j] == 0) { 220 /* found end of an extension name */ 221 const int len = j - i; 222 223 if (len) { 224 assert(k < num_extensions); 225 226 extensions[k] = malloc(len + 1); 227 if (!extensions[k]) { 228 fprintf(stderr, "Error: malloc() failed\n"); 229 exit(1); 230 } 231 232 memcpy(extensions[k], ext + i, len); 233 extensions[k][len] = 0; 234 235 ++k; 236 }; 237 238 i += len + 1; 239 240 if (ext[j] == 0) { 241 break; 242 } 243 } 244 j++; 245 } 246 assert(k == num_extensions); 247 248 /* sort extensions alphabetically */ 249 qsort(extensions, num_extensions, sizeof extensions[0], compare_string_ptr); 250 251 /* print the extensions */ 252 width = indent; 253 printf("%s", indentString); 254 for (k = 0; k < num_extensions; ++k) { 255 const int len = strlen(extensions[k]); 256 if ((!singleLine) && (width + len > max)) { 257 /* start a new line */ 258 printf("\n"); 259 width = indent; 260 printf("%s", indentString); 261 } 262 /* print the extension name */ 263 printf("%s", extensions[k]); 264 265 /* either we're all done, or we'll continue with next extension */ 266 width += len + 1; 267 268 if (singleLine) { 269 printf("\n"); 270 width = indent; 271 printf("%s", indentString); 272 } 273 else if (k < (num_extensions -1)) { 274 printf(", "); 275 width += 2; 276 } 277 } 278 printf("\n"); 279 280 for (k = 0; k < num_extensions; ++k) { 281 free(extensions[k]); 282 } 283 free(extensions); 284} 285 286 287 288 289/** 290 * Get list of OpenGL extensions using core profile's glGetStringi(). 291 */ 292char * 293build_core_profile_extension_list(const struct ext_functions *extfuncs) 294{ 295 GLint i, n, totalLen; 296 char *buffer; 297 298 glGetIntegerv(GL_NUM_EXTENSIONS, &n); 299 300 /* compute totalLen */ 301 totalLen = 0; 302 for (i = 0; i < n; i++) { 303 const char *ext = (const char *) extfuncs->GetStringi(GL_EXTENSIONS, i); 304 if (ext) 305 totalLen += strlen(ext) + 1; /* plus a space */ 306 } 307 308 if (!totalLen) 309 return NULL; 310 311 buffer = malloc(totalLen + 1); 312 if (buffer) { 313 int pos = 0; 314 for (i = 0; i < n; i++) { 315 const char *ext = (const char *) extfuncs->GetStringi(GL_EXTENSIONS, i); 316 strcpy(buffer + pos, ext); 317 pos += strlen(ext); 318 buffer[pos++] = ' '; 319 } 320 buffer[pos] = '\0'; 321 } 322 return buffer; 323} 324 325 326/** Is extension 'ext' supported? */ 327GLboolean 328extension_supported(const char *ext, const char *extensionsList) 329{ 330 while (1) { 331 const char *p = strstr(extensionsList, ext); 332 if (p) { 333 /* check that next char is a space or end of string */ 334 int extLen = strlen(ext); 335 if (p[extLen] == 0 || p[extLen] == ' ') { 336 return 1; 337 } 338 else { 339 /* We found a superset string, keep looking */ 340 extensionsList += extLen; 341 } 342 } 343 else { 344 break; 345 } 346 } 347 return 0; 348} 349 350 351/** 352 * Is verNum >= verString? 353 * \param verString such as "2.1", "3.0", etc. 354 * \param verNum such as 20, 21, 30, 31, 32, etc. 355 */ 356static GLboolean 357version_supported(const char *verString, int verNum) 358{ 359 int v; 360 361 if (!verString || 362 !isdigit(verString[0]) || 363 verString[1] != '.' || 364 !isdigit(verString[2])) { 365 return GL_FALSE; 366 } 367 368 v = (verString[0] - '0') * 10 + (verString[2] - '0'); 369 370 return verNum >= v; 371} 372 373 374struct token_name 375{ 376 GLenum token; 377 const char *name; 378}; 379 380 381static void 382print_shader_limit_list(const struct token_name *lim) 383{ 384 GLint max[1]; 385 unsigned i; 386 387 for (i = 0; lim[i].token; i++) { 388 glGetIntegerv(lim[i].token, max); 389 if (glGetError() == GL_NO_ERROR) { 390 printf(" %s = %d\n", lim[i].name, max[0]); 391 } 392 } 393} 394 395 396/** 397 * Print interesting limits for vertex/fragment shaders. 398 */ 399static void 400print_shader_limits(GLenum target) 401{ 402 static const struct token_name vertex_limits[] = { 403 { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB" }, 404 { GL_MAX_VARYING_FLOATS_ARB, "GL_MAX_VARYING_FLOATS_ARB" }, 405 { GL_MAX_VERTEX_ATTRIBS_ARB, "GL_MAX_VERTEX_ATTRIBS_ARB" }, 406 { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" }, 407 { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB" }, 408 { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB" }, 409 { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" }, 410 { GL_MAX_VERTEX_OUTPUT_COMPONENTS , "GL_MAX_VERTEX_OUTPUT_COMPONENTS " }, 411 { (GLenum) 0, NULL } 412 }; 413 static const struct token_name fragment_limits[] = { 414 { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB" }, 415 { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" }, 416 { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" }, 417 { GL_MAX_FRAGMENT_INPUT_COMPONENTS , "GL_MAX_FRAGMENT_INPUT_COMPONENTS " }, 418 { (GLenum) 0, NULL } 419 }; 420 static const struct token_name geometry_limits[] = { 421 { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, "GL_MAX_GEOMETRY_UNIFORM_COMPONENTS" }, 422 { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS" }, 423 { GL_MAX_GEOMETRY_OUTPUT_VERTICES , "GL_MAX_GEOMETRY_OUTPUT_VERTICES " }, 424 { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS" }, 425 { GL_MAX_GEOMETRY_INPUT_COMPONENTS , "GL_MAX_GEOMETRY_INPUT_COMPONENTS " }, 426 { GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, "GL_MAX_GEOMETRY_OUTPUT_COMPONENTS" }, 427 { (GLenum) 0, NULL } 428 }; 429 430 switch (target) { 431 case GL_VERTEX_SHADER: 432 printf(" GL_VERTEX_SHADER_ARB:\n"); 433 print_shader_limit_list(vertex_limits); 434 break; 435 436 case GL_FRAGMENT_SHADER: 437 printf(" GL_FRAGMENT_SHADER_ARB:\n"); 438 print_shader_limit_list(fragment_limits); 439 break; 440 441 case GL_GEOMETRY_SHADER: 442 printf(" GL_GEOMETRY_SHADER:\n"); 443 print_shader_limit_list(geometry_limits); 444 break; 445 } 446} 447 448 449/** 450 * Print interesting limits for vertex/fragment programs. 451 */ 452static void 453print_program_limits(GLenum target, 454 const struct ext_functions *extfuncs) 455{ 456#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) 457 struct token_name { 458 GLenum token; 459 const char *name; 460 }; 461 static const struct token_name common_limits[] = { 462 { GL_MAX_PROGRAM_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_INSTRUCTIONS_ARB" }, 463 { GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB" }, 464 { GL_MAX_PROGRAM_TEMPORARIES_ARB, "GL_MAX_PROGRAM_TEMPORARIES_ARB" }, 465 { GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB" }, 466 { GL_MAX_PROGRAM_PARAMETERS_ARB, "GL_MAX_PROGRAM_PARAMETERS_ARB" }, 467 { GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB" }, 468 { GL_MAX_PROGRAM_ATTRIBS_ARB, "GL_MAX_PROGRAM_ATTRIBS_ARB" }, 469 { GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB" }, 470 { GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB" }, 471 { GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" }, 472 { GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB" }, 473 { GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB" }, 474 { (GLenum) 0, NULL } 475 }; 476 static const struct token_name fragment_limits[] = { 477 { GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB" }, 478 { GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB" }, 479 { GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB" }, 480 { GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" }, 481 { GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" }, 482 { GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" }, 483 { (GLenum) 0, NULL } 484 }; 485 486 GLint max[1]; 487 int i; 488 489 if (target == GL_VERTEX_PROGRAM_ARB) { 490 printf(" GL_VERTEX_PROGRAM_ARB:\n"); 491 } 492 else if (target == GL_FRAGMENT_PROGRAM_ARB) { 493 printf(" GL_FRAGMENT_PROGRAM_ARB:\n"); 494 } 495 else { 496 return; /* something's wrong */ 497 } 498 499 for (i = 0; common_limits[i].token; i++) { 500 extfuncs->GetProgramivARB(target, common_limits[i].token, max); 501 if (glGetError() == GL_NO_ERROR) { 502 printf(" %s = %d\n", common_limits[i].name, max[0]); 503 } 504 } 505 if (target == GL_FRAGMENT_PROGRAM_ARB) { 506 for (i = 0; fragment_limits[i].token; i++) { 507 extfuncs->GetProgramivARB(target, fragment_limits[i].token, max); 508 if (glGetError() == GL_NO_ERROR) { 509 printf(" %s = %d\n", fragment_limits[i].name, max[0]); 510 } 511 } 512 } 513#endif /* GL_ARB_vertex_program / GL_ARB_fragment_program */ 514} 515 516 517/** 518 * Print interesting OpenGL implementation limits. 519 * \param version 20, 21, 30, 31, 32, etc. 520 */ 521void 522print_limits(const char *extensions, const char *oglstring, int version, 523 const struct ext_functions *extfuncs) 524{ 525 struct token_name { 526 GLuint count; 527 GLenum token; 528 const char *name; 529 const char *extension; /* NULL or GL extension name or version string */ 530 }; 531 static const struct token_name limits[] = { 532 { 1, GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH", NULL }, 533 { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH", NULL }, 534 { 1, GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES", NULL }, 535 { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "GL_MAX_COLOR_MATRIX_STACK_DEPTH", "GL_ARB_imaging" }, 536 { 1, GL_MAX_ELEMENTS_VERTICES, "GL_MAX_ELEMENTS_VERTICES", NULL }, 537 { 1, GL_MAX_ELEMENTS_INDICES, "GL_MAX_ELEMENTS_INDICES", NULL }, 538 { 1, GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER", NULL }, 539 { 1, GL_MAX_LIGHTS, "GL_MAX_LIGHTS", NULL }, 540 { 1, GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING", NULL }, 541 { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH", NULL }, 542 { 1, GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH", NULL }, 543 { 1, GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE", NULL }, 544 { 1, GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH", NULL }, 545 { 1, GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH", NULL }, 546 { 1, GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE", NULL }, 547 { 1, GL_MAX_3D_TEXTURE_SIZE, "GL_MAX_3D_TEXTURE_SIZE", NULL }, 548#if defined(GL_EXT_texture_array) 549 { 1, GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, "GL_MAX_ARRAY_TEXTURE_LAYERS", "GL_EXT_texture_array" }, 550#endif 551 { 2, GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS", NULL }, 552 { 2, GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE", NULL }, 553 { 2, GL_SMOOTH_LINE_WIDTH_RANGE, "GL_SMOOTH_LINE_WIDTH_RANGE", NULL }, 554 { 2, GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE", NULL }, 555 { 2, GL_SMOOTH_POINT_SIZE_RANGE, "GL_SMOOTH_POINT_SIZE_RANGE", NULL }, 556#if defined(GL_ARB_texture_cube_map) 557 { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB", "GL_ARB_texture_cube_map" }, 558#endif 559#if defined(GL_NV_texture_rectangle) 560 { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV", "GL_NV_texture_rectangle" }, 561#endif 562#if defined(GL_ARB_multitexture) 563 { 1, GL_MAX_TEXTURE_UNITS_ARB, "GL_MAX_TEXTURE_UNITS_ARB", "GL_ARB_multitexture" }, 564#endif 565#if defined(GL_EXT_texture_lod_bias) 566 { 1, GL_MAX_TEXTURE_LOD_BIAS_EXT, "GL_MAX_TEXTURE_LOD_BIAS_EXT", "GL_EXT_texture_lod_bias" }, 567#endif 568#if defined(GL_EXT_texture_filter_anisotropic) 569 { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT", "GL_EXT_texture_filter_anisotropic" }, 570#endif 571#if defined(GL_ARB_draw_buffers) 572 { 1, GL_MAX_DRAW_BUFFERS_ARB, "GL_MAX_DRAW_BUFFERS_ARB", "GL_ARB_draw_buffers" }, 573#endif 574#if defined(GL_ARB_blend_func_extended) 575 { 1, GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS", "GL_ARB_blend_func_extended" }, 576#endif 577#if defined (GL_ARB_framebuffer_object) 578 { 1, GL_MAX_RENDERBUFFER_SIZE, "GL_MAX_RENDERBUFFER_SIZE", "GL_ARB_framebuffer_object" }, 579 { 1, GL_MAX_COLOR_ATTACHMENTS, "GL_MAX_COLOR_ATTACHMENTS", "GL_ARB_framebuffer_object" }, 580 { 1, GL_MAX_SAMPLES, "GL_MAX_SAMPLES", "GL_ARB_framebuffer_object" }, 581#endif 582#if defined (GL_EXT_transform_feedback) 583 { 1, GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS", "GL_EXT_transform_feedback" }, 584 { 1, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT, "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", "GL_EXT_transform_feedback" }, 585 { 1, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", "GL_EXT_transform_feedback", }, 586 { 1, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", "GL_EXT_transform_feedback" }, 587#endif 588#if defined (GL_ARB_texture_buffer_object) 589 { 1, GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, "GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT", "GL_ARB_texture_buffer_object" }, 590 { 1, GL_MAX_TEXTURE_BUFFER_SIZE, "GL_MAX_TEXTURE_BUFFER_SIZE", "GL_ARB_texture_buffer_object" }, 591#endif 592#if defined (GL_ARB_texture_multisample) 593 { 1, GL_MAX_COLOR_TEXTURE_SAMPLES, "GL_MAX_COLOR_TEXTURE_SAMPLES", "GL_ARB_texture_multisample" }, 594 { 1, GL_MAX_DEPTH_TEXTURE_SAMPLES, "GL_MAX_DEPTH_TEXTURE_SAMPLES", "GL_ARB_texture_multisample" }, 595 { 1, GL_MAX_INTEGER_SAMPLES, "GL_MAX_INTEGER_SAMPLES", "GL_ARB_texture_multisample" }, 596#endif 597#if defined (GL_ARB_uniform_buffer_object) 598 { 1, GL_MAX_VERTEX_UNIFORM_BLOCKS, "GL_MAX_VERTEX_UNIFORM_BLOCKS", "GL_ARB_uniform_buffer_object" }, 599 { 1, GL_MAX_FRAGMENT_UNIFORM_BLOCKS, "GL_MAX_FRAGMENT_UNIFORM_BLOCKS", "GL_ARB_uniform_buffer_object" }, 600 { 1, GL_MAX_GEOMETRY_UNIFORM_BLOCKS, "GL_MAX_GEOMETRY_UNIFORM_BLOCKS" , "GL_ARB_uniform_buffer_object" }, 601 { 1, GL_MAX_COMBINED_UNIFORM_BLOCKS, "GL_MAX_COMBINED_UNIFORM_BLOCKS", "GL_ARB_uniform_buffer_object" }, 602 { 1, GL_MAX_UNIFORM_BUFFER_BINDINGS, "GL_MAX_UNIFORM_BUFFER_BINDINGS", "GL_ARB_uniform_buffer_object" }, 603 { 1, GL_MAX_UNIFORM_BLOCK_SIZE, "GL_MAX_UNIFORM_BLOCK_SIZE", "GL_ARB_uniform_buffer_object" }, 604 { 1, GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", "GL_ARB_uniform_buffer_object" }, 605 { 1, GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", "GL_ARB_uniform_buffer_object" }, 606 { 1, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS", "GL_ARB_uniform_buffer_object" }, 607 { 1, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT", "GL_ARB_uniform_buffer_object" }, 608#endif 609#if defined (GL_ARB_vertex_attrib_binding) 610 { 1, GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, "GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET", "GL_ARB_vertex_attrib_binding" }, 611 { 1, GL_MAX_VERTEX_ATTRIB_BINDINGS, "GL_MAX_VERTEX_ATTRIB_BINDINGS", "GL_ARB_vertex_attrib_binding" }, 612#endif 613#if defined(GL_ARB_tessellation_shader) 614 { 1, GL_MAX_TESS_GEN_LEVEL, "GL_MAX_TESS_GEN_LEVEL", "GL_ARB_tessellation_shader" }, 615 { 1, GL_MAX_TESS_PATCH_COMPONENTS, "GL_MAX_TESS_PATCH_COMPONENTS", "GL_ARB_tessellation_shader" }, 616 { 1, GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, "GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS", "GL_ARB_tessellation_shader" }, 617 { 1, GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS, "GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS", "GL_ARB_tessellation_shader" }, 618 { 1, GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS, "GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS", "GL_ARB_tessellation_shader" }, 619 { 1, GL_MAX_TESS_CONTROL_INPUT_COMPONENTS, "GL_MAX_TESS_CONTROL_INPUT_COMPONENTS", "GL_ARB_tessellation_shader" }, 620 { 1, GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS, "GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS", "GL_ARB_tessellation_shader" }, 621 { 1, GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS, "GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS", "GL_ARB_tessellation_shader" }, 622 { 1, GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS", "GL_ARB_tessellation_shader" }, 623 { 1, GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, "GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS", "GL_ARB_tessellation_shader" }, 624 { 1, GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, "GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS", "GL_ARB_tessellation_shader" }, 625 { 1, GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, "GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS", "GL_ARB_tessellation_shader" }, 626 { 1, GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, "GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS", "GL_ARB_tessellation_shader" }, 627 { 1, GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, "GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS", "GL_ARB_tessellation_shader" }, 628 { 1, GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS", "GL_ARB_tessellation_shader" }, 629#endif 630 631#if defined(GL_VERSION_3_0) 632 { 1, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", "3.0" }, 633 { 1, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", "3.0" }, 634 { 1, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", "3.0" }, 635#endif 636#if defined(GL_VERSION_3_1) 637 { 1, GL_MAX_TEXTURE_BUFFER_SIZE, "GL_MAX_TEXTURE_BUFFER_SIZE", "3.1" }, 638 { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE, "GL_MAX_RECTANGLE_TEXTURE_SIZE", "3.1" }, 639#endif 640#if defined(GL_VERSION_3_2) 641 { 1, GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS", "3.2" }, 642 { 1, GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, "GL_MAX_GEOMETRY_UNIFORM_COMPONENTS", "3.2" }, 643 { 1, GL_MAX_GEOMETRY_OUTPUT_VERTICES, "GL_MAX_GEOMETRY_OUTPUT_VERTICES", "3.2" }, 644 { 1, GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS", "3.2" }, 645 { 1, GL_MAX_VERTEX_OUTPUT_COMPONENTS, "GL_MAX_VERTEX_OUTPUT_COMPONENTS", "3.2" }, 646 { 1, GL_MAX_GEOMETRY_INPUT_COMPONENTS, "GL_MAX_GEOMETRY_INPUT_COMPONENTS", "3.2" }, 647 { 1, GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, "GL_MAX_GEOMETRY_OUTPUT_COMPONENTS", "3.2" }, 648 { 1, GL_MAX_FRAGMENT_INPUT_COMPONENTS, "GL_MAX_FRAGMENT_INPUT_COMPONENTS", "3.2" }, 649 { 1, GL_MAX_SERVER_WAIT_TIMEOUT, "GL_MAX_SERVER_WAIT_TIMEOUT", "3.2" }, 650 { 1, GL_MAX_SAMPLE_MASK_WORDS, "GL_MAX_SAMPLE_MASK_WORDS", "3.2" }, 651 { 1, GL_MAX_COLOR_TEXTURE_SAMPLES, "GL_MAX_COLOR_TEXTURE_SAMPLES", "3.2" }, 652 { 1, GL_MAX_DEPTH_TEXTURE_SAMPLES, "GL_MAX_DEPTH_TEXTURE_SAMPLES", "3.2" }, 653 { 1, GL_MAX_INTEGER_SAMPLES, "GL_MAX_INTEGER_SAMPLES", "3.2" }, 654#endif 655#if defined(GL_VERSION_3_3) 656 { 1, GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS", "3.3" }, 657#endif 658#if defined(GL_VERSION_4_0) 659 { 1, GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS", "4.0" }, 660#endif 661#if defined(GL_VERSION_4_1) 662 { 1, GL_MAX_VERTEX_UNIFORM_VECTORS, "GL_MAX_VERTEX_UNIFORM_VECTORS", "4.1" }, 663 { 1, GL_MAX_VARYING_VECTORS, "GL_MAX_VARYING_VECTORS", "4.1" }, 664 { 1, GL_MAX_FRAGMENT_UNIFORM_VECTORS, "GL_MAX_FRAGMENT_UNIFORM_VECTORS", "4.1" }, 665#endif 666#if defined(GL_VERSION_4_2) 667 { 1, GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS", "4.2" }, 668 { 1, GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, "GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS", "4.2" }, 669 { 1, GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS", "4.2" }, 670 { 1, GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS", "4.2" }, 671 { 1, GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS", "4.2" }, 672 { 1, GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, "GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS", "4.2" }, 673 { 1, GL_MAX_VERTEX_ATOMIC_COUNTERS, "GL_MAX_VERTEX_ATOMIC_COUNTERS", "4.2" }, 674 { 1, GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, "GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS", "4.2" }, 675 { 1, GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS", "4.2" }, 676 { 1, GL_MAX_GEOMETRY_ATOMIC_COUNTERS, "GL_MAX_GEOMETRY_ATOMIC_COUNTERS", "4.2" }, 677 { 1, GL_MAX_FRAGMENT_ATOMIC_COUNTERS, "GL_MAX_FRAGMENT_ATOMIC_COUNTERS", "4.2" }, 678 { 1, GL_MAX_COMBINED_ATOMIC_COUNTERS, "GL_MAX_COMBINED_ATOMIC_COUNTERS", "4.2" }, 679 { 1, GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, "GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE", "4.2" }, 680 { 1, GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, "GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS", "4.2" }, 681 { 1, GL_MAX_IMAGE_UNITS, "GL_MAX_IMAGE_UNITS", "4.2" }, 682 { 1, GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS, "GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS", "4.2" }, 683 { 1, GL_MAX_IMAGE_SAMPLES, "GL_MAX_IMAGE_SAMPLES", "4.2" }, 684 { 1, GL_MAX_VERTEX_IMAGE_UNIFORMS , "GL_MAX_VERTEX_IMAGE_UNIFORMS", "4.2" }, 685 { 1, GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, "GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS", "4.2" }, 686 { 1, GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, "GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS", "4.2" }, 687 { 1, GL_MAX_GEOMETRY_IMAGE_UNIFORMS, "GL_MAX_GEOMETRY_IMAGE_UNIFORMS", "4.2" }, 688 { 1, GL_MAX_FRAGMENT_IMAGE_UNIFORMS, "GL_MAX_FRAGMENT_IMAGE_UNIFORMS", "4.2" }, 689 { 1, GL_MAX_COMBINED_IMAGE_UNIFORMS, "GL_MAX_COMBINED_IMAGE_UNIFORMS", "4.2" }, 690#endif 691#if defined(GL_VERSION_4_3) 692 { 1, GL_MAX_ELEMENT_INDEX, "GL_MAX_ELEMENT_INDEX", "4.3" }, 693 { 1, GL_MAX_COMPUTE_UNIFORM_BLOCKS, "GL_MAX_COMPUTE_UNIFORM_BLOCKS", "4.3" }, 694 { 1, GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, "GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS", "4.3" }, 695 { 1, GL_MAX_COMPUTE_IMAGE_UNIFORMS, "GL_MAX_COMPUTE_IMAGE_UNIFORMS", "4.3" }, 696 { 1, GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, "GL_MAX_COMPUTE_SHARED_MEMORY_SIZE", "4.3" }, 697 { 1, GL_MAX_COMPUTE_UNIFORM_COMPONENTS, "GL_MAX_COMPUTE_UNIFORM_COMPONENTS", "4.3" }, 698 { 1, GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, "GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS", "4.3" }, 699 { 1, GL_MAX_COMPUTE_ATOMIC_COUNTERS, "GL_MAX_COMPUTE_ATOMIC_COUNTERS", "4.3" }, 700 { 1, GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS", "4.3" }, 701 { 1, GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, "GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS", "4.3" }, 702 { 1, GL_MAX_COMPUTE_WORK_GROUP_COUNT, "GL_MAX_COMPUTE_WORK_GROUP_COUNT", "4.3" }, 703 { 1, GL_MAX_COMPUTE_WORK_GROUP_SIZE, "GL_MAX_COMPUTE_WORK_GROUP_SIZE", "4.3" }, 704 { 1, GL_MAX_DEBUG_MESSAGE_LENGTH, "GL_MAX_DEBUG_MESSAGE_LENGTH", "4.3" }, 705 { 1, GL_MAX_DEBUG_LOGGED_MESSAGES, "GL_MAX_DEBUG_LOGGED_MESSAGES", "4.3" }, 706 { 1, GL_MAX_DEBUG_GROUP_STACK_DEPTH, "GL_MAX_DEBUG_GROUP_STACK_DEPTH", "4.3" }, 707 { 1, GL_MAX_LABEL_LENGTH, "GL_MAX_LABEL_LENGTH", "4.3" }, 708 { 1, GL_MAX_UNIFORM_LOCATIONS, "GL_MAX_UNIFORM_LOCATIONS", "4.3" }, 709 { 1, GL_MAX_FRAMEBUFFER_WIDTH, "GL_MAX_FRAMEBUFFER_WIDTH", "4.3" }, 710 { 1, GL_MAX_FRAMEBUFFER_HEIGHT, "GL_MAX_FRAMEBUFFER_HEIGHT", "4.3" }, 711 { 1, GL_MAX_FRAMEBUFFER_LAYERS, "GL_MAX_FRAMEBUFFER_LAYERS", "4.3" }, 712 { 1, GL_MAX_FRAMEBUFFER_SAMPLES, "GL_MAX_FRAMEBUFFER_SAMPLES", "4.3" }, 713 { 1, GL_MAX_WIDTH, "GL_MAX_WIDTH", "4.3" }, 714 { 1, GL_MAX_HEIGHT, "GL_MAX_HEIGHT", "4.3" }, 715 { 1, GL_MAX_DEPTH, "GL_MAX_DEPTH", "4.3" }, 716 { 1, GL_MAX_LAYERS, "GL_MAX_LAYERS", "4.3" }, 717 { 1, GL_MAX_COMBINED_DIMENSIONS, "GL_MAX_COMBINED_DIMENSIONS", "4.3" }, 718 { 1, GL_MAX_NAME_LENGTH, "GL_MAX_NAME_LENGTH", "4.3" }, 719 { 1, GL_MAX_NUM_ACTIVE_VARIABLES, "GL_MAX_NUM_ACTIVE_VARIABLES", "4.3" }, 720 { 1, GL_MAX_NUM_COMPATIBLE_SUBROUTINES, "GL_MAX_NUM_COMPATIBLE_SUBROUTINES", "4.3" }, 721 { 1, GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS", "4.3" }, 722 { 1, GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS", "4.3" }, 723 { 1, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, "GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS", "4.3" }, 724 { 1, GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, "GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS", "4.3" }, 725 { 1, GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS", "4.3" }, 726 { 1, GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS", "4.3" }, 727 { 1, GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, "GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS", "4.3" }, 728 { 1, GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS", "4.3" }, 729 { 1, GL_MAX_SHADER_STORAGE_BLOCK_SIZE, "GL_MAX_SHADER_STORAGE_BLOCK_SIZE", "4.3" }, 730 { 1, GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, "GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES", "4.3" }, 731 { 1, GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, "GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET", "4.3" }, 732 { 1, GL_MAX_VERTEX_ATTRIB_BINDINGS, "GL_MAX_VERTEX_ATTRIB_BINDINGS", "4.3" }, 733#endif 734#if defined(GL_VERSION_4_4) 735 { 1, GL_MAX_VERTEX_ATTRIB_STRIDE, "GL_MAX_VERTEX_ATTRIB_STRIDE", "4.4" }, 736#endif 737#if defined(GL_VERSION_4_5) 738 { 1, GL_MAX_CULL_DISTANCES, "GL_MAX_CULL_DISTANCES", "4.5" }, 739 { 1, GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES", "4.5" }, 740#endif 741#if defined(GL_VERSION_4_6) 742 { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY, "GL_MAX_TEXTURE_MAX_ANISOTROPY", "4.6" }, 743#endif 744#if defined(GL_ARB_transform_feedback3) 745 { 1, GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS", "GL_ARB_transform_feedback3" }, 746 { 1, GL_MAX_VERTEX_STREAMS, "GL_MAX_VERTEX_STREAMS", "GL_ARB_transform_feedback3" }, 747#endif 748 { 0, (GLenum) 0, NULL, NULL } 749 }; 750 GLint i, max[2]; 751 const char *prev_ext = "none"; 752 753 printf("%s limits:\n", oglstring); 754 for (i = 0; limits[i].count; i++) { 755 if (!limits[i].extension || 756 version_supported(limits[i].extension, version) || 757 extension_supported(limits[i].extension, extensions)) { 758 glGetIntegerv(limits[i].token, max); 759 if (glGetError() == GL_NO_ERROR) { 760 if (limits[i].extension && strcmp(limits[i].extension, prev_ext) != 0) { 761 printf(" %s:\n", limits[i].extension); 762 prev_ext = limits[i].extension; 763 } 764 if (limits[i].count == 1) { 765 printf(" %s = %d\n", limits[i].name, max[0]); 766 } 767 else { 768 assert(limits[i].count == 2); 769 printf(" %s = %d, %d\n", limits[i].name, max[0], max[1]); 770 } 771 } 772 } 773 } 774 775 /* these don't fit into the above mechanism, unfortunately */ 776 if (extension_supported("GL_ARB_imaging", extensions)) { 777 extfuncs->GetConvolutionParameteriv(GL_CONVOLUTION_2D, 778 GL_MAX_CONVOLUTION_WIDTH, max); 779 extfuncs->GetConvolutionParameteriv(GL_CONVOLUTION_2D, 780 GL_MAX_CONVOLUTION_HEIGHT, max+1); 781 printf(" GL_ARB_imaging:\n"); 782 printf(" GL_MAX_CONVOLUTION_WIDTH/HEIGHT = %d, %d\n", max[0], max[1]); 783 } 784 785 if (extension_supported("GL_ARB_texture_compression", extensions)) { 786 GLint i, n; 787 GLint *formats; 788 printf(" GL_ARB_texture_compression:\n"); 789 glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &n); 790 printf(" GL_NUM_COMPRESSED_TEXTURE_FORMATS = %d\n", n); 791 formats = (GLint *) malloc(n * sizeof(GLint)); 792 glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats); 793 for (i = 0; i < n; i++) { 794 printf(" %s\n", enum_name(formats[i])); 795 } 796 free(formats); 797 } 798 799#if defined(GL_VERSION_4_3) 800 if (version >= 43) { 801 GLint i, n = 0; 802 printf(" 4.3:\n"); 803 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &n); 804 printf(" GL_NUM_SHADING_LANGUAGE_VERSIONS = %d\n", n); 805 for (i = 0; i < n; i++) { 806 printf(" %s\n", (const char *) 807 extfuncs->GetStringi(GL_SHADING_LANGUAGE_VERSION, i)); 808 } 809 } 810#endif 811 812#if defined(GL_ARB_vertex_program) 813 if (extension_supported("GL_ARB_vertex_program", extensions)) { 814 print_program_limits(GL_VERTEX_PROGRAM_ARB, extfuncs); 815 } 816#endif 817#if defined(GL_ARB_fragment_program) 818 if (extension_supported("GL_ARB_fragment_program", extensions)) { 819 print_program_limits(GL_FRAGMENT_PROGRAM_ARB, extfuncs); 820 } 821#endif 822 if (extension_supported("GL_ARB_vertex_shader", extensions)) { 823 print_shader_limits(GL_VERTEX_SHADER_ARB); 824 } 825 if (extension_supported("GL_ARB_fragment_shader", extensions)) { 826 print_shader_limits(GL_FRAGMENT_SHADER_ARB); 827 } 828 if (version >= 32) { 829 print_shader_limits(GL_GEOMETRY_SHADER); 830 } 831} 832 833 834 835/** 836 * Return string representation for bits in a bitmask. 837 */ 838const char * 839bitmask_to_string(const struct bit_info bits[], int numBits, int mask) 840{ 841 static char buffer[256], *p; 842 int i; 843 844 strcpy(buffer, "(none)"); 845 p = buffer; 846 for (i = 0; i < numBits; i++) { 847 if (mask & bits[i].bit) { 848 if (p > buffer) 849 *p++ = ','; 850 strcpy(p, bits[i].name); 851 p += strlen(bits[i].name); 852 } 853 } 854 855 return buffer; 856} 857 858/** 859 * Return string representation for the bitmask returned by 860 * GL_CONTEXT_PROFILE_MASK (OpenGL 3.2 or later). 861 */ 862const char * 863profile_mask_string(int mask) 864{ 865 const static struct bit_info bits[] = { 866#ifdef GL_CONTEXT_CORE_PROFILE_BIT 867 { GL_CONTEXT_CORE_PROFILE_BIT, "core profile"}, 868#endif 869#ifdef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 870 { GL_CONTEXT_COMPATIBILITY_PROFILE_BIT, "compatibility profile" } 871#endif 872 }; 873 874 return bitmask_to_string(bits, ELEMENTS(bits), mask); 875} 876 877 878/** 879 * Return string representation for the bitmask returned by 880 * GL_CONTEXT_FLAGS (OpenGL 3.0 or later). 881 */ 882const char * 883context_flags_string(int mask) 884{ 885 const static struct bit_info bits[] = { 886 { GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT, "forward-compatible" }, 887 { GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB, "robust-access" }, 888 { GL_CONTEXT_FLAG_DEBUG_BIT, "debug" }, 889 { GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR, "no-error" }, 890 }; 891 892 return bitmask_to_string(bits, ELEMENTS(bits), mask); 893} 894 895 896static void 897usage(void) 898{ 899#ifdef _WIN32 900 printf("Usage: wglinfo [-v] [-t] [-h] [-b] [-l] [-s]\n"); 901#else 902 printf("Usage: glxinfo [-v] [-t] [-h] [-b] [-l] [-s] [-i] [-display <dname>]\n"); 903 printf("\t-display <dname>: Print GLX visuals on specified server.\n"); 904 printf("\t-i: Force an indirect rendering context.\n"); 905#endif 906 printf("\t-B: brief output, print only the basics.\n"); 907 printf("\t-v: Print visuals info in verbose form.\n"); 908 printf("\t-t: Print verbose visual information table.\n"); 909 printf("\t-h: This information.\n"); 910 printf("\t-b: Find the 'best' visual and print its number.\n"); 911 printf("\t-l: Print interesting OpenGL limits.\n"); 912 printf("\t-s: Print a single extension per line.\n"); 913} 914 915void 916parse_args(int argc, char *argv[], struct options *options) 917{ 918 int i; 919 920 options->mode = Normal; 921 options->findBest = GL_FALSE; 922 options->limits = GL_FALSE; 923 options->singleLine = GL_FALSE; 924 options->displayName = NULL; 925 options->allowDirect = GL_TRUE; 926 927 for (i = 1; i < argc; i++) { 928#ifndef _WIN32 929 if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) { 930 options->displayName = argv[i + 1]; 931 i++; 932 } 933 else if (strcmp(argv[i], "-i") == 0) { 934 options->allowDirect = GL_FALSE; 935 } 936 else 937#endif 938 if (strcmp(argv[i], "-t") == 0) { 939 options->mode = Wide; 940 } 941 else if (strcmp(argv[i], "-v") == 0) { 942 options->mode = Verbose; 943 } 944 else if (strcmp(argv[i], "-B") == 0) { 945 options->mode = Brief; 946 } 947 else if (strcmp(argv[i], "-b") == 0) { 948 options->findBest = GL_TRUE; 949 } 950 else if (strcmp(argv[i], "-l") == 0) { 951 options->limits = GL_TRUE; 952 } 953 else if (strcmp(argv[i], "-h") == 0) { 954 usage(); 955 exit(0); 956 } 957 else if(strcmp(argv[i], "-s") == 0) { 958 options->singleLine = GL_TRUE; 959 } 960 else { 961 printf("Unknown option `%s'\n", argv[i]); 962 usage(); 963 exit(0); 964 } 965 } 966} 967 968static void 969query_ATI_meminfo(void) 970{ 971#ifdef GL_ATI_meminfo 972 int i[4]; 973 974 printf("Memory info (GL_ATI_meminfo):\n"); 975 976 glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, i); 977 printf(" VBO free memory - total: %u MB, largest block: %u MB\n", 978 i[0] / 1024, i[1] / 1024); 979 printf(" VBO free aux. memory - total: %u MB, largest block: %u MB\n", 980 i[2] / 1024, i[3] / 1024); 981 982 glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, i); 983 printf(" Texture free memory - total: %u MB, largest block: %u MB\n", 984 i[0] / 1024, i[1] / 1024); 985 printf(" Texture free aux. memory - total: %u MB, largest block: %u MB\n", 986 i[2] / 1024, i[3] / 1024); 987 988 glGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, i); 989 printf(" Renderbuffer free memory - total: %u MB, largest block: %u MB\n", 990 i[0] / 1024, i[1] / 1024); 991 printf(" Renderbuffer free aux. memory - total: %u MB, largest block: %u MB\n", 992 i[2] / 1024, i[3] / 1024); 993#endif 994} 995 996static void 997query_NVX_gpu_memory_info(void) 998{ 999#ifdef GL_NVX_gpu_memory_info 1000 int i; 1001 1002 printf("Memory info (GL_NVX_gpu_memory_info):\n"); 1003 1004 glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &i); 1005 printf(" Dedicated video memory: %u MB\n", i / 1024); 1006 1007 glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &i); 1008 printf(" Total available memory: %u MB\n", i / 1024); 1009 1010 glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &i); 1011 printf(" Currently available dedicated video memory: %u MB\n", i / 1024); 1012#endif 1013} 1014 1015void 1016print_gpu_memory_info(const char *glExtensions) 1017{ 1018 if (strstr(glExtensions, "GL_ATI_meminfo")) 1019 query_ATI_meminfo(); 1020 if (strstr(glExtensions, "GL_NVX_gpu_memory_info")) 1021 query_NVX_gpu_memory_info(); 1022} 1023