tests/gl_basic_test: add compat/fwdcompat workaround
[mesa-waffle.git] / tests / functional / gl_basic_test.c
blob7724e244766ab891aec46e0b56d9a5c7a71ea290
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.
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 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.
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
52 #include <cmocka.h>
53 #include "waffle.h"
55 #include "gl_basic_cocoa.h"
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,
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;
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;
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;
81 uint8_t actual_pixels[4 * WINDOW_WIDTH * WINDOW_HEIGHT];
82 uint8_t expect_pixels[4 * WINDOW_WIDTH * WINDOW_HEIGHT];
85 #define ASSERT_GL(statement) \
86 do { \
87 statement; \
88 assert_false(glGetError()); \
89 } while (0)
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] */
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
118 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
119 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
121 #define GL_CONTEXT_PROFILE_MASK 0x9126
122 #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
123 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
125 #ifndef _WIN32
126 #define APIENTRY
127 #else
128 #ifndef APIENTRY
129 #define APIENTRY __stdcall
130 #endif
131 #endif
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 );
146 static int
147 setup(void **state)
149 struct test_state_gl_basic *ts;
151 ts = calloc(1, sizeof(*ts));
152 if (!ts)
153 return -1;
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;
164 // Fill actual_pixels with canaries.
165 memset(&ts->actual_pixels, 0x99, sizeof(ts->actual_pixels));
167 *state = ts;
168 return 0;
171 static int
172 teardown(void **state)
174 free(*state);
175 return 0;
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.
183 // This function hides that complexity with a naive heuristic: try, then try
184 // again.
185 static void *
186 get_gl_symbol(enum waffle_enum context_api, const char *name)
188 void *sym = NULL;
189 enum waffle_enum dl = 0;
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;
199 if (waffle_dl_can_open(dl)) {
200 sym = waffle_dl_sym(dl, name);
203 if (!sym) {
204 sym = waffle_get_proc_address(name);
207 return sym;
210 static int
211 gl_basic_init(void **state, int32_t waffle_platform)
213 struct test_state_gl_basic *ts;
214 int ret;
216 ret = setup((void **)&ts);
217 if (ret)
218 return -1;
220 const int32_t init_attrib_list[] = {
221 WAFFLE_PLATFORM, waffle_platform,
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;
232 *state = ts;
233 return 0;
236 static int
237 gl_basic_fini(void **state)
239 struct test_state_gl_basic *ts = *state;
240 bool ret = false;
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);
254 if (ts->initialized)
255 ret = waffle_teardown();
257 teardown(state);
258 return ret ? 0 : -1;
261 #define gl_basic_draw(state, ...) \
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__ \
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;
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"); \
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"); \
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"); \
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"); \
312 static void
313 error_waffle(void)
315 const struct waffle_error_info *info = waffle_error_get_info();
316 const char *code = waffle_error_to_string(info->code);
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);
324 #define assert_true_with_wfl_error(_arg) \
325 if (!(_arg)) { \
326 error_waffle(); \
327 assert_true(0); \
330 static void
331 gl_basic_draw__(void **state, struct gl_basic_draw_args__ args)
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;
344 int32_t config_attrib_list[64];
345 int i;
347 const intptr_t window_attrib_list[] = {
348 WAFFLE_WINDOW_WIDTH, WINDOW_WIDTH,
349 WAFFLE_WINDOW_HEIGHT, WINDOW_HEIGHT,
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;
362 if (context_profile != WAFFLE_DONT_CARE) {
363 config_attrib_list[i++] = WAFFLE_CONTEXT_PROFILE;
364 config_attrib_list[i++] = context_profile;
366 if (context_forward_compatible) {
367 config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE;
368 config_attrib_list[i++] = true;
370 if (context_debug) {
371 config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG;
372 config_attrib_list[i++] = true;
374 if (context_robust) {
375 config_attrib_list[i++] = WAFFLE_CONTEXT_ROBUST_ACCESS;
376 config_attrib_list[i++] = true;
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;
388 // Create objects.
389 ts->dpy = waffle_display_connect(NULL);
390 assert_true_with_wfl_error(ts->dpy);
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);
410 ts->window = waffle_window_create2(ts->config, window_attrib_list);
411 assert_true_with_wfl_error(ts->window);
413 ret = waffle_window_show(ts->window);
414 assert_true_with_wfl_error(ret);
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);
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"));
438 ret = waffle_make_current(ts->dpy, ts->window, ts->ctx);
439 assert_true_with_wfl_error(ret);
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);
445 const char *version_str, *expected_version_str;
446 int major, minor, count;
448 ASSERT_GL(version_str = (const char *) glGetString(GL_VERSION));
449 assert_true(version_str != NULL);
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;
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;
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);
476 if (context_version != WAFFLE_DONT_CARE) {
477 int expected_major = context_version / 10;
478 int expected_minor = context_version % 10;
480 assert_int_ge(major, expected_major);
481 if (major == expected_major)
482 assert_int_ge(minor, expected_minor);
485 const char *profile_suffix = "";
487 if (waffle_context_api == WAFFLE_CONTEXT_OPENGL) {
488 switch (context_profile) {
489 case WAFFLE_CONTEXT_CORE_PROFILE:
490 profile_suffix = " (Core Profile)";
491 break;
492 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
493 // HACK: seems like Mesa 19.3.3 at least will report
494 if (context_forward_compatible)
495 profile_suffix = " (Core Profile)";
496 else
497 profile_suffix = " (Compatibility Profile)";
498 break;
499 case WAFFLE_DONT_CARE:
500 break;
501 default:
502 assert_true(0);
503 break;
507 char profile_str[30]; // 30 should be enough ;-)
508 sprintf(profile_str, "%d.%d%s", major, minor, profile_suffix);
510 const size_t profile_str_len = strlen(profile_str);
511 assert_string_len_equal(version_str, profile_str, profile_str_len);
513 int version_10x = 10 * major + minor;
515 // Another profile check
516 if (waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 32) {
517 GLint profile_mask = 0;
518 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask);
520 switch (context_profile) {
521 case WAFFLE_CONTEXT_CORE_PROFILE:
522 assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
523 break;
524 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
525 // HACK: seems like Mesa 19.3.3 at least will report
526 if (context_forward_compatible)
527 assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
528 else
529 assert_true(profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT);
530 break;
531 case WAFFLE_DONT_CARE:
532 break;
533 default:
534 assert_true(0);
535 break;
539 if ((waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 30) ||
540 (waffle_context_api != WAFFLE_CONTEXT_OPENGL && version_10x >= 32)) {
541 GLint context_flags = 0;
542 if (context_forward_compatible || context_debug) {
543 glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
546 if (context_forward_compatible) {
547 assert_true(context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
550 if (context_debug) {
551 assert_true(context_flags & GL_CONTEXT_FLAG_DEBUG_BIT);
555 // GL_ROBUST_ACCESS comes with the following extensions
556 // GL_ARB_robustness
557 // GL_EXT_robustness
558 // GL_KHR_robustness
560 // To keep it simple, assume the correct extension is there if
561 // glGetError is happy ;-)
562 if (context_robust) {
563 GLint robust_flag = 0;
564 glGetIntegerv(GL_CONTEXT_ROBUST_ACCESS, &robust_flag);
566 if (glGetError() == GL_NO_ERROR)
567 assert_true(robust_flag);
570 // Draw.
571 ASSERT_GL(glClearColor(RED_F, GREEN_F, BLUE_F, ALPHA_F));
572 ASSERT_GL(glClear(GL_COLOR_BUFFER_BIT));
573 ASSERT_GL(glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT,
574 GL_RGBA, GL_UNSIGNED_BYTE,
575 ts->actual_pixels));
576 ret = waffle_window_swap_buffers(ts->window);
577 assert_true_with_wfl_error(ret);
579 assert_memory_equal(&ts->actual_pixels, &ts->expect_pixels,
580 sizeof(ts->expect_pixels));
584 // List of tests common to all platforms.
587 #define test_XX_rgb(context_api, waffle_api, error) \
588 static void test_gl_basic_##context_api##_rgb(void **state) \
590 gl_basic_draw(state, \
591 .api=WAFFLE_CONTEXT_##waffle_api, \
592 .expect_error=WAFFLE_##error); \
595 #define test_XX_rgba(context_api, waffle_api, error) \
596 static void test_gl_basic_##context_api##_rgba(void **state) \
598 gl_basic_draw(state, \
599 .api=WAFFLE_CONTEXT_##waffle_api, \
600 .alpha=true, \
601 .expect_error=WAFFLE_##error); \
604 #define test_XX_fwdcompat(context_api, waffle_api, error) \
605 static void test_gl_basic_##context_api##_fwdcompat(void **state) \
607 gl_basic_draw(state, \
608 .api=WAFFLE_CONTEXT_##waffle_api, \
609 .forward_compatible=true, \
610 .expect_error=WAFFLE_##error); \
613 #define test_XX_debug(context_api, waffle_api, error) \
614 static void test_gl_basic_##context_api##_debug(void **state) \
616 gl_basic_draw(state, \
617 .api=WAFFLE_CONTEXT_##waffle_api, \
618 .debug=true, \
619 .expect_error=WAFFLE_##error); \
622 #define test_XX_robust(context_api, waffle_api, error) \
623 static void test_gl_basic_##context_api##_robust(void **state) \
625 gl_basic_draw(state, \
626 .api=WAFFLE_CONTEXT_##waffle_api, \
627 .robust=true, \
628 .expect_error=WAFFLE_##error); \
631 #define test_glXX(waffle_version, error) \
632 static void test_gl_basic_gl##waffle_version(void **state) \
634 gl_basic_draw(state, \
635 .api=WAFFLE_CONTEXT_OPENGL, \
636 .version=waffle_version, \
637 .expect_error=WAFFLE_##error); \
640 #define test_glXX_fwdcompat(waffle_version, error) \
641 static void test_gl_basic_gl##waffle_version##_fwdcompat(void **state) \
643 gl_basic_draw(state, \
644 .api=WAFFLE_CONTEXT_OPENGL, \
645 .version=waffle_version, \
646 .forward_compatible=true, \
647 .expect_error=WAFFLE_##error); \
650 #define test_glXX_core(waffle_version, error) \
651 static void test_gl_basic_gl##waffle_version##_core(void **state) \
653 gl_basic_draw(state, \
654 .api=WAFFLE_CONTEXT_OPENGL, \
655 .version=waffle_version, \
656 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
657 .expect_error=WAFFLE_##error); \
660 #define test_glXX_core_fwdcompat(waffle_version, error) \
661 static void test_gl_basic_gl##waffle_version##_core_fwdcompat(void **state) \
663 gl_basic_draw(state, \
664 .api=WAFFLE_CONTEXT_OPENGL, \
665 .version=waffle_version, \
666 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
667 .forward_compatible=true, \
668 .expect_error=WAFFLE_##error); \
671 #define test_glXX_core_debug(waffle_version, error) \
672 static void test_gl_basic_gl##waffle_version##_core_debug(void **state) \
674 gl_basic_draw(state, \
675 .api=WAFFLE_CONTEXT_OPENGL, \
676 .version=waffle_version, \
677 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
678 .debug=true, \
679 .expect_error=WAFFLE_##error); \
682 #define test_glXX_core_robust(waffle_version, error) \
683 static void test_gl_basic_gl##waffle_version##_core_robust(void **state) \
685 gl_basic_draw(state, \
686 .api=WAFFLE_CONTEXT_OPENGL, \
687 .version=waffle_version, \
688 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
689 .robust=true, \
690 .expect_error=WAFFLE_##error); \
693 #define test_glXX_compat(waffle_version, error) \
694 static void test_gl_basic_gl##waffle_version##_compat(void **state) \
696 gl_basic_draw(state, \
697 .api=WAFFLE_CONTEXT_OPENGL, \
698 .version=waffle_version, \
699 .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, \
700 .expect_error=WAFFLE_##error); \
703 #define test_glXX_compat_debug(waffle_version, error) \
704 static void test_gl_basic_gl##waffle_version##_compat_debug(void **state) \
706 gl_basic_draw(state, \
707 .api=WAFFLE_CONTEXT_OPENGL, \
708 .version=waffle_version, \
709 .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, \
710 .debug=true, \
711 .expect_error=WAFFLE_##error); \
714 #define test_glXX_compat_robust(waffle_version, error) \
715 static void test_gl_basic_gl##waffle_version##_compat_robust(void **state) \
717 gl_basic_draw(state, \
718 .api=WAFFLE_CONTEXT_OPENGL, \
719 .version=waffle_version, \
720 .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, \
721 .robust=true, \
722 .expect_error=WAFFLE_##error); \
725 #define test_glesXX(api_version, waffle_version, error) \
726 static void test_gl_basic_gles##waffle_version(void **state) \
728 gl_basic_draw(state, \
729 .api=WAFFLE_CONTEXT_OPENGL_ES##api_version, \
730 .version=waffle_version, \
731 .expect_error=WAFFLE_##error); \
735 #define CREATE_TESTSUITE(waffle_platform, platform) \
737 static int \
738 setup_##platform(void **state) \
740 return gl_basic_init(state, waffle_platform); \
743 static int \
744 testsuite_##platform(void) \
746 const struct CMUnitTest tests[] = { \
748 unit_test_make(test_gl_basic_gl_rgb), \
749 unit_test_make(test_gl_basic_gl_rgba), \
750 unit_test_make(test_gl_basic_gl_fwdcompat), \
751 unit_test_make(test_gl_basic_gl_debug), \
752 unit_test_make(test_gl_basic_gl_robust), \
754 unit_test_make(test_gl_basic_gl10), \
755 unit_test_make(test_gl_basic_gl11), \
756 unit_test_make(test_gl_basic_gl12), \
757 unit_test_make(test_gl_basic_gl13), \
758 unit_test_make(test_gl_basic_gl14), \
759 unit_test_make(test_gl_basic_gl15), \
760 unit_test_make(test_gl_basic_gl20), \
761 unit_test_make(test_gl_basic_gl21), \
762 unit_test_make(test_gl_basic_gl21_fwdcompat), \
764 unit_test_make(test_gl_basic_gl30), \
765 unit_test_make(test_gl_basic_gl30_fwdcompat), \
766 unit_test_make(test_gl_basic_gl31), \
767 unit_test_make(test_gl_basic_gl31_fwdcompat), \
769 unit_test_make(test_gl_basic_gl32_core), \
770 unit_test_make(test_gl_basic_gl32_core_fwdcompat), \
771 unit_test_make(test_gl_basic_gl32_core_debug), \
772 unit_test_make(test_gl_basic_gl32_core_robust), \
773 unit_test_make(test_gl_basic_gl33_core), \
774 unit_test_make(test_gl_basic_gl40_core), \
775 unit_test_make(test_gl_basic_gl41_core), \
776 unit_test_make(test_gl_basic_gl42_core), \
777 unit_test_make(test_gl_basic_gl43_core), \
779 unit_test_make(test_gl_basic_gl32_compat), \
780 unit_test_make(test_gl_basic_gl32_compat_debug), \
781 unit_test_make(test_gl_basic_gl32_compat_robust), \
782 unit_test_make(test_gl_basic_gl33_compat), \
783 unit_test_make(test_gl_basic_gl40_compat), \
784 unit_test_make(test_gl_basic_gl41_compat), \
785 unit_test_make(test_gl_basic_gl42_compat), \
786 unit_test_make(test_gl_basic_gl43_compat), \
788 unit_test_make(test_gl_basic_gles1_rgb), \
789 unit_test_make(test_gl_basic_gles1_rgba), \
790 unit_test_make(test_gl_basic_gles1_fwdcompat), \
791 unit_test_make(test_gl_basic_gles1_robust), \
792 unit_test_make(test_gl_basic_gles1_debug), \
793 unit_test_make(test_gl_basic_gles10), \
794 unit_test_make(test_gl_basic_gles11), \
796 unit_test_make(test_gl_basic_gles2_rgb), \
797 unit_test_make(test_gl_basic_gles2_rgba), \
798 unit_test_make(test_gl_basic_gles2_fwdcompat), \
799 unit_test_make(test_gl_basic_gles2_debug), \
800 unit_test_make(test_gl_basic_gles2_robust), \
801 unit_test_make(test_gl_basic_gles20), \
803 unit_test_make(test_gl_basic_gles3_rgb), \
804 unit_test_make(test_gl_basic_gles3_rgba), \
805 unit_test_make(test_gl_basic_gles3_fwdcompat), \
806 unit_test_make(test_gl_basic_gles3_debug), \
807 unit_test_make(test_gl_basic_gles3_robust), \
808 unit_test_make(test_gl_basic_gles30), \
810 }; \
812 return cmocka_run_group_tests_name(#platform, tests, NULL, NULL); \
816 // Most of the following tests will return ERROR_UNSUPPORTED_ON_PLATFORM
817 // on Apple/CGL, where NO_ERROR is expected.
818 // This is safe, as the test is skipped when the said error occurs.
820 // As BAD_ATTRIBUTE (core validation) takes greater precedence over
821 // UNSUPPORTED_ON_PLATFORM (platform specific one).
822 // Thus we're safe to use the former here, eventhough CGL has support
823 // for neither GLES* nor fwdcompa "CGL and everyone else".
825 test_XX_rgb(gl, OPENGL, NO_ERROR)
826 test_XX_rgba(gl, OPENGL, NO_ERROR)
827 test_XX_fwdcompat(gl, OPENGL, ERROR_BAD_ATTRIBUTE)
828 test_XX_debug(gl, OPENGL, NO_ERROR)
829 test_XX_robust(gl, OPENGL, NO_ERROR)
831 test_glXX(10, NO_ERROR)
832 test_glXX(11, NO_ERROR)
833 test_glXX(12, NO_ERROR)
834 test_glXX(13, NO_ERROR)
835 test_glXX(14, NO_ERROR)
836 test_glXX(15, NO_ERROR)
837 test_glXX(20, NO_ERROR)
838 test_glXX(21, NO_ERROR)
839 test_glXX_fwdcompat(21, ERROR_BAD_ATTRIBUTE)
840 test_glXX(30, NO_ERROR)
841 test_glXX_fwdcompat(30, NO_ERROR)
842 test_glXX(31, NO_ERROR)
843 test_glXX_fwdcompat(31, NO_ERROR)
845 test_glXX_core(32, NO_ERROR)
846 test_glXX_core_fwdcompat(32, NO_ERROR)
847 test_glXX_core_debug(32, NO_ERROR)
848 test_glXX_core_robust(32, NO_ERROR)
849 test_glXX_core(33, NO_ERROR)
850 test_glXX_core(40, NO_ERROR)
851 test_glXX_core(41, NO_ERROR)
852 test_glXX_core(42, NO_ERROR)
853 test_glXX_core(43, NO_ERROR)
855 test_glXX_compat(32, NO_ERROR)
856 test_glXX_compat_debug(32, NO_ERROR)
857 test_glXX_compat_robust(32, NO_ERROR)
858 test_glXX_compat(33, NO_ERROR)
859 test_glXX_compat(40, NO_ERROR)
860 test_glXX_compat(41, NO_ERROR)
861 test_glXX_compat(42, NO_ERROR)
862 test_glXX_compat(43, NO_ERROR)
864 test_XX_rgb(gles1, OPENGL_ES1, NO_ERROR)
865 test_XX_rgba(gles1, OPENGL_ES1, NO_ERROR)
866 test_XX_fwdcompat(gles1, OPENGL_ES1, ERROR_BAD_ATTRIBUTE)
867 test_XX_debug(gles1, OPENGL_ES1, NO_ERROR)
868 test_XX_robust(gles1, OPENGL_ES1, NO_ERROR)
869 test_glesXX(1, 10, NO_ERROR)
870 test_glesXX(1, 11, NO_ERROR)
872 test_XX_rgb(gles2, OPENGL_ES2, NO_ERROR)
873 test_XX_rgba(gles2, OPENGL_ES2, NO_ERROR)
874 test_XX_fwdcompat(gles2, OPENGL_ES2, ERROR_BAD_ATTRIBUTE)
875 test_XX_debug(gles2, OPENGL_ES2, NO_ERROR)
876 test_XX_robust(gles2, OPENGL_ES2, NO_ERROR)
877 test_glesXX(2, 20, NO_ERROR)
879 test_XX_rgb(gles3, OPENGL_ES3, NO_ERROR)
880 test_XX_rgba(gles3, OPENGL_ES3, NO_ERROR)
881 test_XX_fwdcompat(gles3, OPENGL_ES3, ERROR_BAD_ATTRIBUTE)
882 test_XX_debug(gles3, OPENGL_ES3, NO_ERROR)
883 test_XX_robust(gles3, OPENGL_ES3, NO_ERROR)
884 test_glesXX(3, 30, NO_ERROR)
887 #ifdef WAFFLE_HAS_CGL
889 #define unit_test_make(name) \
890 cmocka_unit_test_setup_teardown(name, setup_cgl, gl_basic_fini)
892 CREATE_TESTSUITE(WAFFLE_PLATFORM_CGL, cgl)
894 #undef unit_test_make
896 #endif // WAFFLE_HAS_CGL
898 #ifdef WAFFLE_HAS_GBM
900 #define unit_test_make(name) \
901 cmocka_unit_test_setup_teardown(name, setup_gbm, gl_basic_fini)
903 CREATE_TESTSUITE(WAFFLE_PLATFORM_GBM, gbm)
905 #undef unit_test_make
907 #endif // WAFFLE_HAS_GBM
909 #ifdef WAFFLE_HAS_GLX
911 #define unit_test_make(name) \
912 cmocka_unit_test_setup_teardown(name, setup_glx, gl_basic_fini)
914 CREATE_TESTSUITE(WAFFLE_PLATFORM_GLX, glx)
916 #undef unit_test_make
918 #endif // WAFFLE_HAS_GLX
920 #ifdef WAFFLE_HAS_SURFACELESS_EGL
922 #define unit_test_make(name) \
923 cmocka_unit_test_setup_teardown(name, setup_surfaceless_egl, gl_basic_fini)
925 CREATE_TESTSUITE(WAFFLE_PLATFORM_SURFACELESS_EGL, surfaceless_egl)
927 #undef unit_test_make
929 #endif // WAFFLE_HAS_SURFACELESS_EGL
931 #ifdef WAFFLE_HAS_WAYLAND
933 #define unit_test_make(name) \
934 cmocka_unit_test_setup_teardown(name, setup_wayland, gl_basic_fini)
936 CREATE_TESTSUITE(WAFFLE_PLATFORM_WAYLAND, wayland)
938 #undef unit_test_make
940 #endif // WAFFLE_HAS_WAYLAND
942 #ifdef WAFFLE_HAS_X11_EGL
944 #define unit_test_make(name) \
945 cmocka_unit_test_setup_teardown(name, setup_x11_egl, gl_basic_fini)
947 CREATE_TESTSUITE(WAFFLE_PLATFORM_X11_EGL, x11_egl)
949 #undef unit_test_make
951 #endif // WAFFLE_HAS_X11_EGL
953 #ifdef WAFFLE_HAS_WGL
955 #define unit_test_make(name) \
956 cmocka_unit_test_setup_teardown(name, setup_wgl, gl_basic_fini)
958 CREATE_TESTSUITE(WAFFLE_PLATFORM_WGL, wgl)
960 #undef unit_test_make
962 #endif // WAFFLE_HAS_WGL
964 #undef test_glesXX
966 #undef test_glXX_compat_robust
967 #undef test_glXX_compat_debug
968 #undef test_glXX_compat
969 #undef test_glXX_core_robust
970 #undef test_glXX_core_debug
971 #undef test_glXX_core_fwdcompat
972 #undef test_glXX_core
973 #undef test_glXX_fwdcompat
974 #undef test_glXX
976 #undef test_XX_robust
977 #undef test_XX_debug
978 #undef test_XX_fwdcompat
979 #undef test_XX_rgba
980 #undef test_XX_rgb
982 #ifdef __APPLE__
984 static void
985 removeArg(int index, int *argc, char **argv)
987 --*argc;
988 for (; index < *argc; ++index)
989 argv[index] = argv[index + 1];
992 static void
993 removeXcodeArgs(int *argc, char **argv)
995 // Xcode sometimes adds additional arguments.
996 for (int i = 1; i < *argc; )
998 if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0 ||
999 strcmp(argv[i], "-ApplePersistenceIgnoreState" ) == 0)
1001 removeArg(i, argc, argv);
1002 removeArg(i, argc, argv);
1003 } else
1004 ++i;
1008 #endif // __APPLE__
1010 static const char *usage_message =
1011 "Usage:\n"
1012 " gl_basic_test <Required Parameter> [Options]\n"
1013 "\n"
1014 "Description:\n"
1015 " Run the basic functionality tests.\n"
1016 "\n"
1017 "Required Parameter:\n"
1018 " -p, --platform\n"
1019 " One of: cgl, gbm, glx, wayland, wgl or x11_egl\n"
1020 "\n"
1021 "Options:\n"
1022 " -h, --help\n"
1023 " Print gl_basic_test usage information.\n"
1026 #if defined(__GNUC__)
1027 #define NORETURN __attribute__((noreturn))
1028 #elif defined(_MSC_VER)
1029 #define NORETURN __declspec(noreturn)
1030 #else
1031 #define NORETURN
1032 #endif
1034 static void NORETURN
1035 write_usage_and_exit(FILE *f, int exit_code)
1037 fprintf(f, "%s", usage_message);
1038 exit(exit_code);
1041 enum {
1042 OPT_PLATFORM = 'p',
1043 OPT_HELP = 'h',
1046 static const struct option get_opts[] = {
1047 { .name = "platform", .has_arg = required_argument, .val = OPT_PLATFORM },
1048 { .name = "help", .has_arg = no_argument, .val = OPT_HELP },
1051 static void NORETURN
1052 usage_error_printf(const char *fmt, ...)
1054 fprintf(stderr, "gl_basic_test usage error: ");
1056 if (fmt) {
1057 va_list ap;
1058 va_start(ap, fmt);
1059 vfprintf(stderr, fmt, ap);
1060 va_end(ap);
1061 fprintf(stderr, " ");
1064 fprintf(stderr, "(see gl_basic_test --help)\n");
1065 exit(EXIT_FAILURE);
1068 struct enum_map {
1069 int i;
1070 const char *s;
1073 static const struct enum_map platform_map[] = {
1074 {WAFFLE_PLATFORM_CGL, "cgl", },
1075 {WAFFLE_PLATFORM_GBM, "gbm" },
1076 {WAFFLE_PLATFORM_GLX, "glx" },
1077 {WAFFLE_PLATFORM_WAYLAND, "wayland" },
1078 {WAFFLE_PLATFORM_WGL, "wgl" },
1079 {WAFFLE_PLATFORM_X11_EGL, "x11_egl" },
1080 {WAFFLE_PLATFORM_SURFACELESS_EGL, "surfaceless_egl" },
1081 {WAFFLE_PLATFORM_SURFACELESS_EGL, "sl" },
1082 {0, 0 },
1085 /// @brief Translate string to `enum waffle_enum`.
1087 /// @param self is a list of map items. The last item must be zero-filled.
1088 /// @param result is altered only if @a s if found.
1089 /// @return true if @a s was found in @a map.
1090 static bool
1091 enum_map_translate_str(
1092 const struct enum_map *self,
1093 const char *s,
1094 int *result)
1096 for (const struct enum_map *i = self; i->i != 0; ++i) {
1097 if (!strncmp(s, i->s, strlen(i->s) + 1)) {
1098 *result = i->i;
1099 return true;
1103 return false;
1106 /// @return true on success.
1107 static bool
1108 parse_args(int argc, char *argv[], int *out_platform)
1110 bool ok;
1111 bool loop_get_opt = true;
1112 int platform = 0;
1114 #ifdef __APPLE__
1115 removeXcodeArgs(&argc, argv);
1116 #endif
1118 // prevent getopt_long from printing an error message
1119 opterr = 0;
1121 while (loop_get_opt) {
1122 int opt = getopt_long(argc, argv, "hp:", get_opts, NULL);
1123 switch (opt) {
1124 case -1:
1125 loop_get_opt = false;
1126 break;
1127 case '?':
1128 goto error_unrecognized_arg;
1129 case OPT_PLATFORM:
1130 ok = enum_map_translate_str(platform_map, optarg, &platform);
1131 if (!ok) {
1132 usage_error_printf("'%s' is not a valid platform",
1133 optarg);
1135 break;
1136 case OPT_HELP:
1137 write_usage_and_exit(stdout, EXIT_SUCCESS);
1138 break;
1139 default:
1140 loop_get_opt = false;
1141 break;
1145 if (optind < argc) {
1146 goto error_unrecognized_arg;
1149 if (!platform) {
1150 usage_error_printf("--platform is required");
1153 *out_platform = platform;
1154 return true;
1156 error_unrecognized_arg:
1157 if (optarg)
1158 usage_error_printf("unrecognized option '%s'", optarg);
1159 else if (optopt)
1160 usage_error_printf("unrecognized option '-%c'", optopt);
1161 else
1162 usage_error_printf("unrecognized option");
1166 main(int argc, char *argv[])
1168 int platform;
1169 bool ok;
1171 ok = parse_args(argc, argv, &platform);
1172 if (!ok)
1173 exit(EXIT_FAILURE);
1175 switch (platform) {
1176 #ifdef WAFFLE_HAS_CGL
1177 case WAFFLE_PLATFORM_CGL:
1178 return testsuite_cgl();
1179 #endif
1180 #ifdef WAFFLE_HAS_GBM
1181 case WAFFLE_PLATFORM_GBM:
1182 return testsuite_gbm();
1183 #endif
1184 #ifdef WAFFLE_HAS_GLX
1185 case WAFFLE_PLATFORM_GLX:
1186 return testsuite_glx();
1187 #endif
1188 #ifdef WAFFLE_HAS_SURFACELESS_EGL
1189 case WAFFLE_PLATFORM_SURFACELESS_EGL:
1190 return testsuite_surfaceless_egl();
1191 #endif
1192 #ifdef WAFFLE_HAS_WAYLAND
1193 case WAFFLE_PLATFORM_WAYLAND:
1194 return testsuite_wayland();
1195 #endif
1196 #ifdef WAFFLE_HAS_WGL
1197 case WAFFLE_PLATFORM_WGL:
1198 return testsuite_wgl();
1199 #endif
1200 #ifdef WAFFLE_HAS_X11_EGL
1201 case WAFFLE_PLATFORM_X11_EGL:
1202 return testsuite_x11_egl();
1203 #endif
1204 default:
1205 abort();
1206 break;
1209 return 0;