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