xref: /third_party/glfw/tests/glfwinfo.c (revision b877906b)
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