[waffle] [PATCH v3 1/3] waffle utils: add wflinfo utility

Jordan Justen jordan.l.justen at intel.com
Mon Jan 13 16:55:39 PST 2014


glxinfo for waffle, but using the command line interface
of waffle's gl_basic test.

v2:
 * Various cleanups suggested by Chad
 * Print context flags rather than verifying them.
 * Only print extensions when --verbose is used

v3:
 * "GL ERROR" => "WFLINFO_GL_ERROR"
 * print_extensions: fix cases that did not print a newline
 * In print_context_flags:
   - print WFLINFO_GL_ERROR when there is an error
   - print 0x0 rather than (none)
 * print vendor/renderer/version/context flags before checking
   for GetStringi
 * Add 'Waffle platform' and 'Waffle api' output
 * Change --debug to --debug-context

Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
---
 .gitignore               |   1 +
 src/CMakeLists.txt       |   1 +
 src/utils/CMakeLists.txt |  20 ++
 src/utils/wflinfo.c      | 734 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 756 insertions(+)
 create mode 100644 src/utils/CMakeLists.txt
 create mode 100644 src/utils/wflinfo.c

diff --git a/.gitignore b/.gitignore
index 56623a1..9d274bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,7 @@ Makefile
 
 *.so
 
+/bin/wflinfo
 /doc/html/man/waffle.7.html
 /doc/html/man/waffle_attrib_list.3.html
 /doc/html/man/waffle_config.3.html
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 661bdd7..aa6d3c3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,4 +2,5 @@ if(waffle_build_tests)
     add_subdirectory(waffle_test)
 endif()
 
+add_subdirectory(utils)
 add_subdirectory(waffle)
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
new file mode 100644
index 0000000..26b777a
--- /dev/null
+++ b/src/utils/CMakeLists.txt
@@ -0,0 +1,20 @@
+
+# ----------------------------------------------------------------------------
+# Target: wflinfo (executable)
+# ----------------------------------------------------------------------------
+
+add_executable(wflinfo wflinfo.c)
+target_link_libraries(wflinfo ${waffle_libname})
+set_target_properties(wflinfo
+    PROPERTIES
+        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+        )
+
+if(waffle_on_mac)
+    set_target_properties(wflinfo
+        PROPERTIES
+        COMPILE_FLAGS "-ObjC"
+        )
+endif()
+
+install(TARGETS wflinfo DESTINATION bin)
diff --git a/src/utils/wflinfo.c b/src/utils/wflinfo.c
new file mode 100644
index 0000000..1257666
--- /dev/null
+++ b/src/utils/wflinfo.c
@@ -0,0 +1,734 @@
+// Copyright 2014 Intel Corporation
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/// @file wflinfo.c
+/// @brief Print GL info using Waffle.
+///
+/// This program does the following:
+///     1. Dynamically choose the platform and GL API according to command
+///        line arguments.
+///     2. Create a GL context.
+///     3. Print information about the context.
+
+#define WAFFLE_API_VERSION 0x0103
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __APPLE__
+#    import <Foundation/NSAutoreleasePool.h>
+#    import <Appkit/NSApplication.h>
+
+static void
+removeXcodeArgs(int *argc, char **argv);
+#endif
+
+#include "waffle.h"
+
+static const char *usage_message =
+    "usage:\n"
+    "    wflinfo --platform=android|cgl|gbm|glx|wayland|x11_egl\n"
+    "             --api=gl|gles1|gles2|gles3\n"
+    "             [--version=MAJOR.MINOR]\n"
+    "             [--profile=core|compat|none]\n"
+    "             [--forward-compatible]\n"
+    "             [--debug-context]\n"
+    "             [--verbose]\n"
+    "\n"
+    "examples:\n"
+    "    wflinfo --platform=glx --api=gl\n"
+    "    wflinfo --platform=x11_egl --api=gl --version=3.2 --profile=core\n"
+    "    wflinfo --platform=wayland --api=gles3\n"
+    "\n"
+    "description:\n"
+    "    Create an OpenGL or OpenGL ES context and print information about it.\n"
+    "\n"
+    "options:\n"
+    "    --verbose\n"
+    "        Print more information.\n"
+    "\n"
+    "    --forward-compatible\n"
+    "        Create a forward-compatible context.\n"
+    "\n"
+    "    --debug-context\n"
+    "        Create a debug context.\n"
+    ;
+
+enum {
+    OPT_PLATFORM = 1,
+    OPT_API,
+    OPT_VERSION,
+    OPT_PROFILE,
+    OPT_VERBOSE,
+    OPT_DEBUG_CONTEXT,
+    OPT_FORWARD_COMPATIBLE,
+};
+
+static const struct option get_opts[] = {
+    { .name = "platform",       .has_arg = required_argument,     .val = OPT_PLATFORM },
+    { .name = "api",            .has_arg = required_argument,     .val = OPT_API },
+    { .name = "version",        .has_arg = required_argument,     .val = OPT_VERSION },
+    { .name = "profile",        .has_arg = required_argument,     .val = OPT_PROFILE },
+    { .name = "verbose",        .has_arg = no_argument,           .val = OPT_VERBOSE },
+    { .name = "debug-context",  .has_arg = no_argument,           .val = OPT_DEBUG_CONTEXT },
+    { .name = "forward-compatible", .has_arg = no_argument,       .val = OPT_FORWARD_COMPATIBLE },
+    { 0 },
+};
+
+/// @defgroup Error handlers
+/// @{
+///
+/// All error handlers exit.
+///
+
+static void __attribute__((noreturn))
+error_printf(const char *fmt, ...)
+{
+    va_list ap;
+
+    fflush(stdout);
+
+    va_start(ap, fmt);
+    fprintf(stderr, "wflinfo: error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+
+    exit(EXIT_FAILURE);
+}
+static void __attribute__((noreturn))
+usage_error_printf(const char *fmt, ...)
+{
+    fflush(stdout);
+    fprintf(stderr, "wflinfo: usage error");
+
+    if (fmt) {
+        va_list ap;
+        va_start(ap, fmt);
+        fprintf(stderr, ": ");
+        vfprintf(stderr, fmt, ap);
+        va_end(ap);
+    }
+
+    fprintf(stderr, "\n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "%s", usage_message);
+
+    exit(EXIT_FAILURE);
+}
+
+static void
+error_waffle(void)
+{
+    const struct waffle_error_info *info = waffle_error_get_info();
+    const char *code = waffle_error_to_string(info->code);
+
+    if (info->message_length > 0)
+        error_printf("%s: %s", code, info->message);
+    else
+        error_printf("%s", code);
+}
+
+static void
+error_get_gl_symbol(const char *name)
+{
+    error_printf("failed to get function pointer for %s", name);
+}
+
+/// @}
+/// @defgroup GL decalrations
+/// @{
+
+typedef float GLclampf;
+typedef unsigned int GLbitfield;
+typedef unsigned int GLint;
+typedef int GLsizei;
+typedef unsigned int GLenum;
+typedef void GLvoid;
+typedef unsigned char GLubyte;
+
+enum {
+    // Copied from <GL/gl*.h>.
+    GL_NO_ERROR = 0,
+
+    GL_CONTEXT_FLAGS = 0x821e,
+    GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = 0x00000001,
+    GL_CONTEXT_FLAG_DEBUG_BIT              = 0x00000002,
+    GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB  = 0x00000004,
+
+    GL_VENDOR                              = 0x1F00,
+    GL_RENDERER                            = 0x1F01,
+    GL_VERSION                             = 0x1F02,
+    GL_EXTENSIONS                          = 0x1F03,
+    GL_NUM_EXTENSIONS                      = 0x821D,
+};
+
+#define WINDOW_WIDTH  320
+#define WINDOW_HEIGHT 240
+
+static GLenum (*glGetError)(void);
+static void (*glGetIntegerv)(GLenum pname, GLint *params);
+static const GLubyte * (*glGetString)(GLenum name);
+static const GLubyte * (*glGetStringi)(GLenum name, GLint i);
+
+/// @}
+/// @defgroup Parsing Options
+/// @{
+
+struct options {
+    /// @brief One of `WAFFLE_PLATFORM_*`.
+    int platform;
+
+    /// @brief One of `WAFFLE_CONTEXT_OPENGL_*`.
+    int context_api;
+
+    /// @brief One of `WAFFLE_CONTEXT_PROFILE_*` or `WAFFLE_NONE`.
+    int context_profile;
+
+    int context_version;
+
+    bool verbose;
+
+    bool context_forward_compatible;
+    bool context_debug;
+
+    /// @brief One of `WAFFLE_DL_*`.
+    int dl;
+};
+
+struct enum_map {
+    int i;
+    const char *s;
+};
+
+static const struct enum_map platform_map[] = {
+    {WAFFLE_PLATFORM_ANDROID,   "android"       },
+    {WAFFLE_PLATFORM_CGL,       "cgl",          },
+    {WAFFLE_PLATFORM_GBM,       "gbm"           },
+    {WAFFLE_PLATFORM_GLX,       "glx"           },
+    {WAFFLE_PLATFORM_WAYLAND,   "wayland"       },
+    {WAFFLE_PLATFORM_X11_EGL,   "x11_egl"       },
+    {0,                         0               },
+};
+
+static const struct enum_map context_api_map[] = {
+    {WAFFLE_CONTEXT_OPENGL,         "gl"        },
+    {WAFFLE_CONTEXT_OPENGL_ES1,     "gles1"     },
+    {WAFFLE_CONTEXT_OPENGL_ES2,     "gles2"     },
+    {WAFFLE_CONTEXT_OPENGL_ES3,     "gles3"     },
+    {0,                             0           },
+};
+
+/// @brief Translate string to `enum waffle_enum`.
+///
+/// @param self is a list of map items. The last item must be zero-filled.
+/// @param result is altered only if @a s if found.
+/// @return true if @a s was found in @a map.
+static bool
+enum_map_translate_str(
+        const struct enum_map *self,
+        const char *s,
+        int *result)
+{
+    for (const struct enum_map *i = self; i->i != 0; ++i) {
+        if (!strncmp(s, i->s, strlen(i->s) + 1)) {
+            *result = i->i;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static const char *
+enum_map_to_str(const struct enum_map *self,
+                int val)
+{
+    for (const struct enum_map *i = self; i->i != 0; ++i) {
+        if (i->i == val) {
+            return i->s;
+        }
+    }
+
+    return NULL;
+}
+
+/// @return true on success.
+static bool
+parse_args(int argc, char *argv[], struct options *opts)
+{
+    bool ok;
+    bool loop_get_opt = true;
+
+#ifdef __APPLE__
+    removeXcodeArgs(&argc, argv);
+#endif
+
+    // Set some context attrs to invalid values.
+    opts->context_profile = -1;
+    opts->context_version = -1;
+
+    while (loop_get_opt) {
+        int opt = getopt_long(argc, argv, "", get_opts, NULL);
+        switch (opt) {
+            case -1:
+                loop_get_opt = false;
+                break;
+            case '?':
+                goto error_unrecognized_arg;
+            case OPT_PLATFORM:
+                ok = enum_map_translate_str(platform_map, optarg,
+                                            &opts->platform);
+                if (!ok) {
+                    usage_error_printf("'%s' is not a valid platform",
+                                       optarg);
+                }
+                break;
+            case OPT_API:
+                ok = enum_map_translate_str(context_api_map, optarg,
+                                            &opts->context_api);
+                if (!ok) {
+                    usage_error_printf("'%s' is not a valid API for a GL "
+                                       "context", optarg);
+                }
+                break;
+            case OPT_VERSION: {
+                int major;
+                int minor;
+                int match_count;
+
+                match_count = sscanf(optarg, "%d.%d", &major, &minor);
+                if (match_count != 2) {
+                    usage_error_printf("'%s' is not a valid GL version",
+                                       optarg);
+                }
+                opts->context_version = 10 * major + minor;
+                break;
+            }
+            case OPT_PROFILE:
+                if (strcmp(optarg, "none") == 0) {
+                    opts->context_profile = WAFFLE_NONE;
+                } else if (strcmp(optarg, "core") == 0) {
+                    opts->context_profile = WAFFLE_CONTEXT_CORE_PROFILE;
+                } else if (strcmp(optarg, "compat") == 0) {
+                    opts->context_profile = WAFFLE_CONTEXT_COMPATIBILITY_PROFILE;
+                } else {
+                    usage_error_printf("'%s' is not a valid GL profile",
+                                       optarg);
+                }
+                break;
+            case OPT_VERBOSE:
+                opts->verbose = true;
+                break;
+            case OPT_FORWARD_COMPATIBLE:
+                opts->context_forward_compatible = true;
+                break;
+            case OPT_DEBUG_CONTEXT:
+                opts->context_debug = true;
+                break;
+            default:
+                abort();
+                loop_get_opt = false;
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        goto error_unrecognized_arg;
+    }
+
+    if (!opts->platform) {
+        usage_error_printf("--platform is required");
+    }
+
+    if (!opts->context_api) {
+        usage_error_printf("--api is required");
+    }
+
+    // Set dl.
+    switch (opts->context_api) {
+        case WAFFLE_CONTEXT_OPENGL:     opts->dl = WAFFLE_DL_OPENGL;      break;
+        case WAFFLE_CONTEXT_OPENGL_ES1: opts->dl = WAFFLE_DL_OPENGL_ES1;  break;
+        case WAFFLE_CONTEXT_OPENGL_ES2: opts->dl = WAFFLE_DL_OPENGL_ES2;  break;
+        case WAFFLE_CONTEXT_OPENGL_ES3: opts->dl = WAFFLE_DL_OPENGL_ES3;  break;
+        default:
+            abort();
+            break;
+    }
+
+    return true;
+
+error_unrecognized_arg:
+    usage_error_printf("unrecognized option '%s'", optarg);
+}
+
+/// @}
+
+static int
+parse_version(const char *version)
+{
+    int count, major, minor;
+
+    if (version == NULL)
+        return 0;
+
+    while (*version != '\0' && !isdigit(*version))
+        version++;
+
+    count = sscanf(version, "%d.%d", &major, &minor);
+    if (count != 2)
+        return 0;
+
+    if (minor > 9)
+        return 0;
+
+    return (major * 10) + minor;
+}
+
+static void
+print_extensions(bool use_stringi)
+{
+    GLint count = 0, i;
+    const char *ext;
+
+    printf("OpenGL extensions: ");
+    if (use_stringi) {
+        glGetIntegerv(GL_NUM_EXTENSIONS, &count);
+        if (glGetError() != GL_NO_ERROR) {
+            printf("WFLINFO_GL_ERROR");
+        } else {
+            for (i = 0; i < count; i++) {
+              ext = (const char *) glGetStringi(GL_EXTENSIONS, i);
+              if (glGetError() != GL_NO_ERROR)
+                  ext = "WFLINFO_GL_ERROR";
+              printf("%s%s", ext, (i + 1) < count ? " " : "");
+            }
+        }
+    } else {
+        const char *extensions = (const char *) glGetString(GL_EXTENSIONS);
+        if (glGetError() != GL_NO_ERROR)
+            printf("WFLINFO_GL_ERROR");
+        else
+            printf("%s", extensions);
+    }
+    printf("\n");
+}
+
+static void
+print_context_flags(void)
+{
+    static struct {
+        GLint flag;
+        char *str;
+    } flags[] = {
+        { GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT, "FORWARD_COMPATIBLE" },
+        { GL_CONTEXT_FLAG_DEBUG_BIT, "DEBUG" },
+        { GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB, "ROBUST_ACCESS" },
+    };
+    int flag_count = sizeof(flags) / sizeof(flags[0]);
+    GLint context_flags = 0;
+
+    printf("OpenGL context flags:");
+
+    glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
+    if (glGetError() != GL_NO_ERROR) {
+        printf(" WFLINFO_GL_ERROR\n");
+        return;
+    }
+
+    if (context_flags == 0) {
+        printf(" 0x0\n");
+        return;
+    }
+
+    for (int i = 0; i < flag_count; i++) {
+        if ((flags[i].flag & context_flags) != 0) {
+            printf(" %s", flags[i].str);
+            context_flags = context_flags & ~flags[i].flag;
+        }
+    }
+    for (int i = 0; context_flags != 0; context_flags >>= 1, i++) {
+        if ((context_flags & 1) != 0) {
+            printf(" 0x%x", 1 << i);
+        }
+    }
+    printf("\n");
+}
+
+/// @brief Print out information about the context that was created.
+static bool
+print_wflinfo(struct options *opts)
+{
+    while(glGetError() != GL_NO_ERROR) {
+        /* Clear all errors */
+    }
+
+    const char *vendor = (const char *) glGetString(GL_VENDOR);
+    if (glGetError() != GL_NO_ERROR || vendor == NULL)
+        vendor = "WFLINFO_GL_ERROR";
+
+    const char *renderer = (const char *) glGetString(GL_RENDERER);
+    if (glGetError() != GL_NO_ERROR || renderer == NULL)
+        renderer = "WFLINFO_GL_ERROR";
+
+    const char *version_str = (const char *) glGetString(GL_VERSION);
+    if (glGetError() != GL_NO_ERROR || version_str == NULL)
+        version_str = "WFLINFO_GL_ERROR";
+
+    const char *platform = enum_map_to_str(platform_map, opts->platform);
+    assert(platform != NULL);
+    printf("Waffle platform: %s\n", platform);
+
+    const char *api = enum_map_to_str(context_api_map, opts->context_api);
+    assert(api != NULL);
+    printf("Waffle api: %s\n", api);
+
+    printf("OpenGL vendor string: %s\n", vendor);
+    printf("OpenGL renderer string: %s\n", renderer);
+    printf("OpenGL version string: %s\n", version_str);
+
+    int version = parse_version(version_str);
+
+    if (opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 31) {
+        print_context_flags();
+    }
+
+    bool need_getstringi =
+            opts->context_api == WAFFLE_CONTEXT_OPENGL &&
+            version >= 30;
+
+    if (!glGetStringi && need_getstringi)
+        error_get_gl_symbol("glGetStringi");
+
+    if (opts->verbose)
+        print_extensions(need_getstringi);
+
+    return true;
+}
+
+#ifdef __APPLE__
+
+static NSAutoreleasePool *pool;
+
+static void
+cocoa_init(void)
+{
+    // From the NSApplication Class Reference:
+    //     [...] if you do need to use Cocoa classes within the main()
+    //     function itself (other than to load nib files or to instantiate
+    //     NSApplication), you should create an autorelease pool before using
+    //     the classes and then release the pool when you’re done.
+    pool = [[NSAutoreleasePool alloc] init];
+
+    // From the NSApplication Class Reference:
+    //     The sharedApplication class method initializes the display
+    //     environment and connects your program to the window server and the
+    //     display server.
+    //
+    // It also creates the singleton NSApp if it does not yet exist.
+    [NSApplication sharedApplication];
+}
+
+static void
+cocoa_finish(void)
+{
+    [pool drain];
+}
+
+static void
+removeArg(int index, int *argc, char **argv)
+{
+    --*argc;
+    for (; index < *argc; ++index)
+        argv[index] = argv[index + 1];
+}
+
+static void
+removeXcodeArgs(int *argc, char **argv)
+{
+    // Xcode sometimes adds additional arguments.
+    for (int i = 1; i < *argc; )
+    {
+        if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0 ||
+            strcmp(argv[i], "-ApplePersistenceIgnoreState" ) == 0)
+        {
+            removeArg(i, argc, argv);
+            removeArg(i, argc, argv);
+        } else
+            ++i;
+    }
+}
+
+#endif // __APPLE__
+
+int
+main(int argc, char **argv)
+{
+    bool ok;
+    int i;
+
+    struct options opts = {0};
+
+    int32_t init_attrib_list[3];
+    int32_t config_attrib_list[64];
+
+    struct waffle_display *dpy;
+    struct waffle_config *config;
+    struct waffle_context *ctx;
+    struct waffle_window *window;
+
+    #ifdef __APPLE__
+        cocoa_init();
+    #endif
+
+    ok = parse_args(argc, argv, &opts);
+    if (!ok)
+        exit(EXIT_FAILURE);
+
+    i = 0;
+    init_attrib_list[i++] = WAFFLE_PLATFORM;
+    init_attrib_list[i++] = opts.platform;
+    init_attrib_list[i++] = WAFFLE_NONE;
+
+    ok = waffle_init(init_attrib_list);
+    if (!ok)
+        error_waffle();
+
+    dpy = waffle_display_connect(NULL);
+    if (!dpy)
+        error_waffle();
+
+    if (!waffle_display_supports_context_api(dpy, opts.context_api)) {
+        error_printf("Display does not support %s",
+                     waffle_enum_to_string(opts.context_api));
+    }
+
+    glGetError = waffle_get_proc_address("glGetError");
+    if (!glGetError)
+        error_get_gl_symbol("glGetError");
+
+    glGetIntegerv = waffle_get_proc_address("glGetIntegerv");
+    if (!glGetIntegerv)
+        error_get_gl_symbol("glGetIntegerv");
+
+    glGetString = waffle_get_proc_address("glGetString");
+    if (!glGetString)
+        error_get_gl_symbol("glGetString");
+
+    glGetStringi = waffle_get_proc_address("glGetStringi");
+
+    i = 0;
+    config_attrib_list[i++] = WAFFLE_CONTEXT_API;
+    config_attrib_list[i++] = opts.context_api;
+
+    if (opts.context_profile != -1) {
+        config_attrib_list[i++] = WAFFLE_CONTEXT_PROFILE;
+        config_attrib_list[i++] = opts.context_profile;
+    }
+
+    if (opts.context_version != -1) {
+        config_attrib_list[i++] = WAFFLE_CONTEXT_MAJOR_VERSION;
+        config_attrib_list[i++] = opts.context_version / 10;
+        config_attrib_list[i++] = WAFFLE_CONTEXT_MINOR_VERSION;
+        config_attrib_list[i++] = opts.context_version % 10;
+    }
+
+    if (opts.context_forward_compatible) {
+        config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE;
+        config_attrib_list[i++] = true;
+    }
+
+    if (opts.context_debug) {
+        config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG;
+        config_attrib_list[i++] = true;
+    }
+
+    static int32_t dont_care_attribs[] = {
+        WAFFLE_RED_SIZE,
+        WAFFLE_GREEN_SIZE,
+        WAFFLE_BLUE_SIZE,
+        WAFFLE_ALPHA_SIZE,
+        WAFFLE_DEPTH_SIZE,
+        WAFFLE_STENCIL_SIZE,
+        WAFFLE_DOUBLE_BUFFERED,
+    };
+    int dont_care_attribs_count =
+        sizeof(dont_care_attribs) / sizeof(dont_care_attribs[0]);
+
+    for (int j = 0; j < dont_care_attribs_count; j++) {
+        config_attrib_list[i++] = dont_care_attribs[j];
+        config_attrib_list[i++] = WAFFLE_DONT_CARE;
+    }
+
+    config_attrib_list[i++] = 0;
+
+    config = waffle_config_choose(dpy, config_attrib_list);
+    if (!config)
+        error_waffle();
+
+    ctx = waffle_context_create(config, NULL);
+    if (!ctx)
+        error_waffle();
+
+    window = waffle_window_create(config, WINDOW_WIDTH, WINDOW_HEIGHT);
+    if (!window)
+        error_waffle();
+
+    ok = waffle_make_current(dpy, window, ctx);
+    if (!ok)
+        error_waffle();
+
+    ok = print_wflinfo(&opts);
+    if (!ok)
+        error_waffle();
+
+    ok = waffle_window_destroy(window);
+    if (!ok)
+        error_waffle();
+
+    ok = waffle_context_destroy(ctx);
+    if (!ok)
+        error_waffle();
+
+    ok = waffle_config_destroy(config);
+    if (!ok)
+        error_waffle();
+
+    ok = waffle_display_disconnect(dpy);
+    if (!ok)
+        error_waffle();
+
+    #ifdef __APPLE__
+        cocoa_finish();
+    #endif
+
+    return EXIT_SUCCESS;
+}
-- 
1.8.5.2



More information about the waffle mailing list