1 // Copyright 2012 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.
10 //
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.
14 //
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.
25 
26 /// @file
27 /// @brief Test basic OpenGL rendering with all platform/gl_api combinations.
28 ///
29 /// Each test does the following:
30 ///     1. Initialize waffle with a platform and gl_api.
31 ///     2. Create a context and window.
32 ///     3. On the window call waffle_make_current, glClear,
33 ///        and waffle_swap_buffers.
34 ///     4. Verify the window contents with glReadPixels.
35 ///     5. Tear down all waffle state.
36 
37 #include <stdarg.h> // for va_start, va_end
38 #include <setjmp.h> // for cmocka.h
39 #include <ctype.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <getopt.h>
44 #include <sys/types.h>
45 #if !defined(_WIN32)
46 #include <unistd.h>
47 #include <sys/wait.h>
48 #else
49 #include <windows.h>
50 #endif
51 
52 #include <cmocka.h>
53 #include "waffle.h"
54 
55 #include "gl_basic_cocoa.h"
56 
57 enum {
58     // Choosing a smaller window would shorten the execution time of pixel
59     // validation, but Windows 7 enforces a minimum size.
60     WINDOW_WIDTH    = 320,
61     WINDOW_HEIGHT   = 240,
62 };
63 
64 static const float      RED_F       = 1.00;
65 static const float      GREEN_F     = 0.00;
66 static const float      BLUE_F      = 1.00;
67 static const float      ALPHA_F     = 1.00;
68 
69 static const uint8_t    RED_UB      = 0xff;
70 static const uint8_t    GREEN_UB    = 0x00;
71 static const uint8_t    BLUE_UB     = 0xff;
72 static const uint8_t    ALPHA_UB    = 0xff;
73 
74 struct test_state_gl_basic {
75     bool initialized;
76     struct waffle_display *dpy;
77     struct waffle_config *config;
78     struct waffle_window *window;
79     struct waffle_context *ctx;
80 
81     uint8_t actual_pixels[4 * WINDOW_WIDTH * WINDOW_HEIGHT];
82     uint8_t expect_pixels[4 * WINDOW_WIDTH * WINDOW_HEIGHT];
83 };
84 
85 #define ASSERT_GL(statement) \
86     do { \
87         statement; \
88         assert_false(glGetError()); \
89     } while (0)
90 
91 typedef unsigned int        GLenum;
92 typedef unsigned char       GLboolean;
93 typedef unsigned int        GLbitfield;
94 typedef void                GLvoid;
95 typedef signed char         GLbyte;     /* 1-byte signed */
96 typedef short               GLshort;    /* 2-byte signed */
97 typedef int                 GLint;      /* 4-byte signed */
98 typedef unsigned char       GLubyte;    /* 1-byte unsigned */
99 typedef unsigned short      GLushort;   /* 2-byte unsigned */
100 typedef unsigned int        GLuint;     /* 4-byte unsigned */
101 typedef int                 GLsizei;    /* 4-byte signed */
102 typedef float               GLfloat;    /* single precision float */
103 typedef float               GLclampf;   /* single precision float in [0,1] */
104 typedef double              GLdouble;   /* double precision float */
105 typedef double              GLclampd;   /* double precision float in [0,1] */
106 
107 #define GL_NO_ERROR                 0x0000
108 #define GL_VERSION                  0x1F02
109 #define GL_UNSIGNED_BYTE            0x1401
110 #define GL_UNSIGNED_INT             0x1405
111 #define GL_FLOAT                    0x1406
112 #define GL_RGB                      0x1907
113 #define GL_RGBA                     0x1908
114 #define GL_COLOR_BUFFER_BIT         0x00004000
115 #define GL_CONTEXT_FLAGS            0x821e
116 #define GL_CONTEXT_ROBUST_ACCESS    0x90F3
117 
118 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
119 #define GL_CONTEXT_FLAG_DEBUG_BIT              0x00000002
120 
121 #define GL_CONTEXT_PROFILE_MASK     0x9126
122 #define GL_CONTEXT_CORE_PROFILE_BIT            0x00000001
123 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT   0x00000002
124 
125 #ifndef _WIN32
126 #define APIENTRY
127 #else
128 #ifndef APIENTRY
129 #define APIENTRY __stdcall
130 #endif
131 #endif
132 
133 static GLenum (APIENTRY *glGetError)(void);
134 static const GLubyte *(APIENTRY *glGetString)(GLenum name);
135 static void (APIENTRY *glGetIntegerv)(GLenum pname, GLint *params);
136 static void (APIENTRY *glClearColor)(GLclampf red,
137                                      GLclampf green,
138                                      GLclampf blue,
139                                      GLclampf alpha);
140 static void (APIENTRY *glClear)(GLbitfield mask);
141 static void (APIENTRY *glReadPixels)(GLint x, GLint y,
142                                      GLsizei width, GLsizei height,
143                                      GLenum format, GLenum type,
144                                      GLvoid *pixels );
145 
146 static int
setup(void ** state)147 setup(void **state)
148 {
149     struct test_state_gl_basic *ts;
150 
151     ts = calloc(1, sizeof(*ts));
152     if (!ts)
153         return -1;
154 
155     for (int y = 0 ; y < WINDOW_HEIGHT; ++y) {
156         for (int x = 0; x < WINDOW_WIDTH; ++x) {
157             uint8_t *p = &ts->expect_pixels[4 * (y * WINDOW_WIDTH + x)];
158             p[0] = RED_UB;
159             p[1] = GREEN_UB;
160             p[2] = BLUE_UB;
161             p[3] = ALPHA_UB;
162         }
163     }
164     // Fill actual_pixels with canaries.
165     memset(&ts->actual_pixels, 0x99, sizeof(ts->actual_pixels));
166 
167     *state = ts;
168     return 0;
169 }
170 
171 static int
teardown(void ** state)172 teardown(void **state)
173 {
174     free(*state);
175     return 0;
176 }
177 
178 // The rules that dictate how to properly query a GL symbol are complex. The
179 // rules depend on the OS, on the winsys API, and even on the particular driver
180 // being used. The rules differ between EGL 1.4 and EGL 1.5; differ between
181 // Linux, Windows, and Mac; and differ between Mesa and Mali.
182 //
183 // This function hides that complexity with a naive heuristic: try, then try
184 // again.
185 static void *
get_gl_symbol(enum waffle_enum context_api,const char * name)186 get_gl_symbol(enum waffle_enum context_api, const char *name)
187 {
188     void *sym = NULL;
189     enum waffle_enum dl = 0;
190 
191     switch (context_api) {
192         case WAFFLE_CONTEXT_OPENGL: dl = WAFFLE_DL_OPENGL; break;
193         case WAFFLE_CONTEXT_OPENGL_ES1: dl = WAFFLE_DL_OPENGL_ES1; break;
194         case WAFFLE_CONTEXT_OPENGL_ES2: dl = WAFFLE_DL_OPENGL_ES2; break;
195         case WAFFLE_CONTEXT_OPENGL_ES3: dl = WAFFLE_DL_OPENGL_ES3; break;
196         default: assert_true(0); break;
197     }
198 
199     if (waffle_dl_can_open(dl)) {
200         sym = waffle_dl_sym(dl, name);
201     }
202 
203     if (!sym) {
204         sym = waffle_get_proc_address(name);
205     }
206 
207     return sym;
208 }
209 
210 static int
gl_basic_init(void ** state,int32_t waffle_platform)211 gl_basic_init(void **state, int32_t waffle_platform)
212 {
213     struct test_state_gl_basic *ts;
214     int ret;
215 
216     ret = setup((void **)&ts);
217     if (ret)
218         return -1;
219 
220     const int32_t init_attrib_list[] = {
221         WAFFLE_PLATFORM, waffle_platform,
222         0,
223     };
224 
225     ts->initialized = waffle_init(init_attrib_list);
226     if (!ts->initialized) {
227         // XXX: does cmocka call teardown if setup fails ?
228         teardown(state);
229         return -1;
230     }
231 
232     *state = ts;
233     return 0;
234 }
235 
236 static int
gl_basic_fini(void ** state)237 gl_basic_fini(void **state)
238 {
239     struct test_state_gl_basic *ts = *state;
240     bool ret = false;
241 
242     // XXX: return immediately on error or attempt to finish the teardown ?
243     if (ts->dpy) // XXX: keep track if we've had current ctx ?
244         ret = waffle_make_current(ts->dpy, NULL, NULL);
245     if (ts->window)
246         ret = waffle_window_destroy(ts->window);
247     if (ts->ctx)
248         ret = waffle_context_destroy(ts->ctx);
249     if (ts->config)
250         ret = waffle_config_destroy(ts->config);
251     if (ts->dpy)
252         ret = waffle_display_disconnect(ts->dpy);
253 
254     if (ts->initialized)
255         ret = waffle_teardown();
256 
257     teardown(state);
258     return ret ? 0 : -1;
259 }
260 
261 #define gl_basic_draw(state, ...) \
262     \
263     gl_basic_draw__(state, (struct gl_basic_draw_args__) { \
264         .api = 0, \
265         .version = WAFFLE_DONT_CARE, \
266         .profile = WAFFLE_DONT_CARE, \
267         .forward_compatible = false, \
268         .debug = false, \
269         .robust = false, \
270         .alpha = false, \
271         .expect_error = WAFFLE_NO_ERROR, \
272         __VA_ARGS__ \
273         })
274 
275 struct gl_basic_draw_args__ {
276     int32_t api;
277     int32_t version;
278     int32_t profile;
279     int32_t expect_error;
280     bool forward_compatible;
281     bool debug;
282     bool robust;
283     bool alpha;
284 };
285 
286 #define assert_int_equal_print(_a, _b) \
287     if (_a != _b) {\
288 	fprintf(stderr, #_a " (%d) != " #_b "(%d)\n", _a, _b); \
289 	assert_true(0 && "Integer comparison failed"); \
290     }
291 
292 #define assert_int_ge(_a, _b) \
293     if (_a < _b) {\
294 	fprintf(stderr, #_a " (%d) < " #_b "(%d)\n", _a, _b); \
295 	assert_true(0 && "Integer comparison failed"); \
296     }
297 
298 #define assert_in_range_print(_a, _min, _max) \
299     if (_a < _min || _a > _max) {\
300 	fprintf(stderr, #_a " (%d) outside range " #_min "(%d) - " #_max "(%d)\n", \
301                 _a, _min, _max); \
302 	assert_true(0 && "Integer comparison failed"); \
303     }
304 
305 #define assert_string_len_equal(_actual, _expected, _len) \
306     if (strncmp(_actual, _expected, _len) != 0) {\
307 	fprintf(stderr, "Expected (" #_expected "): \"%.*s\"\n", (int)_len, _expected); \
308 	fprintf(stderr, "Received (" #_actual "): \"%.*s\"\n", (int)_len, _actual); \
309 	assert_true(0 && "String comparison failed"); \
310     }
311 
312 static void
error_waffle(void)313 error_waffle(void)
314 {
315     const struct waffle_error_info *info = waffle_error_get_info();
316     const char *code = waffle_error_to_string(info->code);
317 
318     if (info->message_length > 0)
319         fprintf(stderr, "Waffle error: 0x%x %s: %s\n", info->code, code, info->message);
320     else
321         fprintf(stderr, "Waffle error: 0x%x %s\n", info->code, code);
322 }
323 
324 #define assert_true_with_wfl_error(_arg) \
325     if (!(_arg)) { \
326         error_waffle(); \
327         assert_true(0); \
328     }
329 
330 static void
gl_basic_draw__(void ** state,struct gl_basic_draw_args__ args)331 gl_basic_draw__(void **state, struct gl_basic_draw_args__ args)
332 {
333     struct test_state_gl_basic *ts = *state;
334     int32_t waffle_context_api = args.api;
335     int32_t context_version = args.version;
336     int32_t context_profile = args.profile;
337     int32_t expect_error = args.expect_error;
338     bool context_forward_compatible = args.forward_compatible;
339     bool context_debug = args.debug;
340     bool context_robust = args.robust;
341     bool alpha = args.alpha;
342     bool ret;
343 
344     int32_t config_attrib_list[64];
345     int i;
346 
347     const intptr_t window_attrib_list[] = {
348         WAFFLE_WINDOW_WIDTH,    WINDOW_WIDTH,
349         WAFFLE_WINDOW_HEIGHT,   WINDOW_HEIGHT,
350         0,
351     };
352 
353     i = 0;
354     config_attrib_list[i++] = WAFFLE_CONTEXT_API;
355     config_attrib_list[i++] = waffle_context_api;
356     if (context_version != WAFFLE_DONT_CARE) {
357         config_attrib_list[i++] = WAFFLE_CONTEXT_MAJOR_VERSION;
358         config_attrib_list[i++] = context_version / 10;
359         config_attrib_list[i++] = WAFFLE_CONTEXT_MINOR_VERSION;
360         config_attrib_list[i++] = context_version % 10;
361     }
362     if (context_profile != WAFFLE_DONT_CARE) {
363         config_attrib_list[i++] = WAFFLE_CONTEXT_PROFILE;
364         config_attrib_list[i++] = context_profile;
365     }
366     if (context_forward_compatible) {
367         config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE;
368         config_attrib_list[i++] = true;
369     }
370     if (context_debug) {
371         config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG;
372         config_attrib_list[i++] = true;
373     }
374     if (context_robust) {
375         config_attrib_list[i++] = WAFFLE_CONTEXT_ROBUST_ACCESS;
376         config_attrib_list[i++] = true;
377     }
378     config_attrib_list[i++] = WAFFLE_RED_SIZE;
379     config_attrib_list[i++] = 8;
380     config_attrib_list[i++] = WAFFLE_GREEN_SIZE;
381     config_attrib_list[i++] = 8;
382     config_attrib_list[i++] = WAFFLE_BLUE_SIZE;
383     config_attrib_list[i++] = 8;
384     config_attrib_list[i++] = WAFFLE_ALPHA_SIZE;
385     config_attrib_list[i++] = alpha;
386     config_attrib_list[i++] = 0;
387 
388     // Create objects.
389     ts->dpy = waffle_display_connect(NULL);
390     assert_true_with_wfl_error(ts->dpy);
391 
392     ts->config = waffle_config_choose(ts->dpy, config_attrib_list);
393     if (expect_error) {
394         assert_true(ts->config == NULL);
395         assert_true(waffle_error_get_code() == expect_error);
396         return;
397     } else if (ts->config == NULL) {
398         switch (waffle_error_get_code()) {
399         case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM:
400             // fall-through
401         case WAFFLE_ERROR_UNKNOWN:
402             // Assume that the native platform rejected the requested
403             // config flavor.
404             skip();
405         default:
406             assert_true_with_wfl_error(ts->config);
407         }
408     }
409 
410     ts->window = waffle_window_create2(ts->config, window_attrib_list);
411     assert_true_with_wfl_error(ts->window);
412 
413     ret = waffle_window_show(ts->window);
414     assert_true_with_wfl_error(ret);
415 
416     ts->ctx = waffle_context_create(ts->config, NULL);
417     if (ts->ctx == NULL) {
418         switch (waffle_error_get_code()) {
419         case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM:
420             // fall-through
421         case WAFFLE_ERROR_UNKNOWN:
422             // Assume that the native platform rejected the requested
423             // context flavor.
424             skip();
425         default:
426             assert_true_with_wfl_error(ts->ctx);
427         }
428     }
429 
430     // Get OpenGL functions.
431     assert_true(glClear         = get_gl_symbol(waffle_context_api, "glClear"));
432     assert_true(glClearColor    = get_gl_symbol(waffle_context_api, "glClearColor"));
433     assert_true(glGetError      = get_gl_symbol(waffle_context_api, "glGetError"));
434     assert_true(glGetIntegerv   = get_gl_symbol(waffle_context_api, "glGetIntegerv"));
435     assert_true(glReadPixels    = get_gl_symbol(waffle_context_api, "glReadPixels"));
436     assert_true(glGetString     = get_gl_symbol(waffle_context_api, "glGetString"));
437 
438     ret = waffle_make_current(ts->dpy, ts->window, ts->ctx);
439     assert_true_with_wfl_error(ret);
440 
441     assert_true(waffle_get_current_display() == ts->dpy);
442     assert_true(waffle_get_current_window() == ts->window);
443     assert_true(waffle_get_current_context() == ts->ctx);
444 
445     const char *version_str, *expected_version_str;
446     int major, minor, count;
447 
448     ASSERT_GL(version_str = (const char *) glGetString(GL_VERSION));
449     assert_true(version_str != NULL);
450 
451     switch (waffle_context_api) {
452     case WAFFLE_CONTEXT_OPENGL:
453 	expected_version_str = "";
454         break;
455     case WAFFLE_CONTEXT_OPENGL_ES1:
456 	expected_version_str = "OpenGL ES-CM ";
457         break;
458     case WAFFLE_CONTEXT_OPENGL_ES2:
459     case WAFFLE_CONTEXT_OPENGL_ES3:
460 	expected_version_str = "OpenGL ES ";
461         break;
462     default:
463         assert_true(0);
464         break;
465     }
466 
467     const size_t version_str_len = strlen(expected_version_str);
468     assert_string_len_equal(version_str, expected_version_str, version_str_len);
469     version_str += version_str_len;
470 
471     count = sscanf(version_str, "%d.%d", &major, &minor);
472     assert_int_equal_print(count, 2);
473     assert_int_ge(major, 0);
474     assert_in_range_print(minor, 0, 10);
475 
476     if (context_version != WAFFLE_DONT_CARE) {
477         int expected_major = context_version / 10;
478         int expected_minor = context_version % 10;
479 
480         assert_int_ge(major, expected_major);
481         if (major == expected_major)
482            assert_int_ge(minor, expected_minor);
483     }
484 
485     const char *profile_suffix = "";
486 
487     if (waffle_context_api == WAFFLE_CONTEXT_OPENGL) {
488         switch (context_profile) {
489         case WAFFLE_CONTEXT_CORE_PROFILE:
490             profile_suffix = " (Core Profile)";
491 #ifdef __APPLE__
492             fprintf(stderr, "MacOS Core contexts, omit the \"%s\" suffix in glGetString(GL_VERSION)."
493                             "Applying workaround.\n", profile_suffix);
494             profile_suffix = "";
495 #endif
496             break;
497         case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
498             // HACK: seems like Mesa 19.3.3 at least will report
499             if (context_forward_compatible)
500                 profile_suffix = " (Core Profile)";
501             else
502                 profile_suffix = " (Compatibility Profile)";
503             break;
504         case WAFFLE_DONT_CARE:
505             break;
506         default:
507             assert_true(0);
508             break;
509         }
510     }
511 
512     char profile_str[30]; // 30 should be enough ;-)
513     sprintf(profile_str, "%d.%d%s", major, minor, profile_suffix);
514 
515     const size_t profile_str_len = strlen(profile_str);
516     assert_string_len_equal(version_str, profile_str, profile_str_len);
517 
518     int version_10x = 10 * major + minor;
519 
520     // Another profile check
521     if (waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 32) {
522         GLint profile_mask = 0;
523         glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask);
524 
525         switch (context_profile) {
526         case WAFFLE_CONTEXT_CORE_PROFILE:
527             assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
528             break;
529         case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
530             // HACK: seems like Mesa 19.3.3 at least will report
531             if (context_forward_compatible)
532                 assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
533             else
534                 assert_true(profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT);
535             break;
536         case WAFFLE_DONT_CARE:
537             break;
538         default:
539             assert_true(0);
540             break;
541         }
542     }
543 
544     if ((waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 30) ||
545         (waffle_context_api != WAFFLE_CONTEXT_OPENGL && version_10x >= 32)) {
546         GLint context_flags = 0;
547         if (context_forward_compatible || context_debug) {
548             glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
549         }
550 
551         if (context_forward_compatible) {
552             assert_true(context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
553         }
554 
555         if (context_debug) {
556             assert_true(context_flags & GL_CONTEXT_FLAG_DEBUG_BIT);
557         }
558     }
559 
560     // GL_ROBUST_ACCESS comes with the following extensions
561     // GL_ARB_robustness
562     // GL_EXT_robustness
563     // GL_KHR_robustness
564     //
565     // To keep it simple, assume the correct extension is there if
566     // glGetError is happy ;-)
567     if (context_robust) {
568         GLint robust_flag = 0;
569         glGetIntegerv(GL_CONTEXT_ROBUST_ACCESS, &robust_flag);
570 
571         if (glGetError() == GL_NO_ERROR)
572             assert_true(robust_flag);
573     }
574 
575     // Draw.
576     ASSERT_GL(glClearColor(RED_F, GREEN_F, BLUE_F, ALPHA_F));
577     ASSERT_GL(glClear(GL_COLOR_BUFFER_BIT));
578     ASSERT_GL(glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT,
579                            GL_RGBA, GL_UNSIGNED_BYTE,
580                            ts->actual_pixels));
581     ret = waffle_window_swap_buffers(ts->window);
582     assert_true_with_wfl_error(ret);
583 
584     assert_memory_equal(&ts->actual_pixels, &ts->expect_pixels,
585                         sizeof(ts->expect_pixels));
586 }
587 
588 //
589 // List of tests common to all platforms.
590 //
591 
592 #define test_XX_rgb(context_api, waffle_api, error)                     \
593 static void test_gl_basic_##context_api##_rgb(void **state)             \
594 {                                                                       \
595     gl_basic_draw(state,                                                \
596                   .api=WAFFLE_CONTEXT_##waffle_api,                     \
597                   .expect_error=WAFFLE_##error);                        \
598 }
599 
600 #define test_XX_rgba(context_api, waffle_api, error)                    \
601 static void test_gl_basic_##context_api##_rgba(void **state)            \
602 {                                                                       \
603     gl_basic_draw(state,                                                \
604                   .api=WAFFLE_CONTEXT_##waffle_api,                     \
605                   .alpha=true,                                          \
606                   .expect_error=WAFFLE_##error);                        \
607 }
608 
609 #define test_XX_fwdcompat(context_api, waffle_api, error)               \
610 static void test_gl_basic_##context_api##_fwdcompat(void **state)       \
611 {                                                                       \
612     gl_basic_draw(state,                                                \
613                   .api=WAFFLE_CONTEXT_##waffle_api,                     \
614                   .forward_compatible=true,                             \
615                   .expect_error=WAFFLE_##error);                        \
616 }
617 
618 #define test_XX_debug(context_api, waffle_api, error)                   \
619 static void test_gl_basic_##context_api##_debug(void **state)           \
620 {                                                                       \
621     gl_basic_draw(state,                                                \
622                   .api=WAFFLE_CONTEXT_##waffle_api,                     \
623                   .debug=true,                                          \
624                   .expect_error=WAFFLE_##error);                        \
625 }
626 
627 #define test_XX_robust(context_api, waffle_api, error)                  \
628 static void test_gl_basic_##context_api##_robust(void **state)          \
629 {                                                                       \
630     gl_basic_draw(state,                                                \
631                   .api=WAFFLE_CONTEXT_##waffle_api,                     \
632                   .robust=true,                                         \
633                   .expect_error=WAFFLE_##error);                        \
634 }
635 
636 #define test_glXX(waffle_version, error)                                \
637 static void test_gl_basic_gl##waffle_version(void **state)              \
638 {                                                                       \
639     gl_basic_draw(state,                                                \
640                   .api=WAFFLE_CONTEXT_OPENGL,                           \
641                   .version=waffle_version,                              \
642                   .expect_error=WAFFLE_##error);                        \
643 }
644 
645 #define test_glXX_fwdcompat(waffle_version, error)                      \
646 static void test_gl_basic_gl##waffle_version##_fwdcompat(void **state)  \
647 {                                                                       \
648     gl_basic_draw(state,                                                \
649                   .api=WAFFLE_CONTEXT_OPENGL,                           \
650                   .version=waffle_version,                              \
651                   .forward_compatible=true,                             \
652                   .expect_error=WAFFLE_##error);                        \
653 }
654 
655 #define test_glXX_core(waffle_version, error)                           \
656 static void test_gl_basic_gl##waffle_version##_core(void **state)       \
657 {                                                                       \
658     gl_basic_draw(state,                                                \
659                   .api=WAFFLE_CONTEXT_OPENGL,                           \
660                   .version=waffle_version,                              \
661                   .profile=WAFFLE_CONTEXT_CORE_PROFILE,                 \
662                   .expect_error=WAFFLE_##error);                        \
663 }
664 
665 #define test_glXX_core_fwdcompat(waffle_version, error)                 \
666 static void test_gl_basic_gl##waffle_version##_core_fwdcompat(void **state) \
667 {                                                                       \
668     gl_basic_draw(state,                                                \
669                   .api=WAFFLE_CONTEXT_OPENGL,                           \
670                   .version=waffle_version,                              \
671                   .profile=WAFFLE_CONTEXT_CORE_PROFILE,                 \
672                   .forward_compatible=true,                             \
673                   .expect_error=WAFFLE_##error);                        \
674 }
675 
676 #define test_glXX_core_debug(waffle_version, error)                     \
677 static void test_gl_basic_gl##waffle_version##_core_debug(void **state) \
678 {                                                                       \
679     gl_basic_draw(state,                                                \
680                   .api=WAFFLE_CONTEXT_OPENGL,                           \
681                   .version=waffle_version,                              \
682                   .profile=WAFFLE_CONTEXT_CORE_PROFILE,                 \
683                   .debug=true,                                          \
684                   .expect_error=WAFFLE_##error);                        \
685 }
686 
687 #define test_glXX_core_robust(waffle_version, error)                    \
688 static void test_gl_basic_gl##waffle_version##_core_robust(void **state) \
689 {                                                                       \
690     gl_basic_draw(state,                                                \
691                   .api=WAFFLE_CONTEXT_OPENGL,                           \
692                   .version=waffle_version,                              \
693                   .profile=WAFFLE_CONTEXT_CORE_PROFILE,                 \
694                   .robust=true,                                         \
695                   .expect_error=WAFFLE_##error);                        \
696 }
697 
698 #define test_glXX_compat(waffle_version, error)                         \
699 static void test_gl_basic_gl##waffle_version##_compat(void **state)     \
700 {                                                                       \
701     gl_basic_draw(state,                                                \
702                   .api=WAFFLE_CONTEXT_OPENGL,                           \
703                   .version=waffle_version,                              \
704                   .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,        \
705                   .expect_error=WAFFLE_##error);                        \
706 }
707 
708 #define test_glXX_compat_fwdcompat(waffle_version, error)               \
709 static void test_gl_basic_gl##waffle_version##_compat_fwdcompat(void **state) \
710 {                                                                       \
711     gl_basic_draw(state,                                                \
712                   .api=WAFFLE_CONTEXT_OPENGL,                           \
713                   .version=waffle_version,                              \
714                   .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,        \
715                   .forward_compatible=true,                             \
716                   .expect_error=WAFFLE_##error);                        \
717 }
718 
719 #define test_glXX_compat_debug(waffle_version, error)                   \
720 static void test_gl_basic_gl##waffle_version##_compat_debug(void **state) \
721 {                                                                       \
722     gl_basic_draw(state,                                                \
723                   .api=WAFFLE_CONTEXT_OPENGL,                           \
724                   .version=waffle_version,                              \
725                   .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,        \
726                   .debug=true,                                          \
727                   .expect_error=WAFFLE_##error);                        \
728 }
729 
730 #define test_glXX_compat_robust(waffle_version, error)                  \
731 static void test_gl_basic_gl##waffle_version##_compat_robust(void **state) \
732 {                                                                       \
733     gl_basic_draw(state,                                                \
734                   .api=WAFFLE_CONTEXT_OPENGL,                           \
735                   .version=waffle_version,                              \
736                   .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,        \
737                   .robust=true,                                         \
738                   .expect_error=WAFFLE_##error);                        \
739 }
740 
741 #define test_glesXX(api_version, waffle_version, error)                 \
742 static void test_gl_basic_gles##waffle_version(void **state)            \
743 {                                                                       \
744     gl_basic_draw(state,                                                \
745                   .api=WAFFLE_CONTEXT_OPENGL_ES##api_version,           \
746                   .version=waffle_version,                              \
747                   .expect_error=WAFFLE_##error);                        \
748 }
749 
750 
751 #define CREATE_TESTSUITE(waffle_platform, platform)                     \
752                                                                         \
753 static int                                                              \
754 setup_##platform(void **state)                                          \
755 {                                                                       \
756     return gl_basic_init(state, waffle_platform);                       \
757 }                                                                       \
758                                                                         \
759 static int                                                              \
760 testsuite_##platform(void)                                              \
761 {                                                                       \
762     const struct CMUnitTest tests[] = {                                 \
763                                                                         \
764         unit_test_make(test_gl_basic_gl_rgb),                           \
765         unit_test_make(test_gl_basic_gl_rgba),                          \
766         unit_test_make(test_gl_basic_gl_fwdcompat),                     \
767         unit_test_make(test_gl_basic_gl_debug),                         \
768         unit_test_make(test_gl_basic_gl_robust),                        \
769                                                                         \
770         unit_test_make(test_gl_basic_gl10),                             \
771         unit_test_make(test_gl_basic_gl11),                             \
772         unit_test_make(test_gl_basic_gl12),                             \
773         unit_test_make(test_gl_basic_gl13),                             \
774         unit_test_make(test_gl_basic_gl14),                             \
775         unit_test_make(test_gl_basic_gl15),                             \
776         unit_test_make(test_gl_basic_gl20),                             \
777         unit_test_make(test_gl_basic_gl21),                             \
778                                                                         \
779         unit_test_make(test_gl_basic_gl30),                             \
780         unit_test_make(test_gl_basic_gl30_fwdcompat),                   \
781         unit_test_make(test_gl_basic_gl31),                             \
782         unit_test_make(test_gl_basic_gl31_fwdcompat),                   \
783                                                                         \
784         unit_test_make(test_gl_basic_gl32_core),                        \
785         unit_test_make(test_gl_basic_gl32_core_fwdcompat),              \
786         unit_test_make(test_gl_basic_gl32_core_debug),                  \
787         unit_test_make(test_gl_basic_gl32_core_robust),                 \
788         unit_test_make(test_gl_basic_gl33_core),                        \
789         unit_test_make(test_gl_basic_gl40_core),                        \
790         unit_test_make(test_gl_basic_gl41_core),                        \
791         unit_test_make(test_gl_basic_gl42_core),                        \
792         unit_test_make(test_gl_basic_gl43_core),                        \
793         unit_test_make(test_gl_basic_gl44_core),                        \
794         unit_test_make(test_gl_basic_gl45_core),                        \
795         unit_test_make(test_gl_basic_gl46_core),                        \
796                                                                         \
797         unit_test_make(test_gl_basic_gl32_compat),                      \
798         unit_test_make(test_gl_basic_gl32_compat_fwdcompat),            \
799         unit_test_make(test_gl_basic_gl32_compat_debug),                \
800         unit_test_make(test_gl_basic_gl32_compat_robust),               \
801         unit_test_make(test_gl_basic_gl33_compat),                      \
802         unit_test_make(test_gl_basic_gl40_compat),                      \
803         unit_test_make(test_gl_basic_gl41_compat),                      \
804         unit_test_make(test_gl_basic_gl42_compat),                      \
805         unit_test_make(test_gl_basic_gl43_compat),                      \
806         unit_test_make(test_gl_basic_gl44_compat),                      \
807         unit_test_make(test_gl_basic_gl45_compat),                      \
808         unit_test_make(test_gl_basic_gl46_compat),                      \
809                                                                         \
810         unit_test_make(test_gl_basic_gles1_rgb),                        \
811         unit_test_make(test_gl_basic_gles1_rgba),                       \
812         unit_test_make(test_gl_basic_gles1_fwdcompat),                  \
813         unit_test_make(test_gl_basic_gles1_robust),                     \
814         unit_test_make(test_gl_basic_gles1_debug),                      \
815         unit_test_make(test_gl_basic_gles10),                           \
816         unit_test_make(test_gl_basic_gles11),                           \
817                                                                         \
818         unit_test_make(test_gl_basic_gles2_rgb),                        \
819         unit_test_make(test_gl_basic_gles2_rgba),                       \
820         unit_test_make(test_gl_basic_gles2_fwdcompat),                  \
821         unit_test_make(test_gl_basic_gles2_debug),                      \
822         unit_test_make(test_gl_basic_gles2_robust),                     \
823         unit_test_make(test_gl_basic_gles20),                           \
824                                                                         \
825         unit_test_make(test_gl_basic_gles3_rgb),                        \
826         unit_test_make(test_gl_basic_gles3_rgba),                       \
827         unit_test_make(test_gl_basic_gles3_fwdcompat),                  \
828         unit_test_make(test_gl_basic_gles3_debug),                      \
829         unit_test_make(test_gl_basic_gles3_robust),                     \
830         unit_test_make(test_gl_basic_gles30),                           \
831         unit_test_make(test_gl_basic_gles31),                           \
832         unit_test_make(test_gl_basic_gles32),                           \
833                                                                         \
834     };                                                                  \
835                                                                         \
836     return cmocka_run_group_tests_name(#platform, tests, NULL, NULL);   \
837 }
838 
839 //
840 // Most of the following tests will return ERROR_UNSUPPORTED_ON_PLATFORM
841 // on Apple/CGL, where NO_ERROR is expected.
842 // This is safe, as the test is skipped when the said error occurs.
843 //
844 // As BAD_ATTRIBUTE (core validation) takes greater precedence over
845 // UNSUPPORTED_ON_PLATFORM (platform specific one).
846 // Thus we're safe to use the former here, eventhough CGL has support
847 // for neither GLES* nor fwdcompa "CGL and everyone else".
848 //
849 
850 //
851 // Quick notes which combinations we test and why
852 // - w/o version, for each API/profile combination check variations of
853 //   - visual - make sure we can draw fine, duh
854 //   - flags - flags selection machinery is funky
855 // - fwdcompat was introduced with OpenGL 3.0, check it and 3.1
856 // - specific version
857 //   - all known versions
858 //   - no permutation
859 //
test_XX_rgb(gl,OPENGL,NO_ERROR)860 test_XX_rgb(gl, OPENGL, NO_ERROR)
861 test_XX_rgba(gl, OPENGL, NO_ERROR)
862 test_XX_fwdcompat(gl, OPENGL, ERROR_BAD_ATTRIBUTE)
863 test_XX_debug(gl, OPENGL, NO_ERROR)
864 test_XX_robust(gl, OPENGL, NO_ERROR)
865 
866 test_glXX(10, NO_ERROR)
867 test_glXX(11, NO_ERROR)
868 test_glXX(12, NO_ERROR)
869 test_glXX(13, NO_ERROR)
870 test_glXX(14, NO_ERROR)
871 test_glXX(15, NO_ERROR)
872 test_glXX(20, NO_ERROR)
873 test_glXX(21, NO_ERROR)
874 test_glXX(30, NO_ERROR)
875 test_glXX_fwdcompat(30, NO_ERROR)
876 test_glXX(31, NO_ERROR)
877 test_glXX_fwdcompat(31, NO_ERROR)
878 
879 test_glXX_core(32, NO_ERROR)
880 test_glXX_core_fwdcompat(32, NO_ERROR)
881 test_glXX_core_debug(32, NO_ERROR)
882 test_glXX_core_robust(32, NO_ERROR)
883 test_glXX_core(33, NO_ERROR)
884 test_glXX_core(40, NO_ERROR)
885 test_glXX_core(41, NO_ERROR)
886 test_glXX_core(42, NO_ERROR)
887 test_glXX_core(43, NO_ERROR)
888 test_glXX_core(44, NO_ERROR)
889 test_glXX_core(45, NO_ERROR)
890 test_glXX_core(46, NO_ERROR)
891 
892 test_glXX_compat(32, NO_ERROR)
893 test_glXX_compat_fwdcompat(32, NO_ERROR)
894 test_glXX_compat_debug(32, NO_ERROR)
895 test_glXX_compat_robust(32, NO_ERROR)
896 test_glXX_compat(33, NO_ERROR)
897 test_glXX_compat(40, NO_ERROR)
898 test_glXX_compat(41, NO_ERROR)
899 test_glXX_compat(42, NO_ERROR)
900 test_glXX_compat(43, NO_ERROR)
901 test_glXX_compat(44, NO_ERROR)
902 test_glXX_compat(45, NO_ERROR)
903 test_glXX_compat(46, NO_ERROR)
904 
905 test_XX_rgb(gles1, OPENGL_ES1, NO_ERROR)
906 test_XX_rgba(gles1, OPENGL_ES1, NO_ERROR)
907 test_XX_fwdcompat(gles1, OPENGL_ES1, ERROR_BAD_ATTRIBUTE)
908 test_XX_debug(gles1, OPENGL_ES1, NO_ERROR)
909 test_XX_robust(gles1, OPENGL_ES1, NO_ERROR)
910 test_glesXX(1, 10, NO_ERROR)
911 test_glesXX(1, 11, NO_ERROR)
912 
913 test_XX_rgb(gles2, OPENGL_ES2, NO_ERROR)
914 test_XX_rgba(gles2, OPENGL_ES2, NO_ERROR)
915 test_XX_fwdcompat(gles2, OPENGL_ES2, ERROR_BAD_ATTRIBUTE)
916 test_XX_debug(gles2, OPENGL_ES2, NO_ERROR)
917 test_XX_robust(gles2, OPENGL_ES2, NO_ERROR)
918 test_glesXX(2, 20, NO_ERROR)
919 
920 test_XX_rgb(gles3, OPENGL_ES3, NO_ERROR)
921 test_XX_rgba(gles3, OPENGL_ES3, NO_ERROR)
922 test_XX_fwdcompat(gles3, OPENGL_ES3, ERROR_BAD_ATTRIBUTE)
923 test_XX_debug(gles3, OPENGL_ES3, NO_ERROR)
924 test_XX_robust(gles3, OPENGL_ES3, NO_ERROR)
925 test_glesXX(3, 30, NO_ERROR)
926 test_glesXX(3, 31, NO_ERROR)
927 test_glesXX(3, 32, NO_ERROR)
928 
929 
930 #ifdef WAFFLE_HAS_CGL
931 
932 #define unit_test_make(name)                                            \
933     cmocka_unit_test_setup_teardown(name, setup_cgl, gl_basic_fini)
934 
935 CREATE_TESTSUITE(WAFFLE_PLATFORM_CGL, cgl)
936 
937 #undef unit_test_make
938 
939 #endif // WAFFLE_HAS_CGL
940 
941 #ifdef WAFFLE_HAS_GBM
942 
943 #define unit_test_make(name)                                            \
944     cmocka_unit_test_setup_teardown(name, setup_gbm, gl_basic_fini)
945 
946 CREATE_TESTSUITE(WAFFLE_PLATFORM_GBM, gbm)
947 
948 #undef unit_test_make
949 
950 #endif // WAFFLE_HAS_GBM
951 
952 #ifdef WAFFLE_HAS_GLX
953 
954 #define unit_test_make(name)                                            \
955     cmocka_unit_test_setup_teardown(name, setup_glx, gl_basic_fini)
956 
957 CREATE_TESTSUITE(WAFFLE_PLATFORM_GLX, glx)
958 
959 #undef unit_test_make
960 
961 #endif // WAFFLE_HAS_GLX
962 
963 #ifdef WAFFLE_HAS_SURFACELESS_EGL
964 
965 #define unit_test_make(name)                                            \
966     cmocka_unit_test_setup_teardown(name, setup_surfaceless_egl, gl_basic_fini)
967 
968 CREATE_TESTSUITE(WAFFLE_PLATFORM_SURFACELESS_EGL, surfaceless_egl)
969 
970 #undef unit_test_make
971 
972 #endif // WAFFLE_HAS_SURFACELESS_EGL
973 
974 #ifdef WAFFLE_HAS_WAYLAND
975 
976 #define unit_test_make(name)                                            \
977     cmocka_unit_test_setup_teardown(name, setup_wayland, gl_basic_fini)
978 
979 CREATE_TESTSUITE(WAFFLE_PLATFORM_WAYLAND, wayland)
980 
981 #undef unit_test_make
982 
983 #endif // WAFFLE_HAS_WAYLAND
984 
985 #ifdef WAFFLE_HAS_X11_EGL
986 
987 #define unit_test_make(name)                                            \
988     cmocka_unit_test_setup_teardown(name, setup_x11_egl, gl_basic_fini)
989 
990 CREATE_TESTSUITE(WAFFLE_PLATFORM_X11_EGL, x11_egl)
991 
992 #undef unit_test_make
993 
994 #endif // WAFFLE_HAS_X11_EGL
995 
996 #ifdef WAFFLE_HAS_WGL
997 
998 #define unit_test_make(name)                                            \
999     cmocka_unit_test_setup_teardown(name, setup_wgl, gl_basic_fini)
1000 
1001 CREATE_TESTSUITE(WAFFLE_PLATFORM_WGL, wgl)
1002 
1003 #undef unit_test_make
1004 
1005 #endif // WAFFLE_HAS_WGL
1006 
1007 #undef test_glesXX
1008 
1009 #undef test_glXX_compat_robust
1010 #undef test_glXX_compat_debug
1011 #undef test_glXX_compat_fwdcompat
1012 #undef test_glXX_compat
1013 #undef test_glXX_core_robust
1014 #undef test_glXX_core_debug
1015 #undef test_glXX_core_fwdcompat
1016 #undef test_glXX_core
1017 #undef test_glXX_fwdcompat
1018 #undef test_glXX
1019 
1020 #undef test_XX_robust
1021 #undef test_XX_debug
1022 #undef test_XX_fwdcompat
1023 #undef test_XX_rgba
1024 #undef test_XX_rgb
1025 
1026 #ifdef __APPLE__
1027 
1028 static void
1029 removeArg(int index, int *argc, char **argv)
1030 {
1031     --*argc;
1032     for (; index < *argc; ++index)
1033         argv[index] = argv[index + 1];
1034 }
1035 
1036 static void
removeXcodeArgs(int * argc,char ** argv)1037 removeXcodeArgs(int *argc, char **argv)
1038 {
1039     // Xcode sometimes adds additional arguments.
1040     for (int i = 1; i < *argc; )
1041     {
1042         if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0 ||
1043             strcmp(argv[i], "-ApplePersistenceIgnoreState" ) == 0)
1044         {
1045             removeArg(i, argc, argv);
1046             removeArg(i, argc, argv);
1047         } else
1048             ++i;
1049     }
1050 }
1051 
1052 #endif // __APPLE__
1053 
1054 static const char *usage_message =
1055     "Usage:\n"
1056     "    gl_basic_test <Required Parameter> [Options]\n"
1057     "\n"
1058     "Description:\n"
1059     "    Run the basic functionality tests.\n"
1060     "\n"
1061     "Required Parameter:\n"
1062     "    -p, --platform\n"
1063     "        One of: cgl, gbm, glx, wayland, wgl or x11_egl\n"
1064     "\n"
1065     "Options:\n"
1066     "    -h, --help\n"
1067     "        Print gl_basic_test usage information.\n"
1068     ;
1069 
1070 #if defined(__GNUC__)
1071 #define NORETURN __attribute__((noreturn))
1072 #elif defined(_MSC_VER)
1073 #define NORETURN __declspec(noreturn)
1074 #else
1075 #define NORETURN
1076 #endif
1077 
1078 static void NORETURN
write_usage_and_exit(FILE * f,int exit_code)1079 write_usage_and_exit(FILE *f, int exit_code)
1080 {
1081     fprintf(f, "%s", usage_message);
1082     exit(exit_code);
1083 }
1084 
1085 enum {
1086     OPT_PLATFORM = 'p',
1087     OPT_HELP = 'h',
1088 };
1089 
1090 static const struct option get_opts[] = {
1091     { .name = "platform",       .has_arg = required_argument,     .val = OPT_PLATFORM },
1092     { .name = "help",           .has_arg = no_argument,           .val = OPT_HELP },
1093 };
1094 
1095 static void NORETURN
usage_error_printf(const char * fmt,...)1096 usage_error_printf(const char *fmt, ...)
1097 {
1098     fprintf(stderr, "gl_basic_test usage error: ");
1099 
1100     if (fmt) {
1101         va_list ap;
1102         va_start(ap, fmt);
1103         vfprintf(stderr, fmt, ap);
1104         va_end(ap);
1105         fprintf(stderr, " ");
1106     }
1107 
1108     fprintf(stderr, "(see gl_basic_test --help)\n");
1109     exit(EXIT_FAILURE);
1110 }
1111 
1112 struct enum_map {
1113     int i;
1114     const char *s;
1115 };
1116 
1117 static const struct enum_map platform_map[] = {
1118     {WAFFLE_PLATFORM_CGL,       "cgl",          },
1119     {WAFFLE_PLATFORM_GBM,       "gbm"           },
1120     {WAFFLE_PLATFORM_GLX,       "glx"           },
1121     {WAFFLE_PLATFORM_WAYLAND,   "wayland"       },
1122     {WAFFLE_PLATFORM_WGL,       "wgl"           },
1123     {WAFFLE_PLATFORM_X11_EGL,   "x11_egl"       },
1124     {WAFFLE_PLATFORM_SURFACELESS_EGL,   "surfaceless_egl"   },
1125     {WAFFLE_PLATFORM_SURFACELESS_EGL,   "sl"                },
1126     {0,                         0               },
1127 };
1128 
1129 /// @brief Translate string to `enum waffle_enum`.
1130 ///
1131 /// @param self is a list of map items. The last item must be zero-filled.
1132 /// @param result is altered only if @a s if found.
1133 /// @return true if @a s was found in @a map.
1134 static bool
enum_map_translate_str(const struct enum_map * self,const char * s,int * result)1135 enum_map_translate_str(
1136         const struct enum_map *self,
1137         const char *s,
1138         int *result)
1139 {
1140     for (const struct enum_map *i = self; i->i != 0; ++i) {
1141         if (!strncmp(s, i->s, strlen(i->s) + 1)) {
1142             *result = i->i;
1143             return true;
1144         }
1145     }
1146 
1147     return false;
1148 }
1149 
1150 /// @return true on success.
1151 static bool
parse_args(int argc,char * argv[],int * out_platform)1152 parse_args(int argc, char *argv[], int *out_platform)
1153 {
1154     bool ok;
1155     bool loop_get_opt = true;
1156     int platform = 0;
1157 
1158 #ifdef __APPLE__
1159     removeXcodeArgs(&argc, argv);
1160 #endif
1161 
1162     // prevent getopt_long from printing an error message
1163     opterr = 0;
1164 
1165     while (loop_get_opt) {
1166         int opt = getopt_long(argc, argv, "hp:", get_opts, NULL);
1167         switch (opt) {
1168             case -1:
1169                 loop_get_opt = false;
1170                 break;
1171             case '?':
1172                 goto error_unrecognized_arg;
1173             case OPT_PLATFORM:
1174                 ok = enum_map_translate_str(platform_map, optarg, &platform);
1175                 if (!ok) {
1176                     usage_error_printf("'%s' is not a valid platform",
1177                                        optarg);
1178                 }
1179                 break;
1180             case OPT_HELP:
1181                 write_usage_and_exit(stdout, EXIT_SUCCESS);
1182                 break;
1183             default:
1184                 loop_get_opt = false;
1185                 break;
1186         }
1187     }
1188 
1189     if (optind < argc) {
1190         goto error_unrecognized_arg;
1191     }
1192 
1193     if (!platform) {
1194         usage_error_printf("--platform is required");
1195     }
1196 
1197     *out_platform = platform;
1198     return true;
1199 
1200 error_unrecognized_arg:
1201     if (optarg)
1202         usage_error_printf("unrecognized option '%s'", optarg);
1203     else if (optopt)
1204         usage_error_printf("unrecognized option '-%c'", optopt);
1205     else
1206         usage_error_printf("unrecognized option");
1207 }
1208 
1209 int
main(int argc,char * argv[])1210 main(int argc, char *argv[])
1211 {
1212     int platform;
1213     bool ok;
1214 
1215     ok = parse_args(argc, argv, &platform);
1216     if (!ok)
1217         exit(EXIT_FAILURE);
1218 
1219     switch (platform) {
1220 #ifdef WAFFLE_HAS_CGL
1221     case WAFFLE_PLATFORM_CGL:
1222         return testsuite_cgl();
1223 #endif
1224 #ifdef WAFFLE_HAS_GBM
1225     case WAFFLE_PLATFORM_GBM:
1226         return testsuite_gbm();
1227 #endif
1228 #ifdef WAFFLE_HAS_GLX
1229     case WAFFLE_PLATFORM_GLX:
1230         return testsuite_glx();
1231 #endif
1232 #ifdef WAFFLE_HAS_SURFACELESS_EGL
1233     case WAFFLE_PLATFORM_SURFACELESS_EGL:
1234         return testsuite_surfaceless_egl();
1235 #endif
1236 #ifdef WAFFLE_HAS_WAYLAND
1237     case WAFFLE_PLATFORM_WAYLAND:
1238         return testsuite_wayland();
1239 #endif
1240 #ifdef WAFFLE_HAS_WGL
1241     case WAFFLE_PLATFORM_WGL:
1242         return testsuite_wgl();
1243 #endif
1244 #ifdef WAFFLE_HAS_X11_EGL
1245     case WAFFLE_PLATFORM_X11_EGL:
1246         return testsuite_x11_egl();
1247 #endif
1248     default:
1249         abort();
1250         break;
1251     }
1252 
1253     return 0;
1254 }
1255