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 #include <glad/gl.h>
27 #include <glad/vulkan.h>
28 #include <GLFW/glfw3.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "getopt.h"
35
36 #ifdef _MSC_VER
37 #define strcasecmp(x, y) _stricmp(x, y)
38 #endif
39
40 #define API_NAME_OPENGL "gl"
41 #define API_NAME_OPENGL_ES "es"
42
43 #define API_NAME_NATIVE "native"
44 #define API_NAME_EGL "egl"
45 #define API_NAME_OSMESA "osmesa"
46
47 #define PROFILE_NAME_CORE "core"
48 #define PROFILE_NAME_COMPAT "compat"
49
50 #define STRATEGY_NAME_NONE "none"
51 #define STRATEGY_NAME_LOSE "lose"
52
53 #define BEHAVIOR_NAME_NONE "none"
54 #define BEHAVIOR_NAME_FLUSH "flush"
55
usage(void)56 static void usage(void)
57 {
58 printf("Usage: glfwinfo [OPTION]...\n");
59 printf("Options:\n");
60 printf(" -a, --client-api=API the client API to use ("
61 API_NAME_OPENGL " or "
62 API_NAME_OPENGL_ES ")\n");
63 printf(" -b, --behavior=BEHAVIOR the release behavior to use ("
64 BEHAVIOR_NAME_NONE " or "
65 BEHAVIOR_NAME_FLUSH ")\n");
66 printf(" -c, --context-api=API the context creation API to use ("
67 API_NAME_NATIVE " or "
68 API_NAME_EGL " or "
69 API_NAME_OSMESA ")\n");
70 printf(" -d, --debug request a debug context\n");
71 printf(" -f, --forward require a forward-compatible context\n");
72 printf(" -h, --help show this help\n");
73 printf(" -l, --list-extensions list all Vulkan and client API extensions\n");
74 printf(" --list-layers list all Vulkan layers\n");
75 printf(" -m, --major=MAJOR the major number of the required "
76 "client API version\n");
77 printf(" -n, --minor=MINOR the minor number of the required "
78 "client API version\n");
79 printf(" -p, --profile=PROFILE the OpenGL profile to use ("
80 PROFILE_NAME_CORE " or "
81 PROFILE_NAME_COMPAT ")\n");
82 printf(" -s, --robustness=STRATEGY the robustness strategy to use ("
83 STRATEGY_NAME_NONE " or "
84 STRATEGY_NAME_LOSE ")\n");
85 printf(" -v, --version print version information\n");
86 printf(" --red-bits=N the number of red bits to request\n");
87 printf(" --green-bits=N the number of green bits to request\n");
88 printf(" --blue-bits=N the number of blue bits to request\n");
89 printf(" --alpha-bits=N the number of alpha bits to request\n");
90 printf(" --depth-bits=N the number of depth bits to request\n");
91 printf(" --stencil-bits=N the number of stencil bits to request\n");
92 printf(" --accum-red-bits=N the number of red bits to request\n");
93 printf(" --accum-green-bits=N the number of green bits to request\n");
94 printf(" --accum-blue-bits=N the number of blue bits to request\n");
95 printf(" --accum-alpha-bits=N the number of alpha bits to request\n");
96 printf(" --aux-buffers=N the number of aux buffers to request\n");
97 printf(" --samples=N the number of MSAA samples to request\n");
98 printf(" --stereo request stereo rendering\n");
99 printf(" --srgb request an sRGB capable framebuffer\n");
100 printf(" --singlebuffer request single-buffering\n");
101 printf(" --no-error request a context that does not emit errors\n");
102 printf(" --graphics-switching request macOS graphics switching\n");
103 }
104
error_callback(int error,const char * description)105 static void error_callback(int error, const char* description)
106 {
107 fprintf(stderr, "Error: %s\n", description);
108 }
109
get_device_type_name(VkPhysicalDeviceType type)110 static const char* get_device_type_name(VkPhysicalDeviceType type)
111 {
112 if (type == VK_PHYSICAL_DEVICE_TYPE_OTHER)
113 return "other";
114 else if (type == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
115 return "integrated GPU";
116 else if (type == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
117 return "discrete GPU";
118 else if (type == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
119 return "virtual GPU";
120 else if (type == VK_PHYSICAL_DEVICE_TYPE_CPU)
121 return "CPU";
122
123 return "unknown";
124 }
125
get_api_name(int api)126 static const char* get_api_name(int api)
127 {
128 if (api == GLFW_OPENGL_API)
129 return "OpenGL";
130 else if (api == GLFW_OPENGL_ES_API)
131 return "OpenGL ES";
132
133 return "Unknown API";
134 }
135
get_profile_name_gl(GLint mask)136 static const char* get_profile_name_gl(GLint mask)
137 {
138 if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
139 return PROFILE_NAME_COMPAT;
140 if (mask & GL_CONTEXT_CORE_PROFILE_BIT)
141 return PROFILE_NAME_CORE;
142
143 return "unknown";
144 }
145
get_profile_name_glfw(int profile)146 static const char* get_profile_name_glfw(int profile)
147 {
148 if (profile == GLFW_OPENGL_COMPAT_PROFILE)
149 return PROFILE_NAME_COMPAT;
150 if (profile == GLFW_OPENGL_CORE_PROFILE)
151 return PROFILE_NAME_CORE;
152
153 return "unknown";
154 }
155
get_strategy_name_gl(GLint strategy)156 static const char* get_strategy_name_gl(GLint strategy)
157 {
158 if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
159 return STRATEGY_NAME_LOSE;
160 if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
161 return STRATEGY_NAME_NONE;
162
163 return "unknown";
164 }
165
get_strategy_name_glfw(int strategy)166 static const char* get_strategy_name_glfw(int strategy)
167 {
168 if (strategy == GLFW_LOSE_CONTEXT_ON_RESET)
169 return STRATEGY_NAME_LOSE;
170 if (strategy == GLFW_NO_RESET_NOTIFICATION)
171 return STRATEGY_NAME_NONE;
172
173 return "unknown";
174 }
175
list_context_extensions(int client,int major,int minor)176 static void list_context_extensions(int client, int major, int minor)
177 {
178 int i;
179 GLint count;
180 const GLubyte* extensions;
181
182 printf("%s context extensions:\n", get_api_name(client));
183
184 if (client == GLFW_OPENGL_API && major > 2)
185 {
186 glGetIntegerv(GL_NUM_EXTENSIONS, &count);
187
188 for (i = 0; i < count; i++)
189 printf(" %s\n", (const char*) glGetStringi(GL_EXTENSIONS, i));
190 }
191 else
192 {
193 extensions = glGetString(GL_EXTENSIONS);
194 while (*extensions != '\0')
195 {
196 putchar(' ');
197
198 while (*extensions != '\0' && *extensions != ' ')
199 {
200 putchar(*extensions);
201 extensions++;
202 }
203
204 while (*extensions == ' ')
205 extensions++;
206
207 putchar('\n');
208 }
209 }
210 }
211
list_vulkan_instance_extensions(void)212 static void list_vulkan_instance_extensions(void)
213 {
214 uint32_t i, ep_count = 0;
215 VkExtensionProperties* ep;
216
217 printf("Vulkan instance extensions:\n");
218
219 if (vkEnumerateInstanceExtensionProperties(NULL, &ep_count, NULL) != VK_SUCCESS)
220 return;
221
222 ep = calloc(ep_count, sizeof(VkExtensionProperties));
223
224 if (vkEnumerateInstanceExtensionProperties(NULL, &ep_count, ep) != VK_SUCCESS)
225 {
226 free(ep);
227 return;
228 }
229
230 for (i = 0; i < ep_count; i++)
231 printf(" %s (v%u)\n", ep[i].extensionName, ep[i].specVersion);
232
233 free(ep);
234 }
235
list_vulkan_instance_layers(void)236 static void list_vulkan_instance_layers(void)
237 {
238 uint32_t i, lp_count = 0;
239 VkLayerProperties* lp;
240
241 printf("Vulkan instance layers:\n");
242
243 if (vkEnumerateInstanceLayerProperties(&lp_count, NULL) != VK_SUCCESS)
244 return;
245
246 lp = calloc(lp_count, sizeof(VkLayerProperties));
247
248 if (vkEnumerateInstanceLayerProperties(&lp_count, lp) != VK_SUCCESS)
249 {
250 free(lp);
251 return;
252 }
253
254 for (i = 0; i < lp_count; i++)
255 {
256 printf(" %s (v%u) \"%s\"\n",
257 lp[i].layerName,
258 lp[i].specVersion >> 22,
259 lp[i].description);
260 }
261
262 free(lp);
263 }
264
list_vulkan_device_extensions(VkInstance instance,VkPhysicalDevice device)265 static void list_vulkan_device_extensions(VkInstance instance, VkPhysicalDevice device)
266 {
267 uint32_t i, ep_count;
268 VkExtensionProperties* ep;
269
270 printf("Vulkan device extensions:\n");
271
272 if (vkEnumerateDeviceExtensionProperties(device, NULL, &ep_count, NULL) != VK_SUCCESS)
273 return;
274
275 ep = calloc(ep_count, sizeof(VkExtensionProperties));
276
277 if (vkEnumerateDeviceExtensionProperties(device, NULL, &ep_count, ep) != VK_SUCCESS)
278 {
279 free(ep);
280 return;
281 }
282
283 for (i = 0; i < ep_count; i++)
284 printf(" %s (v%u)\n", ep[i].extensionName, ep[i].specVersion);
285
286 free(ep);
287 }
288
list_vulkan_device_layers(VkInstance instance,VkPhysicalDevice device)289 static void list_vulkan_device_layers(VkInstance instance, VkPhysicalDevice device)
290 {
291 uint32_t i, lp_count;
292 VkLayerProperties* lp;
293
294 printf("Vulkan device layers:\n");
295
296 if (vkEnumerateDeviceLayerProperties(device, &lp_count, NULL) != VK_SUCCESS)
297 return;
298
299 lp = calloc(lp_count, sizeof(VkLayerProperties));
300
301 if (vkEnumerateDeviceLayerProperties(device, &lp_count, lp) != VK_SUCCESS)
302 {
303 free(lp);
304 return;
305 }
306
307 for (i = 0; i < lp_count; i++)
308 {
309 printf(" %s (v%u) \"%s\"\n",
310 lp[i].layerName,
311 lp[i].specVersion >> 22,
312 lp[i].description);
313 }
314
315 free(lp);
316 }
317
valid_version(void)318 static int valid_version(void)
319 {
320 int major, minor, revision;
321 glfwGetVersion(&major, &minor, &revision);
322
323 if (major != GLFW_VERSION_MAJOR)
324 {
325 printf("*** ERROR: GLFW major version mismatch! ***\n");
326 return GLFW_FALSE;
327 }
328
329 if (minor != GLFW_VERSION_MINOR || revision != GLFW_VERSION_REVISION)
330 printf("*** WARNING: GLFW version mismatch! ***\n");
331
332 return GLFW_TRUE;
333 }
334
print_version(void)335 static void print_version(void)
336 {
337 int major, minor, revision;
338 glfwGetVersion(&major, &minor, &revision);
339
340 printf("GLFW header version: %u.%u.%u\n",
341 GLFW_VERSION_MAJOR,
342 GLFW_VERSION_MINOR,
343 GLFW_VERSION_REVISION);
344 printf("GLFW library version: %u.%u.%u\n", major, minor, revision);
345 printf("GLFW library version string: \"%s\"\n", glfwGetVersionString());
346 }
347
glad_vulkan_callback(const char * name,void * user)348 static GLADapiproc glad_vulkan_callback(const char* name, void* user)
349 {
350 return glfwGetInstanceProcAddress((VkInstance) user, name);
351 }
352
main(int argc,char ** argv)353 int main(int argc, char** argv)
354 {
355 int ch, client, major, minor, revision, profile;
356 GLint redbits, greenbits, bluebits, alphabits, depthbits, stencilbits;
357 int list_extensions = GLFW_FALSE, list_layers = GLFW_FALSE;
358 GLenum error;
359 GLFWwindow* window;
360
361 enum { CLIENT, CONTEXT, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS,
362 MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION,
363 REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS,
364 ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS,
365 AUXBUFFERS, SAMPLES, STEREO, SRGB, SINGLEBUFFER, NOERROR_SRSLY,
366 GRAPHICS_SWITCHING };
367 const struct option options[] =
368 {
369 { "behavior", 1, NULL, BEHAVIOR },
370 { "client-api", 1, NULL, CLIENT },
371 { "context-api", 1, NULL, CONTEXT },
372 { "debug", 0, NULL, DEBUG },
373 { "forward", 0, NULL, FORWARD },
374 { "help", 0, NULL, HELP },
375 { "list-extensions", 0, NULL, EXTENSIONS },
376 { "list-layers", 0, NULL, LAYERS },
377 { "major", 1, NULL, MAJOR },
378 { "minor", 1, NULL, MINOR },
379 { "profile", 1, NULL, PROFILE },
380 { "robustness", 1, NULL, ROBUSTNESS },
381 { "version", 0, NULL, VERSION },
382 { "red-bits", 1, NULL, REDBITS },
383 { "green-bits", 1, NULL, GREENBITS },
384 { "blue-bits", 1, NULL, BLUEBITS },
385 { "alpha-bits", 1, NULL, ALPHABITS },
386 { "depth-bits", 1, NULL, DEPTHBITS },
387 { "stencil-bits", 1, NULL, STENCILBITS },
388 { "accum-red-bits", 1, NULL, ACCUMREDBITS },
389 { "accum-green-bits", 1, NULL, ACCUMGREENBITS },
390 { "accum-blue-bits", 1, NULL, ACCUMBLUEBITS },
391 { "accum-alpha-bits", 1, NULL, ACCUMALPHABITS },
392 { "aux-buffers", 1, NULL, AUXBUFFERS },
393 { "samples", 1, NULL, SAMPLES },
394 { "stereo", 0, NULL, STEREO },
395 { "srgb", 0, NULL, SRGB },
396 { "singlebuffer", 0, NULL, SINGLEBUFFER },
397 { "no-error", 0, NULL, NOERROR_SRSLY },
398 { "graphics-switching", 0, NULL, GRAPHICS_SWITCHING },
399 { NULL, 0, NULL, 0 }
400 };
401
402 // Initialize GLFW and create window
403
404 if (!valid_version())
405 exit(EXIT_FAILURE);
406
407 glfwSetErrorCallback(error_callback);
408
409 glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_FALSE);
410
411 if (!glfwInit())
412 exit(EXIT_FAILURE);
413
414 while ((ch = getopt_long(argc, argv, "a:b:c:dfhlm:n:p:s:v", options, NULL)) != -1)
415 {
416 switch (ch)
417 {
418 case 'a':
419 case CLIENT:
420 if (strcasecmp(optarg, API_NAME_OPENGL) == 0)
421 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
422 else if (strcasecmp(optarg, API_NAME_OPENGL_ES) == 0)
423 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
424 else
425 {
426 usage();
427 exit(EXIT_FAILURE);
428 }
429 break;
430 case 'b':
431 case BEHAVIOR:
432 if (strcasecmp(optarg, BEHAVIOR_NAME_NONE) == 0)
433 {
434 glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR,
435 GLFW_RELEASE_BEHAVIOR_NONE);
436 }
437 else if (strcasecmp(optarg, BEHAVIOR_NAME_FLUSH) == 0)
438 {
439 glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR,
440 GLFW_RELEASE_BEHAVIOR_FLUSH);
441 }
442 else
443 {
444 usage();
445 exit(EXIT_FAILURE);
446 }
447 break;
448 case 'c':
449 case CONTEXT:
450 if (strcasecmp(optarg, API_NAME_NATIVE) == 0)
451 glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
452 else if (strcasecmp(optarg, API_NAME_EGL) == 0)
453 glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
454 else if (strcasecmp(optarg, API_NAME_OSMESA) == 0)
455 glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_OSMESA_CONTEXT_API);
456 else
457 {
458 usage();
459 exit(EXIT_FAILURE);
460 }
461 break;
462 case 'd':
463 case DEBUG:
464 glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
465 break;
466 case 'f':
467 case FORWARD:
468 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
469 break;
470 case 'h':
471 case HELP:
472 usage();
473 exit(EXIT_SUCCESS);
474 case 'l':
475 case EXTENSIONS:
476 list_extensions = GLFW_TRUE;
477 break;
478 case LAYERS:
479 list_layers = GLFW_TRUE;
480 break;
481 case 'm':
482 case MAJOR:
483 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, atoi(optarg));
484 break;
485 case 'n':
486 case MINOR:
487 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, atoi(optarg));
488 break;
489 case 'p':
490 case PROFILE:
491 if (strcasecmp(optarg, PROFILE_NAME_CORE) == 0)
492 {
493 glfwWindowHint(GLFW_OPENGL_PROFILE,
494 GLFW_OPENGL_CORE_PROFILE);
495 }
496 else if (strcasecmp(optarg, PROFILE_NAME_COMPAT) == 0)
497 {
498 glfwWindowHint(GLFW_OPENGL_PROFILE,
499 GLFW_OPENGL_COMPAT_PROFILE);
500 }
501 else
502 {
503 usage();
504 exit(EXIT_FAILURE);
505 }
506 break;
507 case 's':
508 case ROBUSTNESS:
509 if (strcasecmp(optarg, STRATEGY_NAME_NONE) == 0)
510 {
511 glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS,
512 GLFW_NO_RESET_NOTIFICATION);
513 }
514 else if (strcasecmp(optarg, STRATEGY_NAME_LOSE) == 0)
515 {
516 glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS,
517 GLFW_LOSE_CONTEXT_ON_RESET);
518 }
519 else
520 {
521 usage();
522 exit(EXIT_FAILURE);
523 }
524 break;
525 case 'v':
526 case VERSION:
527 print_version();
528 exit(EXIT_SUCCESS);
529 case REDBITS:
530 if (strcmp(optarg, "-") == 0)
531 glfwWindowHint(GLFW_RED_BITS, GLFW_DONT_CARE);
532 else
533 glfwWindowHint(GLFW_RED_BITS, atoi(optarg));
534 break;
535 case GREENBITS:
536 if (strcmp(optarg, "-") == 0)
537 glfwWindowHint(GLFW_GREEN_BITS, GLFW_DONT_CARE);
538 else
539 glfwWindowHint(GLFW_GREEN_BITS, atoi(optarg));
540 break;
541 case BLUEBITS:
542 if (strcmp(optarg, "-") == 0)
543 glfwWindowHint(GLFW_BLUE_BITS, GLFW_DONT_CARE);
544 else
545 glfwWindowHint(GLFW_BLUE_BITS, atoi(optarg));
546 break;
547 case ALPHABITS:
548 if (strcmp(optarg, "-") == 0)
549 glfwWindowHint(GLFW_ALPHA_BITS, GLFW_DONT_CARE);
550 else
551 glfwWindowHint(GLFW_ALPHA_BITS, atoi(optarg));
552 break;
553 case DEPTHBITS:
554 if (strcmp(optarg, "-") == 0)
555 glfwWindowHint(GLFW_DEPTH_BITS, GLFW_DONT_CARE);
556 else
557 glfwWindowHint(GLFW_DEPTH_BITS, atoi(optarg));
558 break;
559 case STENCILBITS:
560 if (strcmp(optarg, "-") == 0)
561 glfwWindowHint(GLFW_STENCIL_BITS, GLFW_DONT_CARE);
562 else
563 glfwWindowHint(GLFW_STENCIL_BITS, atoi(optarg));
564 break;
565 case ACCUMREDBITS:
566 if (strcmp(optarg, "-") == 0)
567 glfwWindowHint(GLFW_ACCUM_RED_BITS, GLFW_DONT_CARE);
568 else
569 glfwWindowHint(GLFW_ACCUM_RED_BITS, atoi(optarg));
570 break;
571 case ACCUMGREENBITS:
572 if (strcmp(optarg, "-") == 0)
573 glfwWindowHint(GLFW_ACCUM_GREEN_BITS, GLFW_DONT_CARE);
574 else
575 glfwWindowHint(GLFW_ACCUM_GREEN_BITS, atoi(optarg));
576 break;
577 case ACCUMBLUEBITS:
578 if (strcmp(optarg, "-") == 0)
579 glfwWindowHint(GLFW_ACCUM_BLUE_BITS, GLFW_DONT_CARE);
580 else
581 glfwWindowHint(GLFW_ACCUM_BLUE_BITS, atoi(optarg));
582 break;
583 case ACCUMALPHABITS:
584 if (strcmp(optarg, "-") == 0)
585 glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, GLFW_DONT_CARE);
586 else
587 glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, atoi(optarg));
588 break;
589 case AUXBUFFERS:
590 if (strcmp(optarg, "-") == 0)
591 glfwWindowHint(GLFW_AUX_BUFFERS, GLFW_DONT_CARE);
592 else
593 glfwWindowHint(GLFW_AUX_BUFFERS, atoi(optarg));
594 break;
595 case SAMPLES:
596 if (strcmp(optarg, "-") == 0)
597 glfwWindowHint(GLFW_SAMPLES, GLFW_DONT_CARE);
598 else
599 glfwWindowHint(GLFW_SAMPLES, atoi(optarg));
600 break;
601 case STEREO:
602 glfwWindowHint(GLFW_STEREO, GLFW_TRUE);
603 break;
604 case SRGB:
605 glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE);
606 break;
607 case SINGLEBUFFER:
608 glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_FALSE);
609 break;
610 case NOERROR_SRSLY:
611 glfwWindowHint(GLFW_CONTEXT_NO_ERROR, GLFW_TRUE);
612 break;
613 case GRAPHICS_SWITCHING:
614 glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GLFW_TRUE);
615 break;
616 default:
617 usage();
618 exit(EXIT_FAILURE);
619 }
620 }
621
622 print_version();
623
624 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
625
626 window = glfwCreateWindow(200, 200, "Version", NULL, NULL);
627 if (!window)
628 {
629 glfwTerminate();
630 exit(EXIT_FAILURE);
631 }
632
633 glfwMakeContextCurrent(window);
634 gladLoadGL(glfwGetProcAddress);
635
636 error = glGetError();
637 if (error != GL_NO_ERROR)
638 printf("*** OpenGL error after make current: 0x%08x ***\n", error);
639
640 // Report client API version
641
642 client = glfwGetWindowAttrib(window, GLFW_CLIENT_API);
643 major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
644 minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
645 revision = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
646 profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE);
647
648 printf("%s context version string: \"%s\"\n",
649 get_api_name(client),
650 glGetString(GL_VERSION));
651
652 printf("%s context version parsed by GLFW: %u.%u.%u\n",
653 get_api_name(client),
654 major, minor, revision);
655
656 // Report client API context properties
657
658 if (client == GLFW_OPENGL_API)
659 {
660 if (major >= 3)
661 {
662 GLint flags;
663
664 glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
665 printf("%s context flags (0x%08x):", get_api_name(client), flags);
666
667 if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
668 printf(" forward-compatible");
669 if (flags & 2/*GL_CONTEXT_FLAG_DEBUG_BIT*/)
670 printf(" debug");
671 if (flags & GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB)
672 printf(" robustness");
673 if (flags & 8/*GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR*/)
674 printf(" no-error");
675 putchar('\n');
676
677 printf("%s context flags parsed by GLFW:", get_api_name(client));
678
679 if (glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT))
680 printf(" forward-compatible");
681 if (glfwGetWindowAttrib(window, GLFW_OPENGL_DEBUG_CONTEXT))
682 printf(" debug");
683 if (glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS) == GLFW_LOSE_CONTEXT_ON_RESET)
684 printf(" robustness");
685 if (glfwGetWindowAttrib(window, GLFW_CONTEXT_NO_ERROR))
686 printf(" no-error");
687 putchar('\n');
688 }
689
690 if (major >= 4 || (major == 3 && minor >= 2))
691 {
692 GLint mask;
693 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
694
695 printf("%s profile mask (0x%08x): %s\n",
696 get_api_name(client),
697 mask,
698 get_profile_name_gl(mask));
699
700 printf("%s profile mask parsed by GLFW: %s\n",
701 get_api_name(client),
702 get_profile_name_glfw(profile));
703 }
704
705 if (GLAD_GL_ARB_robustness)
706 {
707 const int robustness = glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS);
708 GLint strategy;
709 glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
710
711 printf("%s robustness strategy (0x%08x): %s\n",
712 get_api_name(client),
713 strategy,
714 get_strategy_name_gl(strategy));
715
716 printf("%s robustness strategy parsed by GLFW: %s\n",
717 get_api_name(client),
718 get_strategy_name_glfw(robustness));
719 }
720 }
721
722 printf("%s context renderer string: \"%s\"\n",
723 get_api_name(client),
724 glGetString(GL_RENDERER));
725 printf("%s context vendor string: \"%s\"\n",
726 get_api_name(client),
727 glGetString(GL_VENDOR));
728
729 if (major >= 2)
730 {
731 printf("%s context shading language version: \"%s\"\n",
732 get_api_name(client),
733 glGetString(GL_SHADING_LANGUAGE_VERSION));
734 }
735
736 printf("%s framebuffer:\n", get_api_name(client));
737
738 if (client == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE)
739 {
740 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
741 GL_BACK_LEFT,
742 GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE,
743 &redbits);
744 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
745 GL_BACK_LEFT,
746 GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
747 &greenbits);
748 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
749 GL_BACK_LEFT,
750 GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
751 &bluebits);
752 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
753 GL_BACK_LEFT,
754 GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
755 &alphabits);
756 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
757 GL_DEPTH,
758 GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
759 &depthbits);
760 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
761 GL_STENCIL,
762 GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
763 &stencilbits);
764 }
765 else
766 {
767 glGetIntegerv(GL_RED_BITS, &redbits);
768 glGetIntegerv(GL_GREEN_BITS, &greenbits);
769 glGetIntegerv(GL_BLUE_BITS, &bluebits);
770 glGetIntegerv(GL_ALPHA_BITS, &alphabits);
771 glGetIntegerv(GL_DEPTH_BITS, &depthbits);
772 glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
773 }
774
775 printf(" red: %u green: %u blue: %u alpha: %u depth: %u stencil: %u\n",
776 redbits, greenbits, bluebits, alphabits, depthbits, stencilbits);
777
778 if (client == GLFW_OPENGL_ES_API ||
779 GLAD_GL_ARB_multisample ||
780 major > 1 || minor >= 3)
781 {
782 GLint samples, samplebuffers;
783 glGetIntegerv(GL_SAMPLES, &samples);
784 glGetIntegerv(GL_SAMPLE_BUFFERS, &samplebuffers);
785
786 printf(" samples: %u sample buffers: %u\n", samples, samplebuffers);
787 }
788
789 if (client == GLFW_OPENGL_API && profile != GLFW_OPENGL_CORE_PROFILE)
790 {
791 GLint accumredbits, accumgreenbits, accumbluebits, accumalphabits;
792 GLint auxbuffers;
793
794 glGetIntegerv(GL_ACCUM_RED_BITS, &accumredbits);
795 glGetIntegerv(GL_ACCUM_GREEN_BITS, &accumgreenbits);
796 glGetIntegerv(GL_ACCUM_BLUE_BITS, &accumbluebits);
797 glGetIntegerv(GL_ACCUM_ALPHA_BITS, &accumalphabits);
798 glGetIntegerv(GL_AUX_BUFFERS, &auxbuffers);
799
800 printf(" accum red: %u accum green: %u accum blue: %u accum alpha: %u aux buffers: %u\n",
801 accumredbits, accumgreenbits, accumbluebits, accumalphabits, auxbuffers);
802 }
803
804 if (list_extensions)
805 list_context_extensions(client, major, minor);
806
807 printf("Vulkan loader: %s\n",
808 glfwVulkanSupported() ? "available" : "missing");
809
810 if (glfwVulkanSupported())
811 {
812 uint32_t i, re_count, pd_count;
813 const char** re;
814 VkApplicationInfo ai = {0};
815 VkInstanceCreateInfo ici = {0};
816 VkInstance instance;
817 VkPhysicalDevice* pd;
818
819 gladLoadVulkanUserPtr(NULL, glad_vulkan_callback, NULL);
820
821 re = glfwGetRequiredInstanceExtensions(&re_count);
822
823 printf("Vulkan required instance extensions:");
824 if (re)
825 {
826 for (i = 0; i < re_count; i++)
827 printf(" %s", re[i]);
828 putchar('\n');
829 }
830 else
831 printf(" missing\n");
832
833 if (list_extensions)
834 list_vulkan_instance_extensions();
835
836 if (list_layers)
837 list_vulkan_instance_layers();
838
839 ai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
840 ai.pApplicationName = "glfwinfo";
841 ai.applicationVersion = GLFW_VERSION_MAJOR;
842 ai.pEngineName = "GLFW";
843 ai.engineVersion = GLFW_VERSION_MAJOR;
844 ai.apiVersion = VK_API_VERSION_1_0;
845
846 ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
847 ici.pApplicationInfo = &ai;
848 ici.enabledExtensionCount = re_count;
849 ici.ppEnabledExtensionNames = re;
850
851 if (vkCreateInstance(&ici, NULL, &instance) != VK_SUCCESS)
852 {
853 glfwTerminate();
854 exit(EXIT_FAILURE);
855 }
856
857 gladLoadVulkanUserPtr(NULL, glad_vulkan_callback, instance);
858
859 if (vkEnumeratePhysicalDevices(instance, &pd_count, NULL) != VK_SUCCESS)
860 {
861 vkDestroyInstance(instance, NULL);
862 glfwTerminate();
863 exit(EXIT_FAILURE);
864 }
865
866 pd = calloc(pd_count, sizeof(VkPhysicalDevice));
867
868 if (vkEnumeratePhysicalDevices(instance, &pd_count, pd) != VK_SUCCESS)
869 {
870 free(pd);
871 vkDestroyInstance(instance, NULL);
872 glfwTerminate();
873 exit(EXIT_FAILURE);
874 }
875
876 for (i = 0; i < pd_count; i++)
877 {
878 VkPhysicalDeviceProperties pdp;
879
880 vkGetPhysicalDeviceProperties(pd[i], &pdp);
881
882 printf("Vulkan %s device: \"%s\"\n",
883 get_device_type_name(pdp.deviceType),
884 pdp.deviceName);
885
886 if (list_extensions)
887 list_vulkan_device_extensions(instance, pd[i]);
888
889 if (list_layers)
890 list_vulkan_device_layers(instance, pd[i]);
891 }
892
893 free(pd);
894 vkDestroyInstance(instance, NULL);
895 }
896
897 glfwTerminate();
898 exit(EXIT_SUCCESS);
899 }
900
901