glinfo_common.c revision 32001f49
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 34/** 35 * Return the GL enum name for a numeric value. 36 * We really only care about the compressed texture formats for now. 37 */ 38static const char * 39enum_name(GLenum val) 40{ 41 static const struct { 42 const char *name; 43 GLenum val; 44 } enums [] = { 45 { "GL_COMPRESSED_ALPHA", 0x84E9 }, 46 { "GL_COMPRESSED_LUMINANCE", 0x84EA }, 47 { "GL_COMPRESSED_LUMINANCE_ALPHA", 0x84EB }, 48 { "GL_COMPRESSED_INTENSITY", 0x84EC }, 49 { "GL_COMPRESSED_RGB", 0x84ED }, 50 { "GL_COMPRESSED_RGBA", 0x84EE }, 51 { "GL_COMPRESSED_TEXTURE_FORMATS", 0x86A3 }, 52 { "GL_COMPRESSED_RGB", 0x84ED }, 53 { "GL_COMPRESSED_RGBA", 0x84EE }, 54 { "GL_COMPRESSED_TEXTURE_FORMATS", 0x86A3 }, 55 { "GL_COMPRESSED_ALPHA", 0x84E9 }, 56 { "GL_COMPRESSED_LUMINANCE", 0x84EA }, 57 { "GL_COMPRESSED_LUMINANCE_ALPHA", 0x84EB }, 58 { "GL_COMPRESSED_INTENSITY", 0x84EC }, 59 { "GL_COMPRESSED_SRGB", 0x8C48 }, 60 { "GL_COMPRESSED_SRGB_ALPHA", 0x8C49 }, 61 { "GL_COMPRESSED_SLUMINANCE", 0x8C4A }, 62 { "GL_COMPRESSED_SLUMINANCE_ALPHA", 0x8C4B }, 63 { "GL_COMPRESSED_RED", 0x8225 }, 64 { "GL_COMPRESSED_RG", 0x8226 }, 65 { "GL_COMPRESSED_RED_RGTC1", 0x8DBB }, 66 { "GL_COMPRESSED_SIGNED_RED_RGTC1", 0x8DBC }, 67 { "GL_COMPRESSED_RG_RGTC2", 0x8DBD }, 68 { "GL_COMPRESSED_SIGNED_RG_RGTC2", 0x8DBE }, 69 { "GL_COMPRESSED_RGB8_ETC2", 0x9274 }, 70 { "GL_COMPRESSED_SRGB8_ETC2", 0x9275 }, 71 { "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2", 0x9276 }, 72 { "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2", 0x9277 }, 73 { "GL_COMPRESSED_RGBA8_ETC2_EAC", 0x9278 }, 74 { "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC", 0x9279 }, 75 { "GL_COMPRESSED_R11_EAC", 0x9270 }, 76 { "GL_COMPRESSED_SIGNED_R11_EAC", 0x9271 }, 77 { "GL_COMPRESSED_RG11_EAC", 0x9272 }, 78 { "GL_COMPRESSED_SIGNED_RG11_EAC", 0x9273 }, 79 { "GL_COMPRESSED_ALPHA_ARB", 0x84E9 }, 80 { "GL_COMPRESSED_LUMINANCE_ARB", 0x84EA }, 81 { "GL_COMPRESSED_LUMINANCE_ALPHA_ARB", 0x84EB }, 82 { "GL_COMPRESSED_INTENSITY_ARB", 0x84EC }, 83 { "GL_COMPRESSED_RGB_ARB", 0x84ED }, 84 { "GL_COMPRESSED_RGBA_ARB", 0x84EE }, 85 { "GL_COMPRESSED_TEXTURE_FORMATS_ARB", 0x86A3 }, 86 { "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB", 0x8E8C }, 87 { "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB", 0x8E8D }, 88 { "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB", 0x8E8E }, 89 { "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB", 0x8E8F }, 90 { "GL_COMPRESSED_RGBA_ASTC_4x4_KHR", 0x93B0 }, 91 { "GL_COMPRESSED_RGBA_ASTC_5x4_KHR", 0x93B1 }, 92 { "GL_COMPRESSED_RGBA_ASTC_5x5_KHR", 0x93B2 }, 93 { "GL_COMPRESSED_RGBA_ASTC_6x5_KHR", 0x93B3 }, 94 { "GL_COMPRESSED_RGBA_ASTC_6x6_KHR", 0x93B4 }, 95 { "GL_COMPRESSED_RGBA_ASTC_8x5_KHR", 0x93B5 }, 96 { "GL_COMPRESSED_RGBA_ASTC_8x6_KHR", 0x93B6 }, 97 { "GL_COMPRESSED_RGBA_ASTC_8x8_KHR", 0x93B7 }, 98 { "GL_COMPRESSED_RGBA_ASTC_10x5_KHR", 0x93B8 }, 99 { "GL_COMPRESSED_RGBA_ASTC_10x6_KHR", 0x93B9 }, 100 { "GL_COMPRESSED_RGBA_ASTC_10x8_KHR", 0x93BA }, 101 { "GL_COMPRESSED_RGBA_ASTC_10x10_KHR", 0x93BB }, 102 { "GL_COMPRESSED_RGBA_ASTC_12x10_KHR", 0x93BC }, 103 { "GL_COMPRESSED_RGBA_ASTC_12x12_KHR", 0x93BD }, 104 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR", 0x93D0 }, 105 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR", 0x93D1 }, 106 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR", 0x93D2 }, 107 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR", 0x93D3 }, 108 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR", 0x93D4 }, 109 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR", 0x93D5 }, 110 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR", 0x93D6 }, 111 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR", 0x93D7 }, 112 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR", 0x93D8 }, 113 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR", 0x93D9 }, 114 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR", 0x93DA }, 115 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR", 0x93DB }, 116 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR", 0x93DC }, 117 { "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR", 0x93DD }, 118 { "GL_COMPRESSED_RGB_FXT1_3DFX", 0x86B0 }, 119 { "GL_COMPRESSED_RGBA_FXT1_3DFX", 0x86B1 }, 120 { "GL_COMPRESSED_LUMINANCE_LATC1_EXT", 0x8C70 }, 121 { "GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT", 0x8C71 }, 122 { "GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT", 0x8C72 }, 123 { "GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT", 0x8C73 }, 124 { "GL_COMPRESSED_RED_RGTC1_EXT", 0x8DBB }, 125 { "GL_COMPRESSED_SIGNED_RED_RGTC1_EXT", 0x8DBC }, 126 { "GL_COMPRESSED_RED_GREEN_RGTC2_EXT", 0x8DBD }, 127 { "GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT", 0x8DBE }, 128 { "GL_COMPRESSED_RGB_S3TC_DXT1_EXT", 0x83F0 }, 129 { "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT", 0x83F1 }, 130 { "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT", 0x83F2 }, 131 { "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT", 0x83F3 }, 132 { "GL_COMPRESSED_SRGB_EXT", 0x8C48 }, 133 { "GL_COMPRESSED_SRGB_ALPHA_EXT", 0x8C49 }, 134 { "GL_COMPRESSED_SLUMINANCE_EXT", 0x8C4A }, 135 { "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT", 0x8C4B }, 136 { "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT", 0x8C4C }, 137 { "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT", 0x8C4D }, 138 { "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT", 0x8C4E }, 139 { "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT", 0x8C4F }, 140 { "GL_PALETTE4_RGB8_OES", 0x8B90 }, 141 { "GL_PALETTE4_RGBA8_OES", 0x8B91 }, 142 { "GL_PALETTE4_R5_G6_B5_OES", 0x8B92 }, 143 { "GL_PALETTE4_RGBA4_OES", 0x8B93 }, 144 { "GL_PALETTE4_RGB5_A1_OES", 0x8B94 }, 145 { "GL_PALETTE8_RGB8_OES", 0x8B95 }, 146 { "GL_PALETTE8_RGBA8_OES", 0x8B96 }, 147 { "GL_PALETTE8_R5_G6_B5_OES", 0x8B97 }, 148 { "GL_PALETTE8_RGBA4_OES", 0x8B98 }, 149 { "GL_PALETTE8_RGB5_A1_OES", 0x8B99 } 150 }; 151 const int n = sizeof(enums) / sizeof(enums[0]); 152 static char buffer[100]; 153 int i; 154 for (i = 0; i < n; i++) { 155 if (enums[i].val == val) { 156 return enums[i].name; 157 } 158 } 159 /* enum val not found, just print hexadecimal value into static buffer */ 160 snprintf(buffer, sizeof(buffer), "0x%x", val); 161 return buffer; 162} 163 164 165/* 166 * qsort callback for string comparison. 167 */ 168static int 169compare_string_ptr(const void *p1, const void *p2) 170{ 171 return strcmp(* (char * const *) p1, * (char * const *) p2); 172} 173 174/* 175 * Print a list of extensions, with word-wrapping. 176 */ 177void 178print_extension_list(const char *ext, GLboolean singleLine) 179{ 180 char **extensions; 181 int num_extensions; 182 const char *indentString = " "; 183 const int indent = 4; 184 const int max = 79; 185 int width, i, j, k; 186 187 if (!ext || !ext[0]) 188 return; 189 190 /* count the number of extensions, ignoring successive spaces */ 191 num_extensions = 0; 192 j = 1; 193 do { 194 if ((ext[j] == ' ' || ext[j] == 0) && ext[j - 1] != ' ') { 195 ++num_extensions; 196 } 197 } while(ext[j++]); 198 199 /* copy individual extensions to an array */ 200 extensions = malloc(num_extensions * sizeof *extensions); 201 if (!extensions) { 202 fprintf(stderr, "Error: malloc() failed\n"); 203 exit(1); 204 } 205 i = j = k = 0; 206 while (1) { 207 if (ext[j] == ' ' || ext[j] == 0) { 208 /* found end of an extension name */ 209 const int len = j - i; 210 211 if (len) { 212 assert(k < num_extensions); 213 214 extensions[k] = malloc(len + 1); 215 if (!extensions[k]) { 216 fprintf(stderr, "Error: malloc() failed\n"); 217 exit(1); 218 } 219 220 memcpy(extensions[k], ext + i, len); 221 extensions[k][len] = 0; 222 223 ++k; 224 }; 225 226 i += len + 1; 227 228 if (ext[j] == 0) { 229 break; 230 } 231 } 232 j++; 233 } 234 assert(k == num_extensions); 235 236 /* sort extensions alphabetically */ 237 qsort(extensions, num_extensions, sizeof extensions[0], compare_string_ptr); 238 239 /* print the extensions */ 240 width = indent; 241 printf("%s", indentString); 242 for (k = 0; k < num_extensions; ++k) { 243 const int len = strlen(extensions[k]); 244 if ((!singleLine) && (width + len > max)) { 245 /* start a new line */ 246 printf("\n"); 247 width = indent; 248 printf("%s", indentString); 249 } 250 /* print the extension name */ 251 printf("%s", extensions[k]); 252 253 /* either we're all done, or we'll continue with next extension */ 254 width += len + 1; 255 256 if (singleLine) { 257 printf("\n"); 258 width = indent; 259 printf("%s", indentString); 260 } 261 else if (k < (num_extensions -1)) { 262 printf(", "); 263 width += 2; 264 } 265 } 266 printf("\n"); 267 268 for (k = 0; k < num_extensions; ++k) { 269 free(extensions[k]); 270 } 271 free(extensions); 272} 273 274 275 276 277/** 278 * Get list of OpenGL extensions using core profile's glGetStringi(). 279 */ 280char * 281build_core_profile_extension_list(const struct ext_functions *extfuncs) 282{ 283 GLint i, n, totalLen; 284 char *buffer; 285 286 glGetIntegerv(GL_NUM_EXTENSIONS, &n); 287 288 /* compute totalLen */ 289 totalLen = 0; 290 for (i = 0; i < n; i++) { 291 const char *ext = (const char *) extfuncs->GetStringi(GL_EXTENSIONS, i); 292 totalLen += strlen(ext) + 1; /* plus a space */ 293 } 294 295 buffer = malloc(totalLen + 1); 296 if (buffer) { 297 int pos = 0; 298 for (i = 0; i < n; i++) { 299 const char *ext = (const char *) extfuncs->GetStringi(GL_EXTENSIONS, i); 300 strcpy(buffer + pos, ext); 301 pos += strlen(ext); 302 buffer[pos++] = ' '; 303 } 304 buffer[pos] = '\0'; 305 } 306 return buffer; 307} 308 309 310/** Is extension 'ext' supported? */ 311GLboolean 312extension_supported(const char *ext, const char *extensionsList) 313{ 314 while (1) { 315 const char *p = strstr(extensionsList, ext); 316 if (p) { 317 /* check that next char is a space or end of string */ 318 int extLen = strlen(ext); 319 if (p[extLen] == 0 || p[extLen] == ' ') { 320 return 1; 321 } 322 else { 323 /* We found a superset string, keep looking */ 324 extensionsList += extLen; 325 } 326 } 327 else { 328 break; 329 } 330 } 331 return 0; 332} 333 334 335/** 336 * Is verNum >= verString? 337 * \param verString such as "2.1", "3.0", etc. 338 * \param verNum such as 20, 21, 30, 31, 32, etc. 339 */ 340static GLboolean 341version_supported(const char *verString, int verNum) 342{ 343 int v; 344 345 if (!verString || 346 !isdigit(verString[0]) || 347 verString[1] != '.' || 348 !isdigit(verString[2])) { 349 return GL_FALSE; 350 } 351 352 v = (verString[0] - '0') * 10 + (verString[2] - '0'); 353 354 return verNum >= v; 355} 356 357 358struct token_name 359{ 360 GLenum token; 361 const char *name; 362}; 363 364 365static void 366print_shader_limit_list(const struct token_name *lim) 367{ 368 GLint max[1]; 369 unsigned i; 370 371 for (i = 0; lim[i].token; i++) { 372 glGetIntegerv(lim[i].token, max); 373 if (glGetError() == GL_NO_ERROR) { 374 printf(" %s = %d\n", lim[i].name, max[0]); 375 } 376 } 377} 378 379 380/** 381 * Print interesting limits for vertex/fragment shaders. 382 */ 383static void 384print_shader_limits(GLenum target) 385{ 386 static const struct token_name vertex_limits[] = { 387 { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB" }, 388 { GL_MAX_VARYING_FLOATS_ARB, "GL_MAX_VARYING_FLOATS_ARB" }, 389 { GL_MAX_VERTEX_ATTRIBS_ARB, "GL_MAX_VERTEX_ATTRIBS_ARB" }, 390 { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" }, 391 { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB" }, 392 { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB" }, 393 { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" }, 394 { GL_MAX_VERTEX_OUTPUT_COMPONENTS , "GL_MAX_VERTEX_OUTPUT_COMPONENTS " }, 395 { (GLenum) 0, NULL } 396 }; 397 static const struct token_name fragment_limits[] = { 398 { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB" }, 399 { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" }, 400 { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" }, 401 { GL_MAX_FRAGMENT_INPUT_COMPONENTS , "GL_MAX_FRAGMENT_INPUT_COMPONENTS " }, 402 { (GLenum) 0, NULL } 403 }; 404 static const struct token_name geometry_limits[] = { 405 { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, "GL_MAX_GEOMETRY_UNIFORM_COMPONENTS" }, 406 { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS" }, 407 { GL_MAX_GEOMETRY_OUTPUT_VERTICES , "GL_MAX_GEOMETRY_OUTPUT_VERTICES " }, 408 { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS" }, 409 { GL_MAX_GEOMETRY_INPUT_COMPONENTS , "GL_MAX_GEOMETRY_INPUT_COMPONENTS " }, 410 { GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, "GL_MAX_GEOMETRY_OUTPUT_COMPONENTS" }, 411 { (GLenum) 0, NULL } 412 }; 413 414 switch (target) { 415 case GL_VERTEX_SHADER: 416 printf(" GL_VERTEX_SHADER_ARB:\n"); 417 print_shader_limit_list(vertex_limits); 418 break; 419 420 case GL_FRAGMENT_SHADER: 421 printf(" GL_FRAGMENT_SHADER_ARB:\n"); 422 print_shader_limit_list(fragment_limits); 423 break; 424 425 case GL_GEOMETRY_SHADER: 426 printf(" GL_GEOMETRY_SHADER:\n"); 427 print_shader_limit_list(geometry_limits); 428 break; 429 } 430} 431 432 433/** 434 * Print interesting limits for vertex/fragment programs. 435 */ 436static void 437print_program_limits(GLenum target, 438 const struct ext_functions *extfuncs) 439{ 440#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) 441 struct token_name { 442 GLenum token; 443 const char *name; 444 }; 445 static const struct token_name common_limits[] = { 446 { GL_MAX_PROGRAM_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_INSTRUCTIONS_ARB" }, 447 { GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB" }, 448 { GL_MAX_PROGRAM_TEMPORARIES_ARB, "GL_MAX_PROGRAM_TEMPORARIES_ARB" }, 449 { GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB" }, 450 { GL_MAX_PROGRAM_PARAMETERS_ARB, "GL_MAX_PROGRAM_PARAMETERS_ARB" }, 451 { GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB" }, 452 { GL_MAX_PROGRAM_ATTRIBS_ARB, "GL_MAX_PROGRAM_ATTRIBS_ARB" }, 453 { GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB" }, 454 { GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB" }, 455 { GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" }, 456 { GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB" }, 457 { GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB" }, 458 { (GLenum) 0, NULL } 459 }; 460 static const struct token_name fragment_limits[] = { 461 { GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB" }, 462 { GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB" }, 463 { GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB" }, 464 { GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" }, 465 { GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" }, 466 { GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" }, 467 { (GLenum) 0, NULL } 468 }; 469 470 GLint max[1]; 471 int i; 472 473 if (target == GL_VERTEX_PROGRAM_ARB) { 474 printf(" GL_VERTEX_PROGRAM_ARB:\n"); 475 } 476 else if (target == GL_FRAGMENT_PROGRAM_ARB) { 477 printf(" GL_FRAGMENT_PROGRAM_ARB:\n"); 478 } 479 else { 480 return; /* something's wrong */ 481 } 482 483 for (i = 0; common_limits[i].token; i++) { 484 extfuncs->GetProgramivARB(target, common_limits[i].token, max); 485 if (glGetError() == GL_NO_ERROR) { 486 printf(" %s = %d\n", common_limits[i].name, max[0]); 487 } 488 } 489 if (target == GL_FRAGMENT_PROGRAM_ARB) { 490 for (i = 0; fragment_limits[i].token; i++) { 491 extfuncs->GetProgramivARB(target, fragment_limits[i].token, max); 492 if (glGetError() == GL_NO_ERROR) { 493 printf(" %s = %d\n", fragment_limits[i].name, max[0]); 494 } 495 } 496 } 497#endif /* GL_ARB_vertex_program / GL_ARB_fragment_program */ 498} 499 500 501/** 502 * Print interesting OpenGL implementation limits. 503 * \param version 20, 21, 30, 31, 32, etc. 504 */ 505void 506print_limits(const char *extensions, const char *oglstring, int version, 507 const struct ext_functions *extfuncs) 508{ 509 struct token_name { 510 GLuint count; 511 GLenum token; 512 const char *name; 513 const char *extension; /* NULL or GL extension name or version string */ 514 }; 515 static const struct token_name limits[] = { 516 { 1, GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH", NULL }, 517 { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH", NULL }, 518 { 1, GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES", NULL }, 519 { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "GL_MAX_COLOR_MATRIX_STACK_DEPTH", "GL_ARB_imaging" }, 520 { 1, GL_MAX_ELEMENTS_VERTICES, "GL_MAX_ELEMENTS_VERTICES", NULL }, 521 { 1, GL_MAX_ELEMENTS_INDICES, "GL_MAX_ELEMENTS_INDICES", NULL }, 522 { 1, GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER", NULL }, 523 { 1, GL_MAX_LIGHTS, "GL_MAX_LIGHTS", NULL }, 524 { 1, GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING", NULL }, 525 { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH", NULL }, 526 { 1, GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH", NULL }, 527 { 1, GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE", NULL }, 528 { 1, GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH", NULL }, 529 { 1, GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH", NULL }, 530 { 1, GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE", NULL }, 531 { 1, GL_MAX_3D_TEXTURE_SIZE, "GL_MAX_3D_TEXTURE_SIZE", NULL }, 532#if defined(GL_EXT_texture_array) 533 { 1, GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, "GL_MAX_ARRAY_TEXTURE_LAYERS", "GL_EXT_texture_array" }, 534#endif 535 { 2, GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS", NULL }, 536 { 2, GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE", NULL }, 537 { 2, GL_SMOOTH_LINE_WIDTH_RANGE, "GL_SMOOTH_LINE_WIDTH_RANGE", NULL }, 538 { 2, GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE", NULL }, 539 { 2, GL_SMOOTH_POINT_SIZE_RANGE, "GL_SMOOTH_POINT_SIZE_RANGE", NULL }, 540#if defined(GL_ARB_texture_cube_map) 541 { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB", "GL_ARB_texture_cube_map" }, 542#endif 543#if defined(GL_NV_texture_rectangle) 544 { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV", "GL_NV_texture_rectangle" }, 545#endif 546#if defined(GL_ARB_multitexture) 547 { 1, GL_MAX_TEXTURE_UNITS_ARB, "GL_MAX_TEXTURE_UNITS_ARB", "GL_ARB_multitexture" }, 548#endif 549#if defined(GL_EXT_texture_lod_bias) 550 { 1, GL_MAX_TEXTURE_LOD_BIAS_EXT, "GL_MAX_TEXTURE_LOD_BIAS_EXT", "GL_EXT_texture_lod_bias" }, 551#endif 552#if defined(GL_EXT_texture_filter_anisotropic) 553 { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT", "GL_EXT_texture_filter_anisotropic" }, 554#endif 555#if defined(GL_ARB_draw_buffers) 556 { 1, GL_MAX_DRAW_BUFFERS_ARB, "GL_MAX_DRAW_BUFFERS_ARB", "GL_ARB_draw_buffers" }, 557#endif 558#if defined(GL_ARB_blend_func_extended) 559 { 1, GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS", "GL_ARB_blend_func_extended" }, 560#endif 561#if defined (GL_ARB_framebuffer_object) 562 { 1, GL_MAX_RENDERBUFFER_SIZE, "GL_MAX_RENDERBUFFER_SIZE", "GL_ARB_framebuffer_object" }, 563 { 1, GL_MAX_COLOR_ATTACHMENTS, "GL_MAX_COLOR_ATTACHMENTS", "GL_ARB_framebuffer_object" }, 564 { 1, GL_MAX_SAMPLES, "GL_MAX_SAMPLES", "GL_ARB_framebuffer_object" }, 565#endif 566#if defined (GL_EXT_transform_feedback) 567 { 1, GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS", "GL_EXT_transform_feedback" }, 568 { 1, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT, "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", "GL_EXT_transform_feedback" }, 569 { 1, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", "GL_EXT_transform_feedback", }, 570 { 1, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT, "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", "GL_EXT_transform_feedback" }, 571#endif 572#if defined (GL_ARB_texture_buffer_object) 573 { 1, GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, "GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT", "GL_ARB_texture_buffer_object" }, 574 { 1, GL_MAX_TEXTURE_BUFFER_SIZE, "GL_MAX_TEXTURE_BUFFER_SIZE", "GL_ARB_texture_buffer_object" }, 575#endif 576#if defined (GL_ARB_uniform_buffer_object) 577 { 1, GL_MAX_VERTEX_UNIFORM_BLOCKS, "GL_MAX_VERTEX_UNIFORM_BLOCKS", "GL_ARB_uniform_buffer_object" }, 578 { 1, GL_MAX_FRAGMENT_UNIFORM_BLOCKS, "GL_MAX_FRAGMENT_UNIFORM_BLOCKS", "GL_ARB_uniform_buffer_object" }, 579 { 1, GL_MAX_GEOMETRY_UNIFORM_BLOCKS, "GL_MAX_GEOMETRY_UNIFORM_BLOCKS" , "GL_ARB_uniform_buffer_object" }, 580 { 1, GL_MAX_COMBINED_UNIFORM_BLOCKS, "GL_MAX_COMBINED_UNIFORM_BLOCKS", "GL_ARB_uniform_buffer_object" }, 581 { 1, GL_MAX_UNIFORM_BUFFER_BINDINGS, "GL_MAX_UNIFORM_BUFFER_BINDINGS", "GL_ARB_uniform_buffer_object" }, 582 { 1, GL_MAX_UNIFORM_BLOCK_SIZE, "GL_MAX_UNIFORM_BLOCK_SIZE", "GL_ARB_uniform_buffer_object" }, 583 { 1, GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", "GL_ARB_uniform_buffer_object" }, 584 { 1, GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", "GL_ARB_uniform_buffer_object" }, 585 { 1, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, "GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS", "GL_ARB_uniform_buffer_object" }, 586 { 1, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT", "GL_ARB_uniform_buffer_object" }, 587#endif 588#if defined (GL_ARB_vertex_attrib_binding) 589 { 1, GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, "GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET", "GL_ARB_vertex_attrib_binding" }, 590 { 1, GL_MAX_VERTEX_ATTRIB_BINDINGS, "GL_MAX_VERTEX_ATTRIB_BINDINGS", "GL_ARB_vertex_attrib_binding" }, 591#endif 592#if defined(GL_VERSION_4_4) 593 { 1, GL_MAX_VERTEX_ATTRIB_STRIDE, "GL_MAX_VERTEX_ATTRIB_STRIDE", "4.4" }, 594#endif 595 { 0, (GLenum) 0, NULL, NULL } 596 }; 597 GLint i, max[2]; 598 599 printf("%s limits:\n", oglstring); 600 for (i = 0; limits[i].count; i++) { 601 if (!limits[i].extension || 602 version_supported(limits[i].extension, version) || 603 extension_supported(limits[i].extension, extensions)) { 604 glGetIntegerv(limits[i].token, max); 605 if (glGetError() == GL_NO_ERROR) { 606 if (limits[i].count == 1) 607 printf(" %s = %d\n", limits[i].name, max[0]); 608 else /* XXX fix if we ever query something with more than 2 values */ 609 printf(" %s = %d, %d\n", limits[i].name, max[0], max[1]); 610 } 611 } 612 } 613 614 /* these don't fit into the above mechanism, unfortunately */ 615 if (extension_supported("GL_ARB_imaging", extensions)) { 616 extfuncs->GetConvolutionParameteriv(GL_CONVOLUTION_2D, 617 GL_MAX_CONVOLUTION_WIDTH, max); 618 extfuncs->GetConvolutionParameteriv(GL_CONVOLUTION_2D, 619 GL_MAX_CONVOLUTION_HEIGHT, max+1); 620 printf(" GL_MAX_CONVOLUTION_WIDTH/HEIGHT = %d, %d\n", max[0], max[1]); 621 } 622 623 if (extension_supported("GL_ARB_texture_compression", extensions)) { 624 GLint i, n; 625 GLint *formats; 626 glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &n); 627 printf(" GL_NUM_COMPRESSED_TEXTURE_FORMATS = %d\n", n); 628 formats = (GLint *) malloc(n * sizeof(GLint)); 629 glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats); 630 for (i = 0; i < n; i++) { 631 printf(" %s\n", enum_name(formats[i])); 632 } 633 free(formats); 634 } 635#if defined(GL_ARB_vertex_program) 636 if (extension_supported("GL_ARB_vertex_program", extensions)) { 637 print_program_limits(GL_VERTEX_PROGRAM_ARB, extfuncs); 638 } 639#endif 640#if defined(GL_ARB_fragment_program) 641 if (extension_supported("GL_ARB_fragment_program", extensions)) { 642 print_program_limits(GL_FRAGMENT_PROGRAM_ARB, extfuncs); 643 } 644#endif 645 if (extension_supported("GL_ARB_vertex_shader", extensions)) { 646 print_shader_limits(GL_VERTEX_SHADER_ARB); 647 } 648 if (extension_supported("GL_ARB_fragment_shader", extensions)) { 649 print_shader_limits(GL_FRAGMENT_SHADER_ARB); 650 } 651 if (version >= 32) { 652 print_shader_limits(GL_GEOMETRY_SHADER); 653 } 654} 655 656 657 658/** 659 * Return string representation for bits in a bitmask. 660 */ 661const char * 662bitmask_to_string(const struct bit_info bits[], int numBits, int mask) 663{ 664 static char buffer[256], *p; 665 int i; 666 667 strcpy(buffer, "(none)"); 668 p = buffer; 669 for (i = 0; i < numBits; i++) { 670 if (mask & bits[i].bit) { 671 if (p > buffer) 672 *p++ = ','; 673 strcpy(p, bits[i].name); 674 p += strlen(bits[i].name); 675 } 676 } 677 678 return buffer; 679} 680 681/** 682 * Return string representation for the bitmask returned by 683 * GL_CONTEXT_PROFILE_MASK (OpenGL 3.2 or later). 684 */ 685const char * 686profile_mask_string(int mask) 687{ 688 const static struct bit_info bits[] = { 689#ifdef GL_CONTEXT_CORE_PROFILE_BIT 690 { GL_CONTEXT_CORE_PROFILE_BIT, "core profile"}, 691#endif 692#ifdef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 693 { GL_CONTEXT_COMPATIBILITY_PROFILE_BIT, "compatibility profile" } 694#endif 695 }; 696 697 return bitmask_to_string(bits, ELEMENTS(bits), mask); 698} 699 700 701/** 702 * Return string representation for the bitmask returned by 703 * GL_CONTEXT_FLAGS (OpenGL 3.0 or later). 704 */ 705const char * 706context_flags_string(int mask) 707{ 708 const static struct bit_info bits[] = { 709#ifdef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 710 { GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT, "forward-compatible" }, 711#endif 712#ifdef GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 713 { GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB, "robust-access" }, 714#endif 715 }; 716 717 return bitmask_to_string(bits, ELEMENTS(bits), mask); 718} 719 720 721