1//======================================================================== 2// Context creation and information tool 3// Copyright (c) Camilla Löwy <elmindreda@glfw.org> 4// 5// This software is provided 'as-is', without any express or implied 6// warranty. In no event will the authors be held liable for any damages 7// arising from the use of this software. 8// 9// Permission is granted to anyone to use this software for any purpose, 10// including commercial applications, and to alter it and redistribute it 11// freely, subject to the following restrictions: 12// 13// 1. The origin of this software must not be misrepresented; you must not 14// claim that you wrote the original software. If you use this software 15// in a product, an acknowledgment in the product documentation would 16// be appreciated but is not required. 17// 18// 2. Altered source versions must be plainly marked as such, and must not 19// be misrepresented as being the original software. 20// 21// 3. This notice may not be removed or altered from any source 22// distribution. 23// 24//======================================================================== 25 26#define GLAD_GL_IMPLEMENTATION 27#include <glad/gl.h> 28#define GLAD_VULKAN_IMPLEMENTATION 29#include <glad/vulkan.h> 30#define GLFW_INCLUDE_NONE 31#include <GLFW/glfw3.h> 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <stdbool.h> 37 38#include "getopt.h" 39 40#ifdef _MSC_VER 41#define strcasecmp(x, y) _stricmp(x, y) 42#endif 43 44#define API_NAME_OPENGL "gl" 45#define API_NAME_OPENGL_ES "es" 46 47#define API_NAME_NATIVE "native" 48#define API_NAME_EGL "egl" 49#define API_NAME_OSMESA "osmesa" 50 51#define PROFILE_NAME_CORE "core" 52#define PROFILE_NAME_COMPAT "compat" 53 54#define STRATEGY_NAME_NONE "none" 55#define STRATEGY_NAME_LOSE "lose" 56 57#define BEHAVIOR_NAME_NONE "none" 58#define BEHAVIOR_NAME_FLUSH "flush" 59 60#define ANGLE_TYPE_OPENGL "gl" 61#define ANGLE_TYPE_OPENGLES "es" 62#define ANGLE_TYPE_D3D9 "d3d9" 63#define ANGLE_TYPE_D3D11 "d3d11" 64#define ANGLE_TYPE_VULKAN "vk" 65#define ANGLE_TYPE_METAL "mtl" 66 67#define PLATFORM_NAME_ANY "any" 68#define PLATFORM_NAME_WIN32 "win32" 69#define PLATFORM_NAME_COCOA "cooca" 70#define PLATFORM_NAME_WL "wayland" 71#define PLATFORM_NAME_X11 "x11" 72#define PLATFORM_NAME_NULL "null" 73 74static void usage(void) 75{ 76 printf("Usage: glfwinfo [OPTION]...\n"); 77 printf("Options:\n"); 78 printf(" --platform=PLATFORM the platform to use (" 79 PLATFORM_NAME_ANY " or " 80 PLATFORM_NAME_WIN32 " or " 81 PLATFORM_NAME_COCOA " or " 82 PLATFORM_NAME_X11 " or " 83 PLATFORM_NAME_WL " or " 84 PLATFORM_NAME_NULL ")\n"); 85 printf(" -a, --client-api=API the client API to use (" 86 API_NAME_OPENGL " or " 87 API_NAME_OPENGL_ES ")\n"); 88 printf(" -b, --behavior=BEHAVIOR the release behavior to use (" 89 BEHAVIOR_NAME_NONE " or " 90 BEHAVIOR_NAME_FLUSH ")\n"); 91 printf(" -c, --context-api=API the context creation API to use (" 92 API_NAME_NATIVE " or " 93 API_NAME_EGL " or " 94 API_NAME_OSMESA ")\n"); 95 printf(" -d, --debug request a debug context\n"); 96 printf(" -f, --forward require a forward-compatible context\n"); 97 printf(" -h, --help show this help\n"); 98 printf(" -l, --list-extensions list all Vulkan and client API extensions\n"); 99 printf(" --list-layers list all Vulkan layers\n"); 100 printf(" -m, --major=MAJOR the major number of the required " 101 "client API version\n"); 102 printf(" -n, --minor=MINOR the minor number of the required " 103 "client API version\n"); 104 printf(" -p, --profile=PROFILE the OpenGL profile to use (" 105 PROFILE_NAME_CORE " or " 106 PROFILE_NAME_COMPAT ")\n"); 107 printf(" -s, --robustness=STRATEGY the robustness strategy to use (" 108 STRATEGY_NAME_NONE " or " 109 STRATEGY_NAME_LOSE ")\n"); 110 printf(" -v, --version print version information\n"); 111 printf(" --red-bits=N the number of red bits to request\n"); 112 printf(" --green-bits=N the number of green bits to request\n"); 113 printf(" --blue-bits=N the number of blue bits to request\n"); 114 printf(" --alpha-bits=N the number of alpha bits to request\n"); 115 printf(" --depth-bits=N the number of depth bits to request\n"); 116 printf(" --stencil-bits=N the number of stencil bits to request\n"); 117 printf(" --accum-red-bits=N the number of red bits to request\n"); 118 printf(" --accum-green-bits=N the number of green bits to request\n"); 119 printf(" --accum-blue-bits=N the number of blue bits to request\n"); 120 printf(" --accum-alpha-bits=N the number of alpha bits to request\n"); 121 printf(" --aux-buffers=N the number of aux buffers to request\n"); 122 printf(" --samples=N the number of MSAA samples to request\n"); 123 printf(" --stereo request stereo rendering\n"); 124 printf(" --srgb request an sRGB capable framebuffer\n"); 125 printf(" --singlebuffer request single-buffering\n"); 126 printf(" --no-error request a context that does not emit errors\n"); 127 printf(" --angle-type=TYPE the ANGLE platform type to use (" 128 ANGLE_TYPE_OPENGL ", " 129 ANGLE_TYPE_OPENGLES ", " 130 ANGLE_TYPE_D3D9 ", " 131 ANGLE_TYPE_D3D11 ", " 132 ANGLE_TYPE_VULKAN " or " 133 ANGLE_TYPE_METAL ")\n"); 134 printf(" --graphics-switching request macOS graphics switching\n"); 135 printf(" --disable-xcb-surface disable VK_KHR_xcb_surface extension\n"); 136} 137 138static void error_callback(int error, const char* description) 139{ 140 fprintf(stderr, "Error: %s\n", description); 141} 142 143static const char* get_platform_name(int platform) 144{ 145 if (platform == GLFW_PLATFORM_WIN32) 146 return "Win32"; 147 else if (platform == GLFW_PLATFORM_COCOA) 148 return "Cocoa"; 149 else if (platform == GLFW_PLATFORM_WAYLAND) 150 return "Wayland"; 151 else if (platform == GLFW_PLATFORM_X11) 152 return "X11"; 153 else if (platform == GLFW_PLATFORM_NULL) 154 return "Null"; 155 156 return "unknown"; 157} 158 159static const char* get_device_type_name(VkPhysicalDeviceType type) 160{ 161 if (type == VK_PHYSICAL_DEVICE_TYPE_OTHER) 162 return "other"; 163 else if (type == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) 164 return "integrated GPU"; 165 else if (type == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) 166 return "discrete GPU"; 167 else if (type == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) 168 return "virtual GPU"; 169 else if (type == VK_PHYSICAL_DEVICE_TYPE_CPU) 170 return "CPU"; 171 172 return "unknown"; 173} 174 175static const char* get_api_name(int api) 176{ 177 if (api == GLFW_OPENGL_API) 178 return "OpenGL"; 179 else if (api == GLFW_OPENGL_ES_API) 180 return "OpenGL ES"; 181 182 return "Unknown API"; 183} 184 185static const char* get_profile_name_gl(GLint mask) 186{ 187 if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) 188 return PROFILE_NAME_COMPAT; 189 if (mask & GL_CONTEXT_CORE_PROFILE_BIT) 190 return PROFILE_NAME_CORE; 191 192 return "unknown"; 193} 194 195static const char* get_profile_name_glfw(int profile) 196{ 197 if (profile == GLFW_OPENGL_COMPAT_PROFILE) 198 return PROFILE_NAME_COMPAT; 199 if (profile == GLFW_OPENGL_CORE_PROFILE) 200 return PROFILE_NAME_CORE; 201 202 return "unknown"; 203} 204 205static const char* get_strategy_name_gl(GLint strategy) 206{ 207 if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) 208 return STRATEGY_NAME_LOSE; 209 if (strategy == GL_NO_RESET_NOTIFICATION_ARB) 210 return STRATEGY_NAME_NONE; 211 212 return "unknown"; 213} 214 215static const char* get_strategy_name_glfw(int strategy) 216{ 217 if (strategy == GLFW_LOSE_CONTEXT_ON_RESET) 218 return STRATEGY_NAME_LOSE; 219 if (strategy == GLFW_NO_RESET_NOTIFICATION) 220 return STRATEGY_NAME_NONE; 221 222 return "unknown"; 223} 224 225static void list_context_extensions(int client, int major, int minor) 226{ 227 printf("%s context extensions:\n", get_api_name(client)); 228 229 if (client == GLFW_OPENGL_API && major > 2) 230 { 231 GLint count; 232 glGetIntegerv(GL_NUM_EXTENSIONS, &count); 233 234 for (int i = 0; i < count; i++) 235 printf(" %s\n", (const char*) glGetStringi(GL_EXTENSIONS, i)); 236 } 237 else 238 { 239 const GLubyte* extensions = glGetString(GL_EXTENSIONS); 240 while (*extensions != '\0') 241 { 242 putchar(' '); 243 244 while (*extensions != '\0' && *extensions != ' ') 245 { 246 putchar(*extensions); 247 extensions++; 248 } 249 250 while (*extensions == ' ') 251 extensions++; 252 253 putchar('\n'); 254 } 255 } 256} 257 258static void list_vulkan_instance_layers(void) 259{ 260 printf("Vulkan instance layers:\n"); 261 262 uint32_t lp_count; 263 vkEnumerateInstanceLayerProperties(&lp_count, NULL); 264 VkLayerProperties* lp = calloc(lp_count, sizeof(VkLayerProperties)); 265 vkEnumerateInstanceLayerProperties(&lp_count, lp); 266 267 for (uint32_t i = 0; i < lp_count; i++) 268 { 269 printf(" %s (spec version %u.%u) \"%s\"\n", 270 lp[i].layerName, 271 VK_VERSION_MAJOR(lp[i].specVersion), 272 VK_VERSION_MINOR(lp[i].specVersion), 273 lp[i].description); 274 } 275 276 free(lp); 277} 278 279static void list_vulkan_device_layers(VkInstance instance, VkPhysicalDevice device) 280{ 281 printf("Vulkan device layers:\n"); 282 283 uint32_t lp_count; 284 vkEnumerateDeviceLayerProperties(device, &lp_count, NULL); 285 VkLayerProperties* lp = calloc(lp_count, sizeof(VkLayerProperties)); 286 vkEnumerateDeviceLayerProperties(device, &lp_count, lp); 287 288 for (uint32_t i = 0; i < lp_count; i++) 289 { 290 printf(" %s (spec version %u.%u) \"%s\"\n", 291 lp[i].layerName, 292 VK_VERSION_MAJOR(lp[i].specVersion), 293 VK_VERSION_MINOR(lp[i].specVersion), 294 lp[i].description); 295 } 296 297 free(lp); 298} 299 300static bool valid_version(void) 301{ 302 int major, minor, revision; 303 glfwGetVersion(&major, &minor, &revision); 304 305 if (major != GLFW_VERSION_MAJOR) 306 { 307 printf("*** ERROR: GLFW major version mismatch! ***\n"); 308 return false; 309 } 310 311 if (minor != GLFW_VERSION_MINOR || revision != GLFW_VERSION_REVISION) 312 printf("*** WARNING: GLFW version mismatch! ***\n"); 313 314 return true; 315} 316 317static void print_version(void) 318{ 319 int major, minor, revision; 320 glfwGetVersion(&major, &minor, &revision); 321 322 printf("GLFW header version: %u.%u.%u\n", 323 GLFW_VERSION_MAJOR, 324 GLFW_VERSION_MINOR, 325 GLFW_VERSION_REVISION); 326 printf("GLFW library version: %u.%u.%u\n", major, minor, revision); 327 printf("GLFW library version string: \"%s\"\n", glfwGetVersionString()); 328} 329 330static void print_platform(void) 331{ 332 const int platforms[] = 333 { 334 GLFW_PLATFORM_WIN32, 335 GLFW_PLATFORM_COCOA, 336 GLFW_PLATFORM_WAYLAND, 337 GLFW_PLATFORM_X11, 338 GLFW_PLATFORM_NULL 339 }; 340 341 printf("GLFW platform: %s\n", get_platform_name(glfwGetPlatform())); 342 printf("GLFW supported platforms:\n"); 343 344 for (size_t i = 0; i < sizeof(platforms) / sizeof(platforms[0]); i++) 345 { 346 if (glfwPlatformSupported(platforms[i])) 347 printf(" %s\n", get_platform_name(platforms[i])); 348 } 349} 350 351int main(int argc, char** argv) 352{ 353 int ch; 354 bool list_extensions = false, list_layers = false; 355 356 // These duplicate the defaults for each hint 357 int platform = GLFW_ANY_PLATFORM; 358 int client_api = GLFW_OPENGL_API; 359 int context_major = 1; 360 int context_minor = 0; 361 int context_release = GLFW_ANY_RELEASE_BEHAVIOR; 362 int context_creation_api = GLFW_NATIVE_CONTEXT_API; 363 int context_robustness = GLFW_NO_ROBUSTNESS; 364 bool context_debug = false; 365 bool context_no_error = false; 366 bool opengl_forward = false; 367 int opengl_profile = GLFW_OPENGL_ANY_PROFILE; 368 int fb_red_bits = 8; 369 int fb_green_bits = 8; 370 int fb_blue_bits = 8; 371 int fb_alpha_bits = 8; 372 int fb_depth_bits = 24; 373 int fb_stencil_bits = 8; 374 int fb_accum_red_bits = 0; 375 int fb_accum_green_bits = 0; 376 int fb_accum_blue_bits = 0; 377 int fb_accum_alpha_bits = 0; 378 int fb_aux_buffers = 0; 379 int fb_samples = 0; 380 bool fb_stereo = false; 381 bool fb_srgb = false; 382 bool fb_doublebuffer = true; 383 int angle_type = GLFW_ANGLE_PLATFORM_TYPE_NONE; 384 bool cocoa_graphics_switching = false; 385 bool disable_xcb_surface = false; 386 387 enum { PLATFORM, CLIENT, CONTEXT, BEHAVIOR, DEBUG_CONTEXT, FORWARD, HELP, 388 EXTENSIONS, LAYERS, 389 MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION, 390 REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS, 391 ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS, 392 AUXBUFFERS, SAMPLES, STEREO, SRGB, SINGLEBUFFER, NOERROR_SRSLY, 393 ANGLE_TYPE, GRAPHICS_SWITCHING, XCB_SURFACE }; 394 const struct option options[] = 395 { 396 { "platform", 1, NULL, PLATFORM }, 397 { "behavior", 1, NULL, BEHAVIOR }, 398 { "client-api", 1, NULL, CLIENT }, 399 { "context-api", 1, NULL, CONTEXT }, 400 { "debug", 0, NULL, DEBUG_CONTEXT }, 401 { "forward", 0, NULL, FORWARD }, 402 { "help", 0, NULL, HELP }, 403 { "list-extensions", 0, NULL, EXTENSIONS }, 404 { "list-layers", 0, NULL, LAYERS }, 405 { "major", 1, NULL, MAJOR }, 406 { "minor", 1, NULL, MINOR }, 407 { "profile", 1, NULL, PROFILE }, 408 { "robustness", 1, NULL, ROBUSTNESS }, 409 { "version", 0, NULL, VERSION }, 410 { "red-bits", 1, NULL, REDBITS }, 411 { "green-bits", 1, NULL, GREENBITS }, 412 { "blue-bits", 1, NULL, BLUEBITS }, 413 { "alpha-bits", 1, NULL, ALPHABITS }, 414 { "depth-bits", 1, NULL, DEPTHBITS }, 415 { "stencil-bits", 1, NULL, STENCILBITS }, 416 { "accum-red-bits", 1, NULL, ACCUMREDBITS }, 417 { "accum-green-bits", 1, NULL, ACCUMGREENBITS }, 418 { "accum-blue-bits", 1, NULL, ACCUMBLUEBITS }, 419 { "accum-alpha-bits", 1, NULL, ACCUMALPHABITS }, 420 { "aux-buffers", 1, NULL, AUXBUFFERS }, 421 { "samples", 1, NULL, SAMPLES }, 422 { "stereo", 0, NULL, STEREO }, 423 { "srgb", 0, NULL, SRGB }, 424 { "singlebuffer", 0, NULL, SINGLEBUFFER }, 425 { "no-error", 0, NULL, NOERROR_SRSLY }, 426 { "angle-type", 1, NULL, ANGLE_TYPE }, 427 { "graphics-switching", 0, NULL, GRAPHICS_SWITCHING }, 428 { "vk-xcb-surface", 0, NULL, XCB_SURFACE }, 429 { NULL, 0, NULL, 0 } 430 }; 431 432 while ((ch = getopt_long(argc, argv, "a:b:c:dfhlm:n:p:s:v", options, NULL)) != -1) 433 { 434 switch (ch) 435 { 436 case PLATFORM: 437 if (strcasecmp(optarg, PLATFORM_NAME_ANY) == 0) 438 platform = GLFW_ANY_PLATFORM; 439 else if (strcasecmp(optarg, PLATFORM_NAME_WIN32) == 0) 440 platform = GLFW_PLATFORM_WIN32; 441 else if (strcasecmp(optarg, PLATFORM_NAME_COCOA) == 0) 442 platform = GLFW_PLATFORM_COCOA; 443 else if (strcasecmp(optarg, PLATFORM_NAME_WL) == 0) 444 platform = GLFW_PLATFORM_WAYLAND; 445 else if (strcasecmp(optarg, PLATFORM_NAME_X11) == 0) 446 platform = GLFW_PLATFORM_X11; 447 else if (strcasecmp(optarg, PLATFORM_NAME_NULL) == 0) 448 platform = GLFW_PLATFORM_NULL; 449 else 450 { 451 usage(); 452 exit(EXIT_FAILURE); 453 } 454 break; 455 case 'a': 456 case CLIENT: 457 if (strcasecmp(optarg, API_NAME_OPENGL) == 0) 458 client_api = GLFW_OPENGL_API; 459 else if (strcasecmp(optarg, API_NAME_OPENGL_ES) == 0) 460 client_api = GLFW_OPENGL_ES_API; 461 else 462 { 463 usage(); 464 exit(EXIT_FAILURE); 465 } 466 break; 467 case 'b': 468 case BEHAVIOR: 469 if (strcasecmp(optarg, BEHAVIOR_NAME_NONE) == 0) 470 context_release = GLFW_RELEASE_BEHAVIOR_NONE; 471 else if (strcasecmp(optarg, BEHAVIOR_NAME_FLUSH) == 0) 472 context_release = GLFW_RELEASE_BEHAVIOR_FLUSH; 473 else 474 { 475 usage(); 476 exit(EXIT_FAILURE); 477 } 478 break; 479 case 'c': 480 case CONTEXT: 481 if (strcasecmp(optarg, API_NAME_NATIVE) == 0) 482 context_creation_api = GLFW_NATIVE_CONTEXT_API; 483 else if (strcasecmp(optarg, API_NAME_EGL) == 0) 484 context_creation_api = GLFW_EGL_CONTEXT_API; 485 else if (strcasecmp(optarg, API_NAME_OSMESA) == 0) 486 context_creation_api = GLFW_OSMESA_CONTEXT_API; 487 else 488 { 489 usage(); 490 exit(EXIT_FAILURE); 491 } 492 break; 493 case 'd': 494 case DEBUG_CONTEXT: 495 context_debug = true; 496 break; 497 case 'f': 498 case FORWARD: 499 opengl_forward = true; 500 break; 501 case 'h': 502 case HELP: 503 usage(); 504 exit(EXIT_SUCCESS); 505 case 'l': 506 case EXTENSIONS: 507 list_extensions = true; 508 break; 509 case LAYERS: 510 list_layers = true; 511 break; 512 case 'm': 513 case MAJOR: 514 context_major = atoi(optarg); 515 break; 516 case 'n': 517 case MINOR: 518 context_minor = atoi(optarg); 519 break; 520 case 'p': 521 case PROFILE: 522 if (strcasecmp(optarg, PROFILE_NAME_CORE) == 0) 523 opengl_profile = GLFW_OPENGL_CORE_PROFILE; 524 else if (strcasecmp(optarg, PROFILE_NAME_COMPAT) == 0) 525 opengl_profile = GLFW_OPENGL_COMPAT_PROFILE; 526 else 527 { 528 usage(); 529 exit(EXIT_FAILURE); 530 } 531 break; 532 case 's': 533 case ROBUSTNESS: 534 if (strcasecmp(optarg, STRATEGY_NAME_NONE) == 0) 535 context_robustness = GLFW_NO_RESET_NOTIFICATION; 536 else if (strcasecmp(optarg, STRATEGY_NAME_LOSE) == 0) 537 context_robustness = GLFW_LOSE_CONTEXT_ON_RESET; 538 else 539 { 540 usage(); 541 exit(EXIT_FAILURE); 542 } 543 break; 544 case 'v': 545 case VERSION: 546 print_version(); 547 exit(EXIT_SUCCESS); 548 case REDBITS: 549 if (strcmp(optarg, "-") == 0) 550 fb_red_bits = GLFW_DONT_CARE; 551 else 552 fb_red_bits = atoi(optarg); 553 break; 554 case GREENBITS: 555 if (strcmp(optarg, "-") == 0) 556 fb_green_bits = GLFW_DONT_CARE; 557 else 558 fb_green_bits = atoi(optarg); 559 break; 560 case BLUEBITS: 561 if (strcmp(optarg, "-") == 0) 562 fb_blue_bits = GLFW_DONT_CARE; 563 else 564 fb_blue_bits = atoi(optarg); 565 break; 566 case ALPHABITS: 567 if (strcmp(optarg, "-") == 0) 568 fb_alpha_bits = GLFW_DONT_CARE; 569 else 570 fb_alpha_bits = atoi(optarg); 571 break; 572 case DEPTHBITS: 573 if (strcmp(optarg, "-") == 0) 574 fb_depth_bits = GLFW_DONT_CARE; 575 else 576 fb_depth_bits = atoi(optarg); 577 break; 578 case STENCILBITS: 579 if (strcmp(optarg, "-") == 0) 580 fb_stencil_bits = GLFW_DONT_CARE; 581 else 582 fb_stencil_bits = atoi(optarg); 583 break; 584 case ACCUMREDBITS: 585 if (strcmp(optarg, "-") == 0) 586 fb_accum_red_bits = GLFW_DONT_CARE; 587 else 588 fb_accum_red_bits = atoi(optarg); 589 break; 590 case ACCUMGREENBITS: 591 if (strcmp(optarg, "-") == 0) 592 fb_accum_green_bits = GLFW_DONT_CARE; 593 else 594 fb_accum_green_bits = atoi(optarg); 595 break; 596 case ACCUMBLUEBITS: 597 if (strcmp(optarg, "-") == 0) 598 fb_accum_blue_bits = GLFW_DONT_CARE; 599 else 600 fb_accum_blue_bits = atoi(optarg); 601 break; 602 case ACCUMALPHABITS: 603 if (strcmp(optarg, "-") == 0) 604 fb_accum_alpha_bits = GLFW_DONT_CARE; 605 else 606 fb_accum_alpha_bits = atoi(optarg); 607 break; 608 case AUXBUFFERS: 609 if (strcmp(optarg, "-") == 0) 610 fb_aux_buffers = GLFW_DONT_CARE; 611 else 612 fb_aux_buffers = atoi(optarg); 613 break; 614 case SAMPLES: 615 if (strcmp(optarg, "-") == 0) 616 fb_samples = GLFW_DONT_CARE; 617 else 618 fb_samples = atoi(optarg); 619 break; 620 case STEREO: 621 fb_stereo = true; 622 break; 623 case SRGB: 624 fb_srgb = true; 625 break; 626 case SINGLEBUFFER: 627 fb_doublebuffer = false; 628 break; 629 case NOERROR_SRSLY: 630 context_no_error = true; 631 break; 632 case ANGLE_TYPE: 633 if (strcmp(optarg, ANGLE_TYPE_OPENGL) == 0) 634 angle_type = GLFW_ANGLE_PLATFORM_TYPE_OPENGL; 635 else if (strcmp(optarg, ANGLE_TYPE_OPENGLES) == 0) 636 angle_type = GLFW_ANGLE_PLATFORM_TYPE_OPENGLES; 637 else if (strcmp(optarg, ANGLE_TYPE_D3D9) == 0) 638 angle_type = GLFW_ANGLE_PLATFORM_TYPE_D3D9; 639 else if (strcmp(optarg, ANGLE_TYPE_D3D11) == 0) 640 angle_type = GLFW_ANGLE_PLATFORM_TYPE_D3D11; 641 else if (strcmp(optarg, ANGLE_TYPE_VULKAN) == 0) 642 angle_type = GLFW_ANGLE_PLATFORM_TYPE_VULKAN; 643 else if (strcmp(optarg, ANGLE_TYPE_METAL) == 0) 644 angle_type = GLFW_ANGLE_PLATFORM_TYPE_METAL; 645 else 646 { 647 usage(); 648 exit(EXIT_FAILURE); 649 } 650 break; 651 case GRAPHICS_SWITCHING: 652 cocoa_graphics_switching = true; 653 break; 654 case XCB_SURFACE: 655 disable_xcb_surface = true; 656 break; 657 default: 658 usage(); 659 exit(EXIT_FAILURE); 660 } 661 } 662 663 // Initialize GLFW and create window 664 665 if (!valid_version()) 666 exit(EXIT_FAILURE); 667 668 glfwSetErrorCallback(error_callback); 669 670 glfwInitHint(GLFW_PLATFORM, platform); 671 672 glfwInitHint(GLFW_COCOA_MENUBAR, false); 673 674 glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, angle_type); 675 glfwInitHint(GLFW_X11_XCB_VULKAN_SURFACE, !disable_xcb_surface); 676 677 if (!glfwInit()) 678 exit(EXIT_FAILURE); 679 680 print_version(); 681 print_platform(); 682 683 glfwWindowHint(GLFW_VISIBLE, false); 684 685 glfwWindowHint(GLFW_CLIENT_API, client_api); 686 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, context_major); 687 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, context_minor); 688 glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR, context_release); 689 glfwWindowHint(GLFW_CONTEXT_CREATION_API, context_creation_api); 690 glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS, context_robustness); 691 glfwWindowHint(GLFW_CONTEXT_DEBUG, context_debug); 692 glfwWindowHint(GLFW_CONTEXT_NO_ERROR, context_no_error); 693 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, opengl_forward); 694 glfwWindowHint(GLFW_OPENGL_PROFILE, opengl_profile); 695 696 glfwWindowHint(GLFW_RED_BITS, fb_red_bits); 697 glfwWindowHint(GLFW_BLUE_BITS, fb_blue_bits); 698 glfwWindowHint(GLFW_GREEN_BITS, fb_green_bits); 699 glfwWindowHint(GLFW_ALPHA_BITS, fb_alpha_bits); 700 glfwWindowHint(GLFW_DEPTH_BITS, fb_depth_bits); 701 glfwWindowHint(GLFW_STENCIL_BITS, fb_stencil_bits); 702 glfwWindowHint(GLFW_ACCUM_RED_BITS, fb_accum_red_bits); 703 glfwWindowHint(GLFW_ACCUM_GREEN_BITS, fb_accum_green_bits); 704 glfwWindowHint(GLFW_ACCUM_BLUE_BITS, fb_accum_blue_bits); 705 glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, fb_accum_alpha_bits); 706 glfwWindowHint(GLFW_AUX_BUFFERS, fb_aux_buffers); 707 glfwWindowHint(GLFW_SAMPLES, fb_samples); 708 glfwWindowHint(GLFW_STEREO, fb_stereo); 709 glfwWindowHint(GLFW_SRGB_CAPABLE, fb_srgb); 710 glfwWindowHint(GLFW_DOUBLEBUFFER, fb_doublebuffer); 711 712 glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, cocoa_graphics_switching); 713 714 GLFWwindow* window = glfwCreateWindow(200, 200, "Version", NULL, NULL); 715 if (window) 716 { 717 glfwMakeContextCurrent(window); 718 gladLoadGL(glfwGetProcAddress); 719 720 const GLenum error = glGetError(); 721 if (error != GL_NO_ERROR) 722 printf("*** OpenGL error after make current: 0x%08x ***\n", error); 723 724 // Report client API version 725 726 const int client = glfwGetWindowAttrib(window, GLFW_CLIENT_API); 727 const int major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); 728 const int minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); 729 const int revision = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION); 730 const int profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE); 731 732 printf("%s context version string: \"%s\"\n", 733 get_api_name(client), 734 glGetString(GL_VERSION)); 735 736 printf("%s context version parsed by GLFW: %u.%u.%u\n", 737 get_api_name(client), 738 major, minor, revision); 739 740 // Report client API context properties 741 742 if (client == GLFW_OPENGL_API) 743 { 744 if (major >= 3) 745 { 746 GLint flags; 747 748 glGetIntegerv(GL_CONTEXT_FLAGS, &flags); 749 printf("%s context flags (0x%08x):", get_api_name(client), flags); 750 751 if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) 752 printf(" forward-compatible"); 753 if (flags & 2/*GL_CONTEXT_FLAG_DEBUG_BIT*/) 754 printf(" debug"); 755 if (flags & GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB) 756 printf(" robustness"); 757 if (flags & 8/*GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR*/) 758 printf(" no-error"); 759 putchar('\n'); 760 761 printf("%s context flags parsed by GLFW:", get_api_name(client)); 762 763 if (glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT)) 764 printf(" forward-compatible"); 765 if (glfwGetWindowAttrib(window, GLFW_CONTEXT_DEBUG)) 766 printf(" debug"); 767 if (glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS) == GLFW_LOSE_CONTEXT_ON_RESET) 768 printf(" robustness"); 769 if (glfwGetWindowAttrib(window, GLFW_CONTEXT_NO_ERROR)) 770 printf(" no-error"); 771 putchar('\n'); 772 } 773 774 if (major >= 4 || (major == 3 && minor >= 2)) 775 { 776 GLint mask; 777 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); 778 779 printf("%s profile mask (0x%08x): %s\n", 780 get_api_name(client), 781 mask, 782 get_profile_name_gl(mask)); 783 784 printf("%s profile mask parsed by GLFW: %s\n", 785 get_api_name(client), 786 get_profile_name_glfw(profile)); 787 } 788 789 if (GLAD_GL_ARB_robustness) 790 { 791 const int robustness = glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS); 792 GLint strategy; 793 glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); 794 795 printf("%s robustness strategy (0x%08x): %s\n", 796 get_api_name(client), 797 strategy, 798 get_strategy_name_gl(strategy)); 799 800 printf("%s robustness strategy parsed by GLFW: %s\n", 801 get_api_name(client), 802 get_strategy_name_glfw(robustness)); 803 } 804 } 805 806 printf("%s context renderer string: \"%s\"\n", 807 get_api_name(client), 808 glGetString(GL_RENDERER)); 809 printf("%s context vendor string: \"%s\"\n", 810 get_api_name(client), 811 glGetString(GL_VENDOR)); 812 813 if (major >= 2) 814 { 815 printf("%s context shading language version: \"%s\"\n", 816 get_api_name(client), 817 glGetString(GL_SHADING_LANGUAGE_VERSION)); 818 } 819 820 printf("%s framebuffer:\n", get_api_name(client)); 821 822 GLint redbits, greenbits, bluebits, alphabits, depthbits, stencilbits; 823 824 if (client == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE) 825 { 826 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, 827 GL_BACK_LEFT, 828 GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, 829 &redbits); 830 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, 831 GL_BACK_LEFT, 832 GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, 833 &greenbits); 834 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, 835 GL_BACK_LEFT, 836 GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, 837 &bluebits); 838 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, 839 GL_BACK_LEFT, 840 GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, 841 &alphabits); 842 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, 843 GL_DEPTH, 844 GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, 845 &depthbits); 846 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, 847 GL_STENCIL, 848 GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, 849 &stencilbits); 850 } 851 else 852 { 853 glGetIntegerv(GL_RED_BITS, &redbits); 854 glGetIntegerv(GL_GREEN_BITS, &greenbits); 855 glGetIntegerv(GL_BLUE_BITS, &bluebits); 856 glGetIntegerv(GL_ALPHA_BITS, &alphabits); 857 glGetIntegerv(GL_DEPTH_BITS, &depthbits); 858 glGetIntegerv(GL_STENCIL_BITS, &stencilbits); 859 } 860 861 printf(" red: %u green: %u blue: %u alpha: %u depth: %u stencil: %u\n", 862 redbits, greenbits, bluebits, alphabits, depthbits, stencilbits); 863 864 if (client == GLFW_OPENGL_ES_API || 865 GLAD_GL_ARB_multisample || 866 major > 1 || minor >= 3) 867 { 868 GLint samples, samplebuffers; 869 glGetIntegerv(GL_SAMPLES, &samples); 870 glGetIntegerv(GL_SAMPLE_BUFFERS, &samplebuffers); 871 872 printf(" samples: %u sample buffers: %u\n", samples, samplebuffers); 873 } 874 875 if (client == GLFW_OPENGL_API && profile != GLFW_OPENGL_CORE_PROFILE) 876 { 877 GLint accumredbits, accumgreenbits, accumbluebits, accumalphabits; 878 GLint auxbuffers; 879 880 glGetIntegerv(GL_ACCUM_RED_BITS, &accumredbits); 881 glGetIntegerv(GL_ACCUM_GREEN_BITS, &accumgreenbits); 882 glGetIntegerv(GL_ACCUM_BLUE_BITS, &accumbluebits); 883 glGetIntegerv(GL_ACCUM_ALPHA_BITS, &accumalphabits); 884 glGetIntegerv(GL_AUX_BUFFERS, &auxbuffers); 885 886 printf(" accum red: %u accum green: %u accum blue: %u accum alpha: %u aux buffers: %u\n", 887 accumredbits, accumgreenbits, accumbluebits, accumalphabits, auxbuffers); 888 } 889 890 if (list_extensions) 891 list_context_extensions(client, major, minor); 892 893 glfwDestroyWindow(window); 894 } 895 896 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 897 898 window = glfwCreateWindow(200, 200, "Version", NULL, NULL); 899 if (!window) 900 { 901 glfwTerminate(); 902 exit(EXIT_FAILURE); 903 } 904 905 printf("Vulkan loader: %s\n", 906 glfwVulkanSupported() ? "available" : "missing"); 907 908 if (glfwVulkanSupported()) 909 { 910 gladLoadVulkanUserPtr(NULL, (GLADuserptrloadfunc) glfwGetInstanceProcAddress, NULL); 911 912 uint32_t loader_version = VK_API_VERSION_1_0; 913 914 if (vkEnumerateInstanceVersion) 915 { 916 uint32_t version; 917 if (vkEnumerateInstanceVersion(&version) == VK_SUCCESS) 918 loader_version = version; 919 } 920 921 printf("Vulkan loader API version: %i.%i\n", 922 VK_VERSION_MAJOR(loader_version), 923 VK_VERSION_MINOR(loader_version)); 924 925 uint32_t glfw_re_count; 926 const char** glfw_re = glfwGetRequiredInstanceExtensions(&glfw_re_count); 927 928 uint32_t re_count = glfw_re_count; 929 const char** re = calloc(glfw_re_count, sizeof(char*)); 930 931 if (glfw_re) 932 { 933 printf("Vulkan window surface required instance extensions:\n"); 934 for (uint32_t i = 0; i < glfw_re_count; i++) 935 { 936 printf(" %s\n", glfw_re[i]); 937 re[i] = glfw_re[i]; 938 } 939 } 940 else 941 printf("Vulkan window surface extensions missing\n"); 942 943 uint32_t ep_count; 944 vkEnumerateInstanceExtensionProperties(NULL, &ep_count, NULL); 945 VkExtensionProperties* ep = calloc(ep_count, sizeof(VkExtensionProperties)); 946 vkEnumerateInstanceExtensionProperties(NULL, &ep_count, ep); 947 948 if (list_extensions) 949 { 950 printf("Vulkan instance extensions:\n"); 951 952 for (uint32_t i = 0; i < ep_count; i++) 953 printf(" %s (spec version %u)\n", ep[i].extensionName, ep[i].specVersion); 954 } 955 956 bool portability_enumeration = false; 957 958 for (uint32_t i = 0; i < ep_count; i++) 959 { 960 if (strcmp(ep[i].extensionName, "VK_KHR_portability_enumeration") != 0) 961 continue; 962 963 re_count++; 964 re = realloc((void*) re, sizeof(char*) * re_count); 965 re[re_count - 1] = "VK_KHR_portability_enumeration"; 966 portability_enumeration = true; 967 } 968 969 free(ep); 970 971 if (list_layers) 972 list_vulkan_instance_layers(); 973 974 VkApplicationInfo ai = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; 975 ai.pApplicationName = "glfwinfo"; 976 ai.applicationVersion = VK_MAKE_VERSION(GLFW_VERSION_MAJOR, 977 GLFW_VERSION_MINOR, 978 GLFW_VERSION_REVISION); 979 980 if (loader_version >= VK_API_VERSION_1_1) 981 ai.apiVersion = VK_API_VERSION_1_1; 982 else 983 ai.apiVersion = VK_API_VERSION_1_0; 984 985 VkInstanceCreateInfo ici = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; 986 ici.pApplicationInfo = &ai; 987 ici.enabledExtensionCount = re_count; 988 ici.ppEnabledExtensionNames = re; 989 990 if (portability_enumeration) 991 ici.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; 992 993 VkInstance instance = VK_NULL_HANDLE; 994 995 if (vkCreateInstance(&ici, NULL, &instance) != VK_SUCCESS) 996 { 997 glfwTerminate(); 998 exit(EXIT_FAILURE); 999 } 1000 1001 free((void*) re); 1002 1003 gladLoadVulkanUserPtr(NULL, (GLADuserptrloadfunc) glfwGetInstanceProcAddress, instance); 1004 1005 if (glfw_re_count) 1006 { 1007 VkSurfaceKHR surface = VK_NULL_HANDLE; 1008 1009 if (glfwCreateWindowSurface(instance, window, NULL, &surface) == VK_SUCCESS) 1010 { 1011 printf("Vulkan window surface created successfully\n"); 1012 vkDestroySurfaceKHR(instance, surface, NULL); 1013 } 1014 else 1015 printf("Failed to create Vulkan window surface\n"); 1016 } 1017 1018 uint32_t pd_count; 1019 vkEnumeratePhysicalDevices(instance, &pd_count, NULL); 1020 VkPhysicalDevice* pd = calloc(pd_count, sizeof(VkPhysicalDevice)); 1021 vkEnumeratePhysicalDevices(instance, &pd_count, pd); 1022 1023 for (uint32_t i = 0; i < pd_count; i++) 1024 { 1025 VkPhysicalDeviceProperties pdp; 1026 vkGetPhysicalDeviceProperties(pd[i], &pdp); 1027 1028 uint32_t qfp_count; 1029 vkGetPhysicalDeviceQueueFamilyProperties(pd[i], &qfp_count, NULL); 1030 1031 uint32_t ep_count; 1032 vkEnumerateDeviceExtensionProperties(pd[i], NULL, &ep_count, NULL); 1033 VkExtensionProperties* ep = calloc(ep_count, sizeof(VkExtensionProperties)); 1034 vkEnumerateDeviceExtensionProperties(pd[i], NULL, &ep_count, ep); 1035 1036 if (portability_enumeration) 1037 { 1038 bool conformant = true; 1039 1040 for (uint32_t j = 0; j < ep_count; j++) 1041 { 1042 if (strcmp(ep[j].extensionName, "VK_KHR_portability_subset") == 0) 1043 { 1044 conformant = false; 1045 break; 1046 } 1047 } 1048 1049 printf("Vulkan %s %s device: \"%s\" (API version %i.%i)\n", 1050 conformant ? "conformant" : "non-conformant", 1051 get_device_type_name(pdp.deviceType), 1052 pdp.deviceName, 1053 VK_VERSION_MAJOR(pdp.apiVersion), 1054 VK_VERSION_MINOR(pdp.apiVersion)); 1055 } 1056 else 1057 { 1058 printf("Vulkan %s device: \"%s\" (API version %i.%i)\n", 1059 get_device_type_name(pdp.deviceType), 1060 pdp.deviceName, 1061 VK_VERSION_MAJOR(pdp.apiVersion), 1062 VK_VERSION_MINOR(pdp.apiVersion)); 1063 } 1064 1065 if (glfw_re_count) 1066 { 1067 printf("Vulkan device queue family presentation support:\n"); 1068 for (uint32_t j = 0; j < qfp_count; j++) 1069 { 1070 printf(" %u: ", j); 1071 if (glfwGetPhysicalDevicePresentationSupport(instance, pd[i], j)) 1072 printf("supported\n"); 1073 else 1074 printf("no\n"); 1075 } 1076 } 1077 1078 if (list_extensions) 1079 { 1080 printf("Vulkan device extensions:\n"); 1081 for (uint32_t j = 0; j < ep_count; j++) 1082 printf(" %s (spec version %u)\n", ep[j].extensionName, ep[j].specVersion); 1083 } 1084 1085 free(ep); 1086 1087 if (list_layers) 1088 list_vulkan_device_layers(instance, pd[i]); 1089 } 1090 1091 free(pd); 1092 vkDestroyInstance(instance, NULL); 1093 } 1094 1095 glfwDestroyWindow(window); 1096 1097 glfwTerminate(); 1098 exit(EXIT_SUCCESS); 1099} 1100 1101