Mark printf-like functions with the appropriate gcc attribute
[mesa-waffle.git] / examples / gl_basic.c
blobae952c6d88985bf7b2db678f052ededb8eecf329
1 // Copyright 2012 - 2014 Intel Corporation
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // - Redistributions of source code must retain the above copyright notice, this
9 // list of conditions and the following disclaimer.
11 // - Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 /// @file
27 /// @brief Do some basic OpenGL rendering using Waffle.
28 ///
29 /// This example does the following:
30 /// 1. Dynamically choose the platform and OpenGL API according to
31 /// command line arguments.
32 /// 2. Create a window and OpenGL context.
33 /// 3. Fill the window with red, then green, then blue, sleeping between
34 /// each buffer swap.
36 #define _POSIX_C_SOURCE 199309L // glibc feature macro for nanosleep.
37 #define WAFFLE_API_VERSION 0x0108
38 #define WAFFLE_API_EXPERIMENTAL
40 #include <assert.h>
41 #include <getopt.h>
42 #include <stdarg.h>
43 #include <stdbool.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #if !defined(_WIN32)
48 #include <time.h>
49 #else
50 #include <windows.h>
51 #endif
53 #ifdef __APPLE__
54 # import <Foundation/NSAutoreleasePool.h>
55 # import <AppKit/NSApplication.h>
57 static void
58 removeXcodeArgs(int *argc, char **argv);
59 #endif
61 #include "waffle.h"
63 static const char *usage_message =
64 "usage:\n"
65 " gl_basic --platform=android|cgl|gbm|glx|wayland|wgl|surfaceless_egl|x11_egl\n"
66 " --api=gl|gles1|gles2|gles3\n"
67 " [--version=MAJOR.MINOR]\n"
68 " [--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"
74 "\n"
75 "examples:\n"
76 " gl_basic --platform=glx --api=gl\n"
77 " gl_basic --platform=x11_egl --api=gl --version=3.2 --profile=core\n"
78 " gl_basic --platform=wayland --api=gles3\n"
79 "\n"
80 "description:\n"
81 " Create a window. Fill it with red, green, then blue.\n"
82 "\n"
83 "options:\n"
84 " --forward-compatible\n"
85 " Create a forward-compatible context.\n"
86 "\n"
87 " --debug\n"
88 " Create a debug context.\n"
89 "\n"
90 " --robust\n"
91 " Create a robust context.\n"
92 "\n"
93 " --resize-window\n"
94 " Resize the window between each draw call.\n"
95 "\n"
96 " --fullscreen\n"
97 " Create a fullscreen window.\n"
100 enum {
101 OPT_PLATFORM = 1,
102 OPT_API,
103 OPT_VERSION,
104 OPT_PROFILE,
105 OPT_DEBUG,
106 OPT_FORWARD_COMPATIBLE,
107 OPT_ROBUST,
108 OPT_RESIZE_WINDOW,
109 OPT_WINDOW_SIZE,
110 OPT_FULLSCREEN,
113 static const struct option get_opts[] = {
114 { .name = "platform", .has_arg = required_argument, .val = OPT_PLATFORM },
115 { .name = "api", .has_arg = required_argument, .val = OPT_API },
116 { .name = "version", .has_arg = required_argument, .val = OPT_VERSION },
117 { .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 { 0 },
127 #if defined(__GNUC__)
128 #define NORETURN __attribute__((noreturn))
129 #elif defined(_MSC_VER)
130 #define NORETURN __declspec(noreturn)
131 #else
132 #define NORETURN
133 #endif
135 #if defined(__GNUC__)
136 #define PRINTFLIKE(f, a) __attribute__((__format__(__printf__, f, a)))
137 #else
138 #define PRINTFLIKE(f, a)
139 #endif
141 static void NORETURN PRINTFLIKE(1, 2) error_printf(const char *fmt, ...)
143 va_list ap;
145 fflush(stdout);
147 va_start(ap, fmt);
148 fprintf(stderr, "gl_basic: error: ");
149 vfprintf(stderr, fmt, ap);
150 fprintf(stderr, "\n");
151 va_end(ap);
153 exit(EXIT_FAILURE);
156 static void NORETURN PRINTFLIKE(1, 2) usage_error_printf(const char *fmt, ...)
158 fflush(stdout);
159 fprintf(stderr, "gl_basic: usage error");
161 if (fmt) {
162 va_list ap;
163 va_start(ap, fmt);
164 fprintf(stderr, ": ");
165 vfprintf(stderr, fmt, ap);
166 va_end(ap);
169 fprintf(stderr, "\n");
170 fprintf(stderr, "\n");
171 fprintf(stderr, "%s", usage_message);
173 exit(EXIT_FAILURE);
176 static void
177 error_waffle(void)
179 const struct waffle_error_info *info = waffle_error_get_info();
180 const char *code = waffle_error_to_string(info->code);
182 if (info->message_length > 0)
183 error_printf("%s: %s", code, info->message);
184 else
185 error_printf("%s", code);
188 static void
189 error_get_gl_symbol(const char *name)
191 error_printf("failed to get function pointer for %s", name);
194 typedef float GLclampf;
195 typedef unsigned int GLbitfield;
196 typedef unsigned int GLint;
197 typedef int GLsizei;
198 typedef unsigned int GLenum;
199 typedef void GLvoid;
201 enum {
202 // Copied from <GL/gl*.h>.
203 GL_UNSIGNED_BYTE = 0x00001401,
204 GL_RGBA = 0x00001908,
205 GL_COLOR_BUFFER_BIT = 0x00004000,
207 GL_CONTEXT_FLAGS = 0x821e,
208 GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = 0x00000001,
209 GL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002,
210 GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 0x00000004 ,
213 static int window_width = 320;
214 static int window_height = 240;
216 #ifndef _WIN32
217 #define APIENTRY
218 #else
219 #ifndef APIENTRY
220 #define APIENTRY __stdcall
221 #endif
222 #endif
224 static void (APIENTRY *glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
225 static void (APIENTRY *glClear)(GLbitfield mask);
226 static GLenum (APIENTRY *glGetError)(void);
227 static void (APIENTRY *glGetIntegerv)(GLenum pname, GLint *params);
228 static void (APIENTRY *glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height,
229 GLenum format, GLenum type, GLvoid* data);
230 static void (APIENTRY *glViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
232 /// @brief Command line options.
233 struct options {
234 /// @brief One of `WAFFLE_PLATFORM_*`.
235 int platform;
237 /// @brief One of `WAFFLE_CONTEXT_OPENGL_*`.
238 int context_api;
240 /// @brief One of `WAFFLE_CONTEXT_PROFILE_*` or `WAFFLE_NONE`.
241 int context_profile;
243 int context_version;
245 bool context_forward_compatible;
246 bool context_debug;
247 bool context_robust;
249 bool resize_window;
251 bool fullscreen;
253 /// @brief One of `WAFFLE_DL_*`.
254 int dl;
257 struct enum_map {
258 int i;
259 const char *s;
262 static const struct enum_map platform_map[] = {
263 {WAFFLE_PLATFORM_ANDROID, "android" },
264 {WAFFLE_PLATFORM_CGL, "cgl", },
265 {WAFFLE_PLATFORM_GBM, "gbm" },
266 {WAFFLE_PLATFORM_GLX, "glx" },
267 {WAFFLE_PLATFORM_WAYLAND, "wayland" },
268 {WAFFLE_PLATFORM_WGL, "wgl" },
269 {WAFFLE_PLATFORM_SURFACELESS_EGL, "surfaceless_egl" },
270 {WAFFLE_PLATFORM_X11_EGL, "x11_egl" },
271 {0, 0 },
274 static const struct enum_map context_api_map[] = {
275 {WAFFLE_CONTEXT_OPENGL, "gl" },
276 {WAFFLE_CONTEXT_OPENGL_ES1, "gles1" },
277 {WAFFLE_CONTEXT_OPENGL_ES2, "gles2" },
278 {WAFFLE_CONTEXT_OPENGL_ES3, "gles3" },
279 {0, 0 },
282 /// @brief Translate string to `enum waffle_enum`.
284 /// @param self is a list of map items. The last item must be zero-filled.
285 /// @param result is altered only if @a s if found.
286 /// @return true if @a s was found in @a map.
287 static bool
288 enum_map_translate_str(
289 const struct enum_map *self,
290 const char *s,
291 int *result)
293 for (const struct enum_map *i = self; i->i != 0; ++i) {
294 if (!strncmp(s, i->s, strlen(i->s) + 1)) {
295 *result = i->i;
296 return true;
300 return false;
303 /// @return true on success.
304 static bool
305 parse_args(int argc, char *argv[], struct options *opts)
307 bool ok;
308 bool loop_get_opt = true;
309 bool found_window_size = false;
311 #ifdef __APPLE__
312 removeXcodeArgs(&argc, argv);
313 #endif
315 // Set some context attrs to invalid values.
316 opts->context_profile = -1;
317 opts->context_version = -1;
319 while (loop_get_opt) {
320 int opt = getopt_long(argc, argv, "", get_opts, NULL);
321 switch (opt) {
322 case -1:
323 loop_get_opt = false;
324 break;
325 case '?':
326 goto error_unrecognized_arg;
327 case OPT_PLATFORM:
328 ok = enum_map_translate_str(platform_map, optarg,
329 &opts->platform);
330 if (!ok) {
331 usage_error_printf("'%s' is not a valid platform",
332 optarg);
334 break;
335 case OPT_API:
336 ok = enum_map_translate_str(context_api_map, optarg,
337 &opts->context_api);
338 if (!ok) {
339 usage_error_printf("'%s' is not a valid API for an OpenGL "
340 "context", optarg);
342 break;
343 case OPT_VERSION: {
344 int major;
345 int minor;
346 int match_count;
348 match_count = sscanf(optarg, "%d.%d", &major, &minor);
349 if (match_count != 2) {
350 usage_error_printf("'%s' is not a valid OpenGL version",
351 optarg);
353 opts->context_version = 10 * major + minor;
354 break;
356 case OPT_PROFILE:
357 if (strcmp(optarg, "none") == 0) {
358 opts->context_profile = WAFFLE_NONE;
359 } else if (strcmp(optarg, "core") == 0) {
360 opts->context_profile = WAFFLE_CONTEXT_CORE_PROFILE;
361 } else if (strcmp(optarg, "compat") == 0) {
362 opts->context_profile = WAFFLE_CONTEXT_COMPATIBILITY_PROFILE;
363 } else {
364 usage_error_printf("'%s' is not a valid OpenGL profile",
365 optarg);
367 break;
368 case OPT_FORWARD_COMPATIBLE:
369 opts->context_forward_compatible = true;
370 break;
371 case OPT_DEBUG:
372 opts->context_debug = true;
373 break;
374 case OPT_ROBUST:
375 opts->context_robust = true;
376 break;
377 case OPT_RESIZE_WINDOW:
378 opts->resize_window = true;
379 break;
380 case OPT_WINDOW_SIZE: {
381 int match_count;
382 match_count = sscanf(optarg, "%dx%d", &window_width, &window_height);
383 if (match_count != 2) {
384 usage_error_printf("'%s' is not a valid window geometry",
385 optarg);
387 found_window_size = true;
388 break;
390 case OPT_FULLSCREEN:
391 opts->fullscreen = true;
392 break;
393 default:
394 abort();
395 loop_get_opt = false;
396 break;
400 if (optind < argc) {
401 goto error_unrecognized_arg;
404 if (!opts->platform) {
405 usage_error_printf("--platform is required");
408 if (!opts->context_api) {
409 usage_error_printf("--api is required");
412 if (opts->fullscreen && found_window_size) {
413 usage_error_printf("--fullscreen and --window-size are mutually "
414 "exclusive options");
417 // Set dl.
418 switch (opts->context_api) {
419 case WAFFLE_CONTEXT_OPENGL: opts->dl = WAFFLE_DL_OPENGL; break;
420 case WAFFLE_CONTEXT_OPENGL_ES1: opts->dl = WAFFLE_DL_OPENGL_ES1; break;
421 case WAFFLE_CONTEXT_OPENGL_ES2: opts->dl = WAFFLE_DL_OPENGL_ES2; break;
422 case WAFFLE_CONTEXT_OPENGL_ES3: opts->dl = WAFFLE_DL_OPENGL_ES3; break;
423 default:
424 abort();
425 break;
428 return true;
430 error_unrecognized_arg:
431 usage_error_printf("unrecognized option '%s'", optarg);
434 // The rules that dictate how to properly query a GL symbol are complex. The
435 // rules depend on the OS, on the winsys API, and even on the particular driver
436 // being used. The rules differ between EGL 1.4 and EGL 1.5; differ between
437 // Linux, Windows, and Mac; and differ between Mesa and Mali.
439 // This function hides that complexity with a naive heuristic: try, then try
440 // again.
441 static void *
442 get_gl_symbol(const struct options *opts, const char *name)
444 void *sym = NULL;
446 if (waffle_dl_can_open(opts->dl)) {
447 sym = waffle_dl_sym(opts->dl, name);
450 if (!sym) {
451 sym = waffle_get_proc_address(name);
454 return sym;
457 static bool
458 draw(struct waffle_window *window, bool resize)
460 bool ok;
461 unsigned char *colors;
462 int width = window_width;
463 int height = window_height;
465 #if !defined(_WIN32)
466 static const struct timespec sleep_time = {
467 // 0.5 sec
468 .tv_sec = 0,
469 .tv_nsec = 500000000,
471 #endif
473 for (int i = 0; i < 3; ++i) {
474 switch (i) {
475 case 0: glClearColor(1, 0, 0, 1); break;
476 case 1: glClearColor(0, 1, 0, 1); break;
477 case 2: glClearColor(0, 0, 1, 1); break;
478 case 3: abort(); break;
481 if (resize) {
482 width = (i + 2) * 40;
483 height = width;
484 waffle_window_resize(window, width, height);
485 glViewport(0, 0, width, height);
488 glClear(GL_COLOR_BUFFER_BIT);
490 colors = calloc(width * height * 4, sizeof(*colors));
491 glReadPixels(0, 0,
492 width, height,
493 GL_RGBA, GL_UNSIGNED_BYTE,
494 colors);
495 for (int j = 0; j < width * height * 4; j += 4) {
496 if ((colors[j] != (i == 0 ? 0xff : 0)) ||
497 (colors[j+1] != (i == 1 ? 0xff : 0)) ||
498 (colors[j+2] != (i == 2 ? 0xff : 0)) ||
499 (colors[j+3] != 0xff)) {
500 fprintf(stderr, "glReadPixels returned unexpected result\n");
501 break;
504 free(colors);
506 if (i == 0) {
507 ok = waffle_window_show(window);
508 if (!ok)
509 return false;
512 ok = waffle_window_swap_buffers(window);
513 if (!ok)
514 return false;
516 #if !defined(_WIN32)
517 nanosleep(&sleep_time, NULL);
518 #else
519 Sleep(500);
520 #endif
523 return true;
526 #ifdef __APPLE__
528 static NSAutoreleasePool *pool;
530 static void
531 cocoa_init(void)
533 // From the NSApplication Class Reference:
534 // [...] if you do need to use Cocoa classes within the main()
535 // function itself (other than to load nib files or to instantiate
536 // NSApplication), you should create an autorelease pool before using
537 // the classes and then release the pool when you’re done.
538 pool = [[NSAutoreleasePool alloc] init];
540 // From the NSApplication Class Reference:
541 // The sharedApplication class method initializes the display
542 // environment and connects your program to the window server and the
543 // display server.
545 // It also creates the singleton NSApp if it does not yet exist.
546 [NSApplication sharedApplication];
549 static void
550 cocoa_finish(void)
552 [pool drain];
555 static void
556 removeArg(int index, int *argc, char **argv)
558 --*argc;
559 for (; index < *argc; ++index)
560 argv[index] = argv[index + 1];
563 static void
564 removeXcodeArgs(int *argc, char **argv)
566 // Xcode sometimes adds additional arguments.
567 for (int i = 1; i < *argc; )
569 if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0 ||
570 strcmp(argv[i], "-ApplePersistenceIgnoreState" ) == 0)
572 removeArg(i, argc, argv);
573 removeArg(i, argc, argv);
574 } else
575 ++i;
579 #endif // __APPLE__
581 #ifdef __native_client__
582 #include "ppapi_simple/ps_main.h"
584 // We need to rename main() for native client
585 // because ppapi_simple already defines main().
587 int basic_test_main(int argc, char **argv);
588 PPAPI_SIMPLE_REGISTER_MAIN(basic_test_main)
590 basic_test_main(int argc, char **argv)
591 #else
593 main(int argc, char **argv)
594 #endif
596 bool ok;
597 int i;
599 struct options opts = {0};
601 int32_t init_attrib_list[3];
602 int32_t config_attrib_list[64];
603 intptr_t window_attrib_list[5];
605 struct waffle_display *dpy;
606 struct waffle_config *config;
607 struct waffle_context *ctx;
608 struct waffle_window *window;
610 GLint context_flags = 0;
612 #ifdef __APPLE__
613 cocoa_init();
614 #endif
616 #ifdef __native_client__
617 // Fixed arguments for native client.
618 opts.context_api = WAFFLE_CONTEXT_OPENGL_ES2;
619 opts.platform = WAFFLE_PLATFORM_NACL;
620 opts.dl = WAFFLE_DL_OPENGL_ES2;
621 opts.context_profile = WAFFLE_NONE;
622 opts.context_version = -1;
623 #else
624 ok = parse_args(argc, argv, &opts);
625 if (!ok)
626 exit(EXIT_FAILURE);
627 #endif
629 i = 0;
630 init_attrib_list[i++] = WAFFLE_PLATFORM;
631 init_attrib_list[i++] = opts.platform;
632 init_attrib_list[i++] = WAFFLE_NONE;
634 ok = waffle_init(init_attrib_list);
635 if (!ok)
636 error_waffle();
638 dpy = waffle_display_connect(NULL);
639 if (!dpy)
640 error_waffle();
642 if (!waffle_display_supports_context_api(dpy, opts.context_api)) {
643 error_printf("Display does not support %s",
644 waffle_enum_to_string(opts.context_api));
647 glClear = get_gl_symbol(&opts, "glClear");
648 if (!glClear)
649 error_get_gl_symbol("glClear");
651 glClearColor = get_gl_symbol(&opts, "glClearColor");
652 if (!glClearColor)
653 error_get_gl_symbol("glClearColor");
655 glGetError = get_gl_symbol(&opts, "glGetError");
656 if (!glGetError)
657 error_get_gl_symbol("glGetError");
659 glGetIntegerv = get_gl_symbol(&opts, "glGetIntegerv");
660 if (!glGetIntegerv)
661 error_get_gl_symbol("glGetIntegerv");
663 glReadPixels = get_gl_symbol(&opts, "glReadPixels");
664 if (!glReadPixels)
665 error_get_gl_symbol("glReadPixels");
667 glViewport = get_gl_symbol(&opts, "glViewport");
668 if (!glViewport)
669 error_get_gl_symbol("glViewport");
671 i = 0;
672 config_attrib_list[i++] = WAFFLE_CONTEXT_API;
673 config_attrib_list[i++] = opts.context_api;
675 if (opts.context_profile != -1) {
676 config_attrib_list[i++] = WAFFLE_CONTEXT_PROFILE;
677 config_attrib_list[i++] = opts.context_profile;
680 if (opts.context_version != -1) {
681 config_attrib_list[i++] = WAFFLE_CONTEXT_MAJOR_VERSION;
682 config_attrib_list[i++] = opts.context_version / 10;
683 config_attrib_list[i++] = WAFFLE_CONTEXT_MINOR_VERSION;
684 config_attrib_list[i++] = opts.context_version % 10;
687 if (opts.context_forward_compatible) {
688 config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE;
689 config_attrib_list[i++] = true;
692 if (opts.context_debug) {
693 config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG;
694 config_attrib_list[i++] = true;
697 if (opts.context_robust) {
698 config_attrib_list[i++] = WAFFLE_CONTEXT_ROBUST_ACCESS,
699 config_attrib_list[i++] = true;
702 config_attrib_list[i++] = WAFFLE_RED_SIZE;
703 config_attrib_list[i++] = 8;
704 config_attrib_list[i++] = WAFFLE_GREEN_SIZE;
705 config_attrib_list[i++] = 8;
706 config_attrib_list[i++] = WAFFLE_BLUE_SIZE;
707 config_attrib_list[i++] = 8;
708 config_attrib_list[i++] = WAFFLE_ALPHA_SIZE;
709 config_attrib_list[i++] = 8;
710 config_attrib_list[i++] = WAFFLE_DOUBLE_BUFFERED;
711 config_attrib_list[i++] = true;
712 config_attrib_list[i++] = 0;
714 config = waffle_config_choose(dpy, config_attrib_list);
715 if (!config)
716 error_waffle();
718 ctx = waffle_context_create(config, NULL);
719 if (!ctx)
720 error_waffle();
723 i = 0;
724 if (opts.fullscreen) {
725 window_attrib_list[i++] = WAFFLE_WINDOW_FULLSCREEN;
726 window_attrib_list[i++] = true;
727 window_attrib_list[i++] = 0;
728 } else {
729 window_attrib_list[i++] = WAFFLE_WINDOW_WIDTH;
730 window_attrib_list[i++] = window_width;
731 window_attrib_list[i++] = WAFFLE_WINDOW_HEIGHT;
732 window_attrib_list[i++] = window_height;
733 window_attrib_list[i++] = 0;
736 window = waffle_window_create2(config, window_attrib_list);
737 if (!window)
738 error_waffle();
740 ok = waffle_make_current(dpy, window, ctx);
741 if (!ok)
742 error_waffle();
744 if (opts.context_forward_compatible || opts.context_debug) {
745 glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
748 if (glGetError())
749 error_printf("glGetIntegerv(GL_CONTEXT_FLAGS) failed");
751 if (opts.context_forward_compatible
752 && !(context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) {
753 error_printf("context is not forward-compatible");
756 if (opts.context_debug
757 && !(context_flags & GL_CONTEXT_FLAG_DEBUG_BIT)) {
758 error_printf("context is not a debug context");
761 // Don't verify if the context is robust because that pollutes this simple
762 // example program with hairy GL logic. The method of verifying if
763 // a context is robust varies on the combination of context profile,
764 // context version, and supported extensions.
766 ok = draw(window, opts.resize_window);
767 if (!ok)
768 error_waffle();
770 ok = waffle_make_current(dpy, NULL, NULL);
771 if (!ok)
772 error_waffle();
774 ok = waffle_window_destroy(window);
775 if (!ok)
776 error_waffle();
778 ok = waffle_context_destroy(ctx);
779 if (!ok)
780 error_waffle();
782 ok = waffle_config_destroy(config);
783 if (!ok)
784 error_waffle();
786 ok = waffle_display_disconnect(dpy);
787 if (!ok)
788 error_waffle();
790 ok = waffle_teardown();
791 if (!ok)
792 error_waffle();
794 #ifdef __APPLE__
795 cocoa_finish();
796 #endif
798 printf("gl_basic: run was successful\n");
799 return EXIT_SUCCESS;