gl_basic.c 22.8 KB
Newer Older
1
// Copyright 2012 - 2014 Intel Corporation
Chad Versace's avatar
Chad Versace committed
2
//
3
// All rights reserved.
Chad Versace's avatar
Chad Versace committed
4
//
5 6
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
Chad Versace's avatar
Chad Versace committed
7
//
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// - 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.
Chad Versace's avatar
Chad Versace committed
25

26
/// @file
27
/// @brief Do some basic OpenGL rendering using Waffle.
Chad Versace's avatar
Chad Versace committed
28 29
///
/// This example does the following:
30 31 32
///     1. Dynamically choose the platform and OpenGL API according to
///        command line arguments.
///     2. Create a window and OpenGL context.
Chad Versace's avatar
Chad Versace committed
33 34 35 36
///     3. Fill the window with red, then green, then blue, sleeping between
///        each buffer swap.

#define _POSIX_C_SOURCE 199309L // glibc feature macro for nanosleep.
37
#define WAFFLE_API_VERSION 0x0106
38
#define WAFFLE_API_EXPERIMENTAL
Chad Versace's avatar
Chad Versace committed
39

40
#include <assert.h>
41
#include <getopt.h>
42
#include <stdarg.h>
Chad Versace's avatar
Chad Versace committed
43 44 45 46
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
47
#if !defined(_WIN32)
Chad Versace's avatar
Chad Versace committed
48
#include <time.h>
49 50 51
#else
#include <windows.h>
#endif
Chad Versace's avatar
Chad Versace committed
52

53
#ifdef __APPLE__
54 55
#    import <Foundation/NSAutoreleasePool.h>
#    import <Appkit/NSApplication.h>
56 57 58

static void
removeXcodeArgs(int *argc, char **argv);
59 60
#endif

61
#include "waffle.h"
Chad Versace's avatar
Chad Versace committed
62 63 64

static const char *usage_message =
    "usage:\n"
65
    "    gl_basic --platform=android|cgl|gbm|glx|wayland|wgl|x11_egl\n"
66 67 68
    "             --api=gl|gles1|gles2|gles3\n"
    "             [--version=MAJOR.MINOR]\n"
    "             [--profile=core|compat|none]\n"
69
    "             [--forward-compatible]\n"
70
    "             [--debug]\n"
71
    "             [--robust]\n"
72
    "             [--resize-window]\n"
73
    "             [--window-size=WIDTHxHEIGHT | --fullscreen]\n"
Chad Versace's avatar
Chad Versace committed
74
    "\n"
75
    "examples:\n"
76 77 78
    "    gl_basic --platform=glx --api=gl\n"
    "    gl_basic --platform=x11_egl --api=gl --version=3.2 --profile=core\n"
    "    gl_basic --platform=wayland --api=gles3\n"
Chad Versace's avatar
Chad Versace committed
79 80
    "\n"
    "description:\n"
81 82 83 84 85 86 87 88
    "    Create a window. Fill it with red, green, then blue.\n"
    "\n"
    "options:\n"
    "    --forward-compatible\n"
    "        Create a forward-compatible context.\n"
    "\n"
    "    --debug\n"
    "        Create a debug context.\n"
89
    "\n"
90 91 92
    "    --robust\n"
    "        Create a robust context.\n"
    "\n"
93 94
    "    --resize-window\n"
    "        Resize the window between each draw call.\n"
95 96 97
    "\n"
    "    --fullscreen\n"
    "        Create a fullscreen window.\n"
98
    ;
Chad Versace's avatar
Chad Versace committed
99

100 101 102 103 104
enum {
    OPT_PLATFORM = 1,
    OPT_API,
    OPT_VERSION,
    OPT_PROFILE,
105
    OPT_DEBUG,
106
    OPT_FORWARD_COMPATIBLE,
107
    OPT_ROBUST,
108
    OPT_RESIZE_WINDOW,
109
    OPT_WINDOW_SIZE,
110
    OPT_FULLSCREEN,
111 112 113 114 115 116 117
};

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 },
118
    { .name = "debug",          .has_arg = no_argument,           .val = OPT_DEBUG },
119
    { .name = "forward-compatible", .has_arg = no_argument,       .val = OPT_FORWARD_COMPATIBLE },
120
    { .name = "robust",         .has_arg = no_argument,           .val = OPT_ROBUST },
121
    { .name = "resize-window",  .has_arg = no_argument,           .val = OPT_RESIZE_WINDOW },
122
    { .name = "window-size",    .has_arg = required_argument,     .val = OPT_WINDOW_SIZE },
123
    { .name = "fullscreen",     .has_arg = no_argument,           .val = OPT_FULLSCREEN },
124 125 126
    { 0 },
};

127 128 129 130 131 132 133 134 135
#if defined(__GNUC__)
#define NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define NORETURN __declspec(noreturn)
#else
#define NORETURN
#endif

static void NORETURN
136
error_printf(const char *fmt, ...)
137 138 139 140 141 142 143 144 145 146 147 148 149
{
    va_list ap;

    fflush(stdout);

    va_start(ap, fmt);
    fprintf(stderr, "gl_basic: error: ");
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
    va_end(ap);

    exit(EXIT_FAILURE);
}
150 151

static void NORETURN
152
usage_error_printf(const char *fmt, ...)
Chad Versace's avatar
Chad Versace committed
153
{
154 155 156 157 158 159 160 161 162 163 164 165 166
    fflush(stdout);
    fprintf(stderr, "gl_basic: 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");
167
    fprintf(stderr, "%s", usage_message);
168

Chad Versace's avatar
Chad Versace committed
169 170 171 172 173 174
    exit(EXIT_FAILURE);
}

static void
error_waffle(void)
{
175
    const struct waffle_error_info *info = waffle_error_get_info();
176
    const char *code = waffle_error_to_string(info->code);
Chad Versace's avatar
Chad Versace committed
177

178
    if (info->message_length > 0)
179
        error_printf("%s: %s", code, info->message);
180
    else
181
        error_printf("%s", code);
182 183
}

Chad Versace's avatar
Chad Versace committed
184 185 186
static void
error_get_gl_symbol(const char *name)
{
187
    error_printf("failed to get function pointer for %s", name);
Chad Versace's avatar
Chad Versace committed
188 189 190 191
}

typedef float GLclampf;
typedef unsigned int GLbitfield;
192 193 194 195
typedef unsigned int GLint;
typedef int GLsizei;
typedef unsigned int GLenum;
typedef void GLvoid;
Chad Versace's avatar
Chad Versace committed
196 197

enum {
198
    // Copied from <GL/gl*.h>.
199 200
    GL_UNSIGNED_BYTE =    0x00001401,
    GL_RGBA =             0x00001908,
Chad Versace's avatar
Chad Versace committed
201
    GL_COLOR_BUFFER_BIT = 0x00004000,
202 203 204

    GL_CONTEXT_FLAGS = 0x821e,
    GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = 0x00000001,
205
    GL_CONTEXT_FLAG_DEBUG_BIT              = 0x00000002,
206
    GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT      = 0x00000004 ,
Chad Versace's avatar
Chad Versace committed
207 208
};

209 210
static int window_width = 320;
static int window_height = 240;
211

212 213 214 215 216 217 218 219 220 221
#ifndef _WIN32
#define APIENTRY
#else
#ifndef APIENTRY
#define APIENTRY __stdcall
#endif
#endif

static void (APIENTRY *glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
static void (APIENTRY *glClear)(GLbitfield mask);
222
static GLenum (APIENTRY *glGetError)(void);
223 224 225 226
static void (APIENTRY *glGetIntegerv)(GLenum pname, GLint *params);
static void (APIENTRY *glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height,
                                     GLenum format, GLenum type, GLvoid* data);
static void (APIENTRY *glViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
Chad Versace's avatar
Chad Versace committed
227

228
/// @brief Command line options.
Chad Versace's avatar
Chad Versace committed
229
struct options {
230
    /// @brief One of `WAFFLE_PLATFORM_*`.
Chad Versace's avatar
Chad Versace committed
231
    int platform;
232 233 234 235

    /// @brief One of `WAFFLE_CONTEXT_OPENGL_*`.
    int context_api;

236 237 238 239 240
    /// @brief One of `WAFFLE_CONTEXT_PROFILE_*` or `WAFFLE_NONE`.
    int context_profile;

    int context_version;

241
    bool context_forward_compatible;
242
    bool context_debug;
243
    bool context_robust;
244

245 246
    bool resize_window;

247 248
    bool fullscreen;

249 250
    /// @brief One of `WAFFLE_DL_*`.
    int dl;
Chad Versace's avatar
Chad Versace committed
251 252 253 254 255 256 257 258 259
};

struct enum_map {
    int i;
    const char *s;
};

static const struct enum_map platform_map[] = {
    {WAFFLE_PLATFORM_ANDROID,   "android"       },
260
    {WAFFLE_PLATFORM_CGL,       "cgl",          },
261
    {WAFFLE_PLATFORM_GBM,       "gbm"           },
Chad Versace's avatar
Chad Versace committed
262 263
    {WAFFLE_PLATFORM_GLX,       "glx"           },
    {WAFFLE_PLATFORM_WAYLAND,   "wayland"       },
264
    {WAFFLE_PLATFORM_WGL,       "wgl"           },
Chad Versace's avatar
Chad Versace committed
265 266 267 268
    {WAFFLE_PLATFORM_X11_EGL,   "x11_egl"       },
    {0,                         0               },
};

269 270 271 272
static const struct enum_map context_api_map[] = {
    {WAFFLE_CONTEXT_OPENGL,         "gl"        },
    {WAFFLE_CONTEXT_OPENGL_ES1,     "gles1"     },
    {WAFFLE_CONTEXT_OPENGL_ES2,     "gles2"     },
273
    {WAFFLE_CONTEXT_OPENGL_ES3,     "gles3"     },
274
    {0,                             0           },
Chad Versace's avatar
Chad Versace committed
275 276 277 278 279 280 281 282 283 284 285 286 287
};

/// @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)
{
288
    for (const struct enum_map *i = self; i->i != 0; ++i) {
Chad Versace's avatar
Chad Versace committed
289 290 291 292 293 294 295 296 297 298 299 300 301 302
        if (!strncmp(s, i->s, strlen(i->s) + 1)) {
            *result = i->i;
            return true;
        }
    }

    return false;
}

/// @return true on success.
static bool
parse_args(int argc, char *argv[], struct options *opts)
{
    bool ok;
303
    bool loop_get_opt = true;
304
    bool found_window_size = false;
Chad Versace's avatar
Chad Versace committed
305

306
#ifdef __APPLE__
307
    removeXcodeArgs(&argc, argv);
308
#endif
309

310 311 312 313
    // Set some context attrs to invalid values.
    opts->context_profile = -1;
    opts->context_version = -1;

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    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) {
334
                    usage_error_printf("'%s' is not a valid API for an OpenGL "
335 336 337 338 339 340 341 342 343 344
                                       "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) {
345
                    usage_error_printf("'%s' is not a valid OpenGL version",
346 347 348 349 350 351 352 353 354 355 356 357 358
                                       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 {
359
                    usage_error_printf("'%s' is not a valid OpenGL profile",
360 361 362
                                       optarg);
                }
                break;
363 364 365
            case OPT_FORWARD_COMPATIBLE:
                opts->context_forward_compatible = true;
                break;
366 367 368
            case OPT_DEBUG:
                opts->context_debug = true;
                break;
369 370 371
            case OPT_ROBUST:
                opts->context_robust = true;
                break;
372 373 374
            case OPT_RESIZE_WINDOW:
                opts->resize_window = true;
                break;
375 376 377 378 379 380 381
            case OPT_WINDOW_SIZE: {
                int match_count;
                match_count = sscanf(optarg, "%dx%d", &window_width, &window_height);
                if (match_count != 2) {
                    usage_error_printf("'%s' is not a valid window geometry",
                                       optarg);
                }
382
                found_window_size = true;
383 384
                break;
            }
385 386 387
            case OPT_FULLSCREEN:
                opts->fullscreen = true;
                break;
388 389 390 391 392
            default:
                abort();
                loop_get_opt = false;
                break;
        }
Chad Versace's avatar
Chad Versace committed
393 394
    }

395 396
    if (optind < argc) {
        goto error_unrecognized_arg;
Chad Versace's avatar
Chad Versace committed
397 398
    }

399 400
    if (!opts->platform) {
        usage_error_printf("--platform is required");
401 402
    }

403 404
    if (!opts->context_api) {
        usage_error_printf("--api is required");
405 406
    }

407 408 409 410 411
    if (opts->fullscreen && found_window_size) {
        usage_error_printf("--fullscreen and --window-size are mutually "
                           "exclusive options");
    }

412 413
    // Set dl.
    switch (opts->context_api) {
414 415 416
        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;
417
        case WAFFLE_CONTEXT_OPENGL_ES3: opts->dl = WAFFLE_DL_OPENGL_ES3;  break;
418 419 420 421 422
        default:
            abort();
            break;
    }

Chad Versace's avatar
Chad Versace committed
423
    return true;
424 425 426

error_unrecognized_arg:
    usage_error_printf("unrecognized option '%s'", optarg);
Chad Versace's avatar
Chad Versace committed
427 428
}

429 430 431 432 433 434 435 436
// The rules that dictate how to properly query a GL symbol are complex. The
// rules depend on the OS, on the winsys API, and even on the particular driver
// being used. The rules differ between EGL 1.4 and EGL 1.5; differ between
// Linux, Windows, and Mac; and differ between Mesa and Mali.
//
// This function hides that complexity with a naive heuristic: try, then try
// again.
static void *
437
get_gl_symbol(const struct options *opts, const char *name)
438 439 440 441 442 443 444 445 446 447 448 449 450 451
{
    void *sym = NULL;

    if (waffle_dl_can_open(opts->dl)) {
        sym = waffle_dl_sym(opts->dl, name);
    }

    if (!sym) {
        sym = waffle_get_proc_address(name);
    }

    return sym;
}

Chad Versace's avatar
Chad Versace committed
452
static bool
453
draw(struct waffle_window *window, bool resize)
Chad Versace's avatar
Chad Versace committed
454 455
{
    bool ok;
456
    unsigned char *colors;
457 458
    int width = window_width;
    int height = window_height;
Chad Versace's avatar
Chad Versace committed
459

460
#if !defined(_WIN32)
Chad Versace's avatar
Chad Versace committed
461 462 463 464 465
    static const struct timespec sleep_time = {
         // 0.5 sec
        .tv_sec = 0,
        .tv_nsec = 500000000,
    };
466
#endif
Chad Versace's avatar
Chad Versace committed
467

468
    for (int i = 0; i < 3; ++i) {
Chad Versace's avatar
Chad Versace committed
469 470 471 472 473 474 475
        switch (i) {
            case 0: glClearColor(1, 0, 0, 1); break;
            case 1: glClearColor(0, 1, 0, 1); break;
            case 2: glClearColor(0, 0, 1, 1); break;
            case 3: abort(); break;
        }

476 477 478 479 480 481 482
        if (resize) {
            width = (i + 2) * 40;
            height = width;
            waffle_window_resize(window, width, height);
            glViewport(0, 0, width, height);
        }

Chad Versace's avatar
Chad Versace committed
483
        glClear(GL_COLOR_BUFFER_BIT);
484

485
        colors = calloc(width * height * 4, sizeof(*colors));
486
        glReadPixels(0, 0,
487
                     width, height,
488 489
                     GL_RGBA, GL_UNSIGNED_BYTE,
                     colors);
490
        for (int j = 0; j < width * height * 4; j += 4) {
491 492 493 494
           if ((colors[j]   != (i == 0 ? 0xff : 0)) ||
               (colors[j+1] != (i == 1 ? 0xff : 0)) ||
               (colors[j+2] != (i == 2 ? 0xff : 0)) ||
               (colors[j+3] != 0xff)) {
495 496
              fprintf(stderr, "glReadPixels returned unexpected result\n");
              break;
497 498 499 500
           }
        }
        free(colors);

501 502 503 504 505 506
        if (i == 0) {
            ok = waffle_window_show(window);
            if (!ok)
                return false;
        }

Chad Versace's avatar
Chad Versace committed
507 508 509
        ok = waffle_window_swap_buffers(window);
        if (!ok)
            return false;
510

511
#if !defined(_WIN32)
Chad Versace's avatar
Chad Versace committed
512
        nanosleep(&sleep_time, NULL);
513 514 515
#else
        Sleep(500);
#endif
Chad Versace's avatar
Chad Versace committed
516 517 518 519 520
    }

    return true;
}

521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
#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];
}

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
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;
    }
}

574 575
#endif // __APPLE__

576 577 578 579 580 581 582 583 584 585 586
#ifdef __native_client__
#include "ppapi_simple/ps_main.h"
//
// We need to rename main() for native client
// because ppapi_simple already defines main().
//
int basic_test_main(int argc, char **argv);
PPAPI_SIMPLE_REGISTER_MAIN(basic_test_main)
int
basic_test_main(int argc, char **argv)
#else
Chad Versace's avatar
Chad Versace committed
587 588
int
main(int argc, char **argv)
589
#endif
Chad Versace's avatar
Chad Versace committed
590 591
{
    bool ok;
592 593
    int i;

594
    struct options opts = {0};
595 596

    int32_t init_attrib_list[3];
597
    int32_t config_attrib_list[64];
598
    intptr_t window_attrib_list[5];
599

Chad Versace's avatar
Chad Versace committed
600 601 602 603 604
    struct waffle_display *dpy;
    struct waffle_config *config;
    struct waffle_context *ctx;
    struct waffle_window *window;

605 606
    GLint context_flags = 0;

607 608 609 610
    #ifdef __APPLE__
        cocoa_init();
    #endif

611 612 613 614 615 616 617 618
    #ifdef __native_client__
        // Fixed arguments for native client.
        opts.context_api = WAFFLE_CONTEXT_OPENGL_ES2;
        opts.platform = WAFFLE_PLATFORM_NACL;
        opts.dl = WAFFLE_DL_OPENGL_ES2;
        opts.context_profile = WAFFLE_NONE;
        opts.context_version = -1;
    #else
Chad Versace's avatar
Chad Versace committed
619 620 621
    ok = parse_args(argc, argv, &opts);
    if (!ok)
        exit(EXIT_FAILURE);
622
    #endif
Chad Versace's avatar
Chad Versace committed
623

624 625 626 627
    i = 0;
    init_attrib_list[i++] = WAFFLE_PLATFORM;
    init_attrib_list[i++] = opts.platform;
    init_attrib_list[i++] = WAFFLE_NONE;
Chad Versace's avatar
Chad Versace committed
628

629
    ok = waffle_init(init_attrib_list);
Chad Versace's avatar
Chad Versace committed
630 631 632
    if (!ok)
        error_waffle();

633
    dpy = waffle_display_connect(NULL);
634 635 636 637
    if (!dpy)
        error_waffle();

    if (!waffle_display_supports_context_api(dpy, opts.context_api)) {
638 639
        error_printf("Display does not support %s",
                     waffle_enum_to_string(opts.context_api));
640 641
    }

642
    glClear = get_gl_symbol(&opts, "glClear");
Chad Versace's avatar
Chad Versace committed
643 644 645
    if (!glClear)
        error_get_gl_symbol("glClear");

646
    glClearColor = get_gl_symbol(&opts, "glClearColor");
Chad Versace's avatar
Chad Versace committed
647 648 649
    if (!glClearColor)
        error_get_gl_symbol("glClearColor");

650
    glGetError = get_gl_symbol(&opts, "glGetError");
651 652 653
    if (!glGetError)
        error_get_gl_symbol("glGetError");

654
    glGetIntegerv = get_gl_symbol(&opts, "glGetIntegerv");
655 656 657
    if (!glGetIntegerv)
        error_get_gl_symbol("glGetIntegerv");

658
    glReadPixels = get_gl_symbol(&opts, "glReadPixels");
659 660 661
    if (!glReadPixels)
        error_get_gl_symbol("glReadPixels");

662
    glViewport = get_gl_symbol(&opts, "glViewport");
663 664 665
    if (!glViewport)
        error_get_gl_symbol("glViewport");

666 667 668
    i = 0;
    config_attrib_list[i++] = WAFFLE_CONTEXT_API;
    config_attrib_list[i++] = opts.context_api;
669 670 671 672 673 674 675 676 677 678 679 680 681

    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;
    }

682 683 684 685 686
    if (opts.context_forward_compatible) {
        config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE;
        config_attrib_list[i++] = true;
    }

687 688 689 690 691
    if (opts.context_debug) {
        config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG;
        config_attrib_list[i++] = true;
    }

692 693 694 695 696
    if (opts.context_robust) {
        config_attrib_list[i++] = WAFFLE_CONTEXT_ROBUST_ACCESS,
        config_attrib_list[i++] = true;
    }

697 698 699 700 701 702
    config_attrib_list[i++] = WAFFLE_RED_SIZE;
    config_attrib_list[i++] = 8;
    config_attrib_list[i++] = WAFFLE_GREEN_SIZE;
    config_attrib_list[i++] = 8;
    config_attrib_list[i++] = WAFFLE_BLUE_SIZE;
    config_attrib_list[i++] = 8;
703 704
    config_attrib_list[i++] = WAFFLE_ALPHA_SIZE;
    config_attrib_list[i++] = 8;
705 706 707 708 709
    config_attrib_list[i++] = WAFFLE_DOUBLE_BUFFERED;
    config_attrib_list[i++] = true;
    config_attrib_list[i++] = 0;

    config = waffle_config_choose(dpy, config_attrib_list);
Chad Versace's avatar
Chad Versace committed
710 711 712 713 714 715 716
    if (!config)
        error_waffle();

    ctx = waffle_context_create(config, NULL);
    if (!ctx)
        error_waffle();

717 718

    i = 0;
719 720 721 722 723 724 725 726 727 728 729
    if (opts.fullscreen) {
        window_attrib_list[i++] = WAFFLE_WINDOW_FULLSCREEN;
        window_attrib_list[i++] = true;
        window_attrib_list[i++] = 0;
    } else {
        window_attrib_list[i++] = WAFFLE_WINDOW_WIDTH;
        window_attrib_list[i++] = window_width;
        window_attrib_list[i++] = WAFFLE_WINDOW_HEIGHT;
        window_attrib_list[i++] = window_height;
        window_attrib_list[i++] = 0;
    }
730 731

    window = waffle_window_create2(config, window_attrib_list);
Chad Versace's avatar
Chad Versace committed
732 733 734
    if (!window)
        error_waffle();

735
    ok = waffle_make_current(dpy, window, ctx);
Chad Versace's avatar
Chad Versace committed
736 737 738
    if (!ok)
        error_waffle();

739
    if (opts.context_forward_compatible || opts.context_debug) {
740
        glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
741 742
    }

743 744 745
    if (glGetError())
        error_printf("glGetIntegerv(GL_CONTEXT_FLAGS) failed");

746 747
    if (opts.context_forward_compatible
        && !(context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) {
748
        error_printf("context is not forward-compatible");
749 750 751 752
    }

    if (opts.context_debug
        && !(context_flags & GL_CONTEXT_FLAG_DEBUG_BIT)) {
753
        error_printf("context is not a debug context");
754 755
    }

756 757 758 759 760
    // Don't verify if the context is robust because that pollutes this simple
    // example program with hairy GL logic. The method of verifying if
    // a context is robust varies on the combination of context profile,
    // context version, and supported extensions.

761
    ok = draw(window, opts.resize_window);
Chad Versace's avatar
Chad Versace committed
762 763 764
    if (!ok)
        error_waffle();

765 766 767 768
    ok = waffle_make_current(dpy, NULL, NULL);
    if (!ok)
        error_waffle();

Chad Versace's avatar
Chad Versace committed
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
    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();

785 786 787 788
    ok = waffle_teardown();
    if (!ok)
        error_waffle();

789 790 791 792
    #ifdef __APPLE__
        cocoa_finish();
    #endif

793
    printf("gl_basic: run was successful\n");
Chad Versace's avatar
Chad Versace committed
794 795
    return EXIT_SUCCESS;
}