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