tests/gl_basic_test: undo overzealous clang-format changes
[mesa-waffle.git] / tests / functional / gl_basic_test.c
blobf19beedb83fcf36f2740245994eda11bb985649b
1 // SPDX-FileCopyrightText: Copyright 2012 Intel Corporation
2 // SPDX-License-Identifier: BSD-2-Clause
4 /// @file
5 /// @brief Test basic OpenGL rendering with all platform/gl_api combinations.
6 ///
7 /// Each test does the following:
8 /// 1. Initialize waffle with a platform and gl_api.
9 /// 2. Create a context and window.
10 /// 3. On the window call waffle_make_current, glClear,
11 /// and waffle_swap_buffers.
12 /// 4. Verify the window contents with glReadPixels.
13 /// 5. Tear down all waffle state.
15 #include <ctype.h>
16 #include <getopt.h>
17 #include <setjmp.h> // for cmocka.h
18 #include <stdarg.h> // for va_start, va_end
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include <sys/types.h>
24 #if !defined(_WIN32)
25 #include <unistd.h>
27 #include <sys/wait.h>
28 #else
29 #include <windows.h>
30 #endif
32 #include "gl_basic_cocoa.h"
33 #include <cmocka.h>
35 #include "waffle.h"
37 enum {
38 // Choosing a smaller window would shorten the execution time of pixel
39 // validation, but Windows 7 enforces a minimum size.
40 WINDOW_WIDTH = 320,
41 WINDOW_HEIGHT = 240,
44 static const float RED_F = 1.00;
45 static const float GREEN_F = 0.00;
46 static const float BLUE_F = 1.00;
47 static const float ALPHA_F = 1.00;
49 static const uint8_t RED_UB = 0xff;
50 static const uint8_t GREEN_UB = 0x00;
51 static const uint8_t BLUE_UB = 0xff;
52 static const uint8_t ALPHA_UB = 0xff;
54 struct test_state_gl_basic {
55 bool initialized;
56 struct waffle_display *dpy;
57 struct waffle_config *config;
58 struct waffle_window *window;
59 struct waffle_context *ctx;
61 uint8_t actual_pixels[4 * WINDOW_WIDTH * WINDOW_HEIGHT];
62 uint8_t expect_pixels[4 * WINDOW_WIDTH * WINDOW_HEIGHT];
65 #define ASSERT_GL(statement) \
66 do { \
67 statement; \
68 assert_false(glGetError()); \
69 } while (0)
71 typedef unsigned int GLenum;
72 typedef unsigned char GLboolean;
73 typedef unsigned int GLbitfield;
74 typedef void GLvoid;
75 typedef signed char GLbyte; /* 1-byte signed */
76 typedef short GLshort; /* 2-byte signed */
77 typedef int GLint; /* 4-byte signed */
78 typedef unsigned char GLubyte; /* 1-byte unsigned */
79 typedef unsigned short GLushort; /* 2-byte unsigned */
80 typedef unsigned int GLuint; /* 4-byte unsigned */
81 typedef int GLsizei; /* 4-byte signed */
82 typedef float GLfloat; /* single precision float */
83 typedef float GLclampf; /* single precision float in [0,1] */
84 typedef double GLdouble; /* double precision float */
85 typedef double GLclampd; /* double precision float in [0,1] */
87 #define GL_NO_ERROR 0x0000
88 #define GL_VERSION 0x1F02
89 #define GL_UNSIGNED_BYTE 0x1401
90 #define GL_UNSIGNED_INT 0x1405
91 #define GL_FLOAT 0x1406
92 #define GL_RGB 0x1907
93 #define GL_RGBA 0x1908
94 #define GL_COLOR_BUFFER_BIT 0x00004000
95 #define GL_CONTEXT_FLAGS 0x821e
96 #define GL_CONTEXT_ROBUST_ACCESS 0x90F3
98 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
99 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
101 #define GL_CONTEXT_PROFILE_MASK 0x9126
102 #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
103 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
105 #ifndef _WIN32
106 #define APIENTRY
107 #else
108 #ifndef APIENTRY
109 #define APIENTRY __stdcall
110 #endif
111 #endif
113 static GLenum(APIENTRY *glGetError)(void);
114 static const GLubyte *(APIENTRY *glGetString)(GLenum name);
115 static void(APIENTRY *glGetIntegerv)(GLenum pname, GLint *params);
116 static void(APIENTRY *glClearColor)(GLclampf red,
117 GLclampf green,
118 GLclampf blue,
119 GLclampf alpha);
120 static void(APIENTRY *glClear)(GLbitfield mask);
121 static void(APIENTRY *glReadPixels)(GLint x,
122 GLint y,
123 GLsizei width,
124 GLsizei height,
125 GLenum format,
126 GLenum type,
127 GLvoid *pixels);
129 static int
130 setup(void **state)
132 struct test_state_gl_basic *ts;
134 ts = calloc(1, sizeof(*ts));
135 if (!ts)
136 return -1;
138 for (int y = 0; y < WINDOW_HEIGHT; ++y) {
139 for (int x = 0; x < WINDOW_WIDTH; ++x) {
140 uint8_t *p = &ts->expect_pixels[4 * (y * WINDOW_WIDTH + x)];
141 p[0] = RED_UB;
142 p[1] = GREEN_UB;
143 p[2] = BLUE_UB;
144 p[3] = ALPHA_UB;
147 // Fill actual_pixels with canaries.
148 memset(&ts->actual_pixels, 0x99, sizeof(ts->actual_pixels));
150 *state = ts;
151 return 0;
154 static int
155 teardown(void **state)
157 free(*state);
158 return 0;
161 // The rules that dictate how to properly query a GL symbol are complex. The
162 // rules depend on the OS, on the winsys API, and even on the particular driver
163 // being used. The rules differ between EGL 1.4 and EGL 1.5; differ between
164 // Linux, Windows, and Mac; and differ between Mesa and Mali.
166 // This function hides that complexity with a naive heuristic: try, then try
167 // again.
168 static void *
169 get_gl_symbol(enum waffle_enum context_api, const char *name)
171 void *sym = NULL;
172 enum waffle_enum dl = 0;
174 // clang-format off
175 switch (context_api) {
176 case WAFFLE_CONTEXT_OPENGL: dl = WAFFLE_DL_OPENGL; break;
177 case WAFFLE_CONTEXT_OPENGL_ES1: dl = WAFFLE_DL_OPENGL_ES1; break;
178 case WAFFLE_CONTEXT_OPENGL_ES2: dl = WAFFLE_DL_OPENGL_ES2; break;
179 case WAFFLE_CONTEXT_OPENGL_ES3: dl = WAFFLE_DL_OPENGL_ES3; break;
180 default: assert_true(0); break;
182 // clang-format on
184 if (waffle_dl_can_open(dl)) {
185 sym = waffle_dl_sym(dl, name);
188 if (!sym) {
189 sym = waffle_get_proc_address(name);
192 return sym;
195 static int32_t waffle_platform;
196 static const char *platform;
198 static void
199 error_waffle(void);
201 static int
202 gl_basic_init(void **state)
204 struct test_state_gl_basic *ts;
205 int ret;
207 ret = setup((void **)&ts);
208 if (ret)
209 return -1;
211 const int32_t init_attrib_list[] = {
212 // clang-format off
213 WAFFLE_PLATFORM, waffle_platform,
215 // clang-format on
218 ts->initialized = waffle_init(init_attrib_list);
219 if (!ts->initialized) {
220 error_waffle();
221 teardown(state);
222 return -1;
225 *state = ts;
226 return 0;
229 static int
230 gl_basic_fini(void **state)
232 struct test_state_gl_basic *ts = *state;
233 bool ret = false;
235 // XXX: return immediately on error or attempt to finish the teardown ?
236 if (ts->dpy) // XXX: keep track if we've had current ctx ?
237 ret = waffle_make_current(ts->dpy, NULL, NULL);
238 if (ts->window)
239 ret = waffle_window_destroy(ts->window);
240 if (ts->ctx)
241 ret = waffle_context_destroy(ts->ctx);
242 if (ts->config)
243 ret = waffle_config_destroy(ts->config);
244 if (ts->dpy)
245 ret = waffle_display_disconnect(ts->dpy);
247 if (ts->initialized)
248 ret = waffle_teardown();
250 teardown(state);
251 return ret ? 0 : -1;
254 enum {
255 TEST_CTX_FWDCOMPAT = 1 << 0,
256 TEST_CTX_DEBUG = 1 << 1,
257 TEST_CTX_ROBUST = 1 << 2,
258 TEST_CTX_LOSE_CONTEXT = 1 << 3,
261 #define gl_basic_draw(state, ...) \
263 gl_basic_draw__( \
264 state, (struct gl_basic_draw_args__){ .api = 0, \
265 .version = WAFFLE_DONT_CARE, \
266 .profile = WAFFLE_DONT_CARE, \
267 .expect_error = WAFFLE_NO_ERROR, \
268 .context_flags = 0, \
269 .alpha = false, \
270 __VA_ARGS__ })
272 struct gl_basic_draw_args__ {
273 int32_t api;
274 int32_t version;
275 int32_t profile;
276 int32_t expect_error;
277 uint32_t context_flags;
278 bool alpha;
281 #define assert_int_equal_print(_a, _b) \
282 if (_a != _b) { \
283 fprintf(stderr, #_a " (%d) != " #_b "(%d)\n", _a, _b); \
284 assert_true(0 && "Integer comparison failed"); \
287 #define assert_int_ge(_a, _b) \
288 if (_a < _b) { \
289 fprintf(stderr, #_a " (%d) < " #_b "(%d)\n", _a, _b); \
290 assert_true(0 && "Integer comparison failed"); \
293 #define assert_in_range_print(_a, _min, _max) \
294 if (_a < _min || _a > _max) { \
295 fprintf(stderr, \
296 #_a " (%d) outside range " #_min "(%d) - " #_max "(%d)\n", _a, \
297 _min, _max); \
298 assert_true(0 && "Integer comparison failed"); \
301 #define assert_string_len_equal(_actual, _expected, _len) \
302 if (strncmp(_actual, _expected, _len) != 0) { \
303 fprintf(stderr, "Expected (" #_expected "): \"%.*s\"\n", (int)_len, \
304 _expected); \
305 fprintf(stderr, "Received (" #_actual "): \"%.*s\"\n", (int)_len, \
306 _actual); \
307 assert_true(0 && "String comparison failed"); \
310 static void
311 error_waffle(void)
313 const struct waffle_error_info *info = waffle_error_get_info();
314 const char *code = waffle_error_to_string(info->code);
316 if (info->message_length > 0)
317 fprintf(stderr, "Waffle error: 0x%x %s: %s\n", info->code, code,
318 info->message);
319 else
320 fprintf(stderr, "Waffle error: 0x%x %s\n", info->code, code);
323 #define assert_true_with_wfl_error(_arg) \
324 if (!(_arg)) { \
325 error_waffle(); \
326 assert_true(0); \
329 static void
330 gl_basic_draw__(void **state, struct gl_basic_draw_args__ args)
332 struct test_state_gl_basic *ts = *state;
333 int32_t waffle_context_api = args.api;
334 int32_t context_version = args.version;
335 int32_t context_profile = args.profile;
336 int32_t expect_error = args.expect_error;
337 bool context_forward_compatible = args.context_flags & TEST_CTX_FWDCOMPAT;
338 bool context_debug = args.context_flags & TEST_CTX_DEBUG;
339 bool context_robust = args.context_flags & TEST_CTX_ROBUST;
340 bool lose_context_on_reset = args.context_flags & TEST_CTX_LOSE_CONTEXT;
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 // clang-format off
349 WAFFLE_WINDOW_WIDTH, WINDOW_WIDTH,
350 WAFFLE_WINDOW_HEIGHT, WINDOW_HEIGHT,
352 // clang-format on
355 i = 0;
356 config_attrib_list[i++] = WAFFLE_CONTEXT_API;
357 config_attrib_list[i++] = waffle_context_api;
358 if (context_version != WAFFLE_DONT_CARE) {
359 config_attrib_list[i++] = WAFFLE_CONTEXT_MAJOR_VERSION;
360 config_attrib_list[i++] = context_version / 10;
361 config_attrib_list[i++] = WAFFLE_CONTEXT_MINOR_VERSION;
362 config_attrib_list[i++] = context_version % 10;
364 if (context_profile != WAFFLE_DONT_CARE) {
365 config_attrib_list[i++] = WAFFLE_CONTEXT_PROFILE;
366 config_attrib_list[i++] = context_profile;
368 if (context_forward_compatible) {
369 config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE;
370 config_attrib_list[i++] = true;
372 if (context_debug) {
373 config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG;
374 config_attrib_list[i++] = true;
376 if (context_robust) {
377 config_attrib_list[i++] = WAFFLE_CONTEXT_ROBUST_ACCESS;
378 config_attrib_list[i++] = true;
380 if (lose_context_on_reset) {
381 config_attrib_list[i++] = WAFFLE_CONTEXT_LOSE_CONTEXT_ON_RESET;
382 config_attrib_list[i++] = true;
384 config_attrib_list[i++] = WAFFLE_RED_SIZE;
385 config_attrib_list[i++] = 8;
386 config_attrib_list[i++] = WAFFLE_GREEN_SIZE;
387 config_attrib_list[i++] = 8;
388 config_attrib_list[i++] = WAFFLE_BLUE_SIZE;
389 config_attrib_list[i++] = 8;
390 config_attrib_list[i++] = WAFFLE_ALPHA_SIZE;
391 config_attrib_list[i++] = alpha;
392 config_attrib_list[i++] = 0;
394 // Create objects.
395 ts->dpy = waffle_display_connect(NULL);
396 assert_true_with_wfl_error(ts->dpy);
398 ts->config = waffle_config_choose(ts->dpy, config_attrib_list);
399 if (expect_error) {
400 assert_true(ts->config == NULL);
401 assert_true((int32_t)waffle_error_get_code() == expect_error);
402 return;
403 } else if (ts->config == NULL) {
404 switch (waffle_error_get_code()) {
405 case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM:
406 // fall-through
407 case WAFFLE_ERROR_UNKNOWN:
408 // Assume that the native platform rejected the requested
409 // config flavor.
410 skip();
411 // XXX: skip() is not annotated as noreturn, leading to compiler
412 // warning about implicit fallthrough
413 break;
414 default:
415 assert_true_with_wfl_error(ts->config);
419 ts->window = waffle_window_create2(ts->config, window_attrib_list);
420 assert_true_with_wfl_error(ts->window);
422 ret = waffle_window_show(ts->window);
423 assert_true_with_wfl_error(ret);
425 ts->ctx = waffle_context_create(ts->config, NULL);
426 if (ts->ctx == NULL) {
427 switch (waffle_error_get_code()) {
428 case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM:
429 // fall-through
430 case WAFFLE_ERROR_UNKNOWN:
431 // Assume that the native platform rejected the requested
432 // context flavor.
433 skip();
434 // XXX: skip() is not annotated as noreturn, leading to compiler
435 // warning about implicit fallthrough
436 break;
437 default:
438 assert_true_with_wfl_error(ts->ctx);
442 // Get OpenGL functions.
443 // clang-format off
444 assert_true(glClear = get_gl_symbol(waffle_context_api, "glClear"));
445 assert_true(glClearColor = get_gl_symbol(waffle_context_api, "glClearColor"));
446 assert_true(glGetError = get_gl_symbol(waffle_context_api, "glGetError"));
447 assert_true(glGetIntegerv = get_gl_symbol(waffle_context_api, "glGetIntegerv"));
448 assert_true(glReadPixels = get_gl_symbol(waffle_context_api, "glReadPixels"));
449 assert_true(glGetString = get_gl_symbol(waffle_context_api, "glGetString"));
450 // clang-format on
452 ret = waffle_make_current(ts->dpy, ts->window, ts->ctx);
453 assert_true_with_wfl_error(ret);
455 assert_true(waffle_get_current_display() == ts->dpy);
456 assert_true(waffle_get_current_window() == ts->window);
457 assert_true(waffle_get_current_context() == ts->ctx);
459 const char *version_str, *expected_version_str;
460 int major, minor, count;
462 ASSERT_GL(version_str = (const char *)glGetString(GL_VERSION));
463 assert_true(version_str != NULL);
465 // clang-format off
466 switch (waffle_context_api) {
467 case WAFFLE_CONTEXT_OPENGL: expected_version_str = ""; break;
468 case WAFFLE_CONTEXT_OPENGL_ES1: expected_version_str = "OpenGL ES-CM "; break;
469 case WAFFLE_CONTEXT_OPENGL_ES2:
470 case WAFFLE_CONTEXT_OPENGL_ES3: expected_version_str = "OpenGL ES "; break;
471 // Explicitly initialize, to appease GCC
472 default: expected_version_str = ""; assert_true(0); break;
474 // clang-format on
476 const size_t version_str_len = strlen(expected_version_str);
477 assert_string_len_equal(version_str, expected_version_str, version_str_len);
478 version_str += version_str_len;
480 count = sscanf(version_str, "%d.%d", &major, &minor);
481 assert_int_equal_print(count, 2);
482 assert_int_ge(major, 0);
483 assert_in_range_print(minor, 0, 10);
485 if (context_version != WAFFLE_DONT_CARE) {
486 int expected_major = context_version / 10;
487 int expected_minor = context_version % 10;
489 assert_int_ge(major, expected_major);
490 if (major == expected_major)
491 assert_int_ge(minor, expected_minor);
494 const char *profile_suffix = "";
496 if (waffle_context_api == WAFFLE_CONTEXT_OPENGL) {
497 switch (context_profile) {
498 case WAFFLE_CONTEXT_CORE_PROFILE:
499 profile_suffix = " (Core Profile)";
500 #ifdef __APPLE__
501 fprintf(stderr,
502 "MacOS Core contexts, omit the \"%s\" suffix in "
503 "glGetString(GL_VERSION)."
504 "Applying workaround.\n",
505 profile_suffix);
506 profile_suffix = "";
507 #endif
508 break;
509 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
510 // HACK: seems like Mesa 19.3.3 at least will report
511 if (context_forward_compatible)
512 profile_suffix = " (Core Profile)";
513 else
514 profile_suffix = " (Compatibility Profile)";
515 break;
516 case WAFFLE_DONT_CARE:
517 break;
518 default:
519 assert_true(0);
520 break;
524 char profile_str[30]; // 30 should be enough ;-)
525 sprintf(profile_str, "%d.%d%s", major, minor, profile_suffix);
527 const size_t profile_str_len = strlen(profile_str);
528 assert_string_len_equal(version_str, profile_str, profile_str_len);
530 int version_10x = 10 * major + minor;
532 // Another profile check
533 if (waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 32) {
534 GLint profile_mask = 0;
535 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask);
537 switch (context_profile) {
538 case WAFFLE_CONTEXT_CORE_PROFILE:
539 assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
540 break;
541 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
542 // HACK: seems like Mesa 19.3.3 at least will report
543 if (context_forward_compatible)
544 assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
545 else
546 assert_true(profile_mask &
547 GL_CONTEXT_COMPATIBILITY_PROFILE_BIT);
548 break;
549 case WAFFLE_DONT_CARE:
550 break;
551 default:
552 assert_true(0);
553 break;
557 if ((waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 30) ||
558 (waffle_context_api != WAFFLE_CONTEXT_OPENGL && version_10x >= 32)) {
559 GLint context_flags = 0;
560 if (context_forward_compatible || context_debug) {
561 glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
564 if (context_forward_compatible) {
565 assert_true(context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
568 if (context_debug) {
569 assert_true(context_flags & GL_CONTEXT_FLAG_DEBUG_BIT);
573 // GL_ROBUST_ACCESS comes with the following extensions
574 // GL_ARB_robustness
575 // GL_EXT_robustness
576 // GL_KHR_robustness
578 // To keep it simple, assume the correct extension is there if
579 // glGetError is happy ;-)
580 if (context_robust) {
581 GLint robust_flag = 0;
582 glGetIntegerv(GL_CONTEXT_ROBUST_ACCESS, &robust_flag);
584 if (glGetError() == GL_NO_ERROR)
585 assert_true(robust_flag);
588 // Draw.
589 ASSERT_GL(glClearColor(RED_F, GREEN_F, BLUE_F, ALPHA_F));
590 ASSERT_GL(glClear(GL_COLOR_BUFFER_BIT));
591 ASSERT_GL(glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGBA,
592 GL_UNSIGNED_BYTE, ts->actual_pixels));
593 ret = waffle_window_swap_buffers(ts->window);
594 assert_true_with_wfl_error(ret);
596 assert_memory_equal(&ts->actual_pixels, &ts->expect_pixels,
597 sizeof(ts->expect_pixels));
601 // List of tests common to all platforms.
604 // clang-format off
606 #define test_rgb(waffle_api) \
607 static void waffle_api##_rgb(void **state) \
609 gl_basic_draw(state, \
610 .api=WAFFLE_CONTEXT_##waffle_api); \
613 #define test_rgba(waffle_api) \
614 static void waffle_api##_rgba(void **state) \
616 gl_basic_draw(state, \
617 .api=WAFFLE_CONTEXT_##waffle_api, \
618 .alpha=true); \
621 #define test_context_flags(waffle_api, waffle_flags) \
622 static void waffle_api##_##waffle_flags(void **state) \
624 int32_t expect_error = TEST_##waffle_flags & TEST_CTX_FWDCOMPAT ? \
625 WAFFLE_ERROR_BAD_ATTRIBUTE : WAFFLE_NO_ERROR; \
626 gl_basic_draw(state, \
627 .api=WAFFLE_CONTEXT_##waffle_api, \
628 .context_flags=TEST_##waffle_flags, \
629 .expect_error=expect_error); \
632 #define test_version(waffle_api, waffle_version) \
633 static void waffle_api##_##waffle_version(void **state) \
635 gl_basic_draw(state, \
636 .api=WAFFLE_CONTEXT_##waffle_api, \
637 .version=waffle_version); \
640 #define test_version_fwdcompat(waffle_api, waffle_version) \
641 static void waffle_api##_fwdcompat_##waffle_version(void **state) \
643 gl_basic_draw(state, \
644 .api=WAFFLE_CONTEXT_##waffle_api, \
645 .version=waffle_version, \
646 .context_flags=TEST_CTX_FWDCOMPAT); \
649 #define test_profile_version(waffle_profile, waffle_version) \
650 static void waffle_profile##_##waffle_version(void **state) \
652 gl_basic_draw(state, \
653 .api=WAFFLE_CONTEXT_OPENGL, \
654 .version=waffle_version, \
655 .profile=WAFFLE_CONTEXT_##waffle_profile##_PROFILE); \
658 #define test_profile_context_flags(waffle_profile, waffle_flags) \
659 static void waffle_profile##_##waffle_flags(void **state) \
661 gl_basic_draw(state, \
662 .api=WAFFLE_CONTEXT_OPENGL, \
663 .version=32, \
664 .profile=WAFFLE_CONTEXT_##waffle_profile##_PROFILE, \
665 .context_flags=TEST_##waffle_flags); \
670 // Most of the following tests will return ERROR_UNSUPPORTED_ON_PLATFORM
671 // on Apple/CGL, where NO_ERROR is expected.
672 // This is safe, as the test is skipped when the said error occurs.
674 // As BAD_ATTRIBUTE (core validation) takes greater precedence over
675 // UNSUPPORTED_ON_PLATFORM (platform specific one).
676 // Thus we're safe to use the former here, eventhough CGL has support
677 // for neither GLES* nor fwdcompa "CGL and everyone else".
681 // Quick notes which combinations we test and why
682 // - w/o version, for each API/profile combination check variations of
683 // - visual - make sure we can draw fine, duh
684 // - flags - flags selection machinery is funky
685 // - fwdcompat was introduced with OpenGL 3.0, check it and 3.1
686 // - specific version
687 // - all known versions
688 // - no permutation
692 // OPENGL, no profile
694 test_rgb(OPENGL)
695 test_rgba(OPENGL)
697 test_context_flags(OPENGL, CTX_FWDCOMPAT)
698 test_context_flags(OPENGL, CTX_DEBUG)
699 test_context_flags(OPENGL, CTX_ROBUST)
700 test_context_flags(OPENGL, CTX_LOSE_CONTEXT)
702 test_version_fwdcompat(OPENGL, 30)
703 test_version_fwdcompat(OPENGL, 31)
705 test_version(OPENGL, 10)
706 test_version(OPENGL, 11)
707 test_version(OPENGL, 12)
708 test_version(OPENGL, 13)
709 test_version(OPENGL, 14)
710 test_version(OPENGL, 15)
711 test_version(OPENGL, 20)
712 test_version(OPENGL, 21)
713 test_version(OPENGL, 30)
714 test_version(OPENGL, 31)
716 // OPENGL, CORE profile
718 test_profile_context_flags(CORE, CTX_FWDCOMPAT)
719 test_profile_context_flags(CORE, CTX_DEBUG)
720 test_profile_context_flags(CORE, CTX_ROBUST)
721 test_profile_context_flags(CORE, CTX_LOSE_CONTEXT)
723 test_profile_version(CORE, 32)
724 test_profile_version(CORE, 33)
725 test_profile_version(CORE, 40)
726 test_profile_version(CORE, 41)
727 test_profile_version(CORE, 42)
728 test_profile_version(CORE, 43)
729 test_profile_version(CORE, 44)
730 test_profile_version(CORE, 45)
731 test_profile_version(CORE, 46)
733 // OPENGL, COMPATIBILITY profile
735 test_profile_context_flags(COMPATIBILITY, CTX_FWDCOMPAT)
736 test_profile_context_flags(COMPATIBILITY, CTX_DEBUG)
737 test_profile_context_flags(COMPATIBILITY, CTX_ROBUST)
738 test_profile_context_flags(COMPATIBILITY, CTX_LOSE_CONTEXT)
740 test_profile_version(COMPATIBILITY, 32)
741 test_profile_version(COMPATIBILITY, 33)
742 test_profile_version(COMPATIBILITY, 40)
743 test_profile_version(COMPATIBILITY, 41)
744 test_profile_version(COMPATIBILITY, 42)
745 test_profile_version(COMPATIBILITY, 43)
746 test_profile_version(COMPATIBILITY, 44)
747 test_profile_version(COMPATIBILITY, 45)
748 test_profile_version(COMPATIBILITY, 46)
750 // OPENGL_ES1
752 test_rgb(OPENGL_ES1)
753 test_rgba(OPENGL_ES1)
755 test_context_flags(OPENGL_ES1, CTX_FWDCOMPAT)
756 test_context_flags(OPENGL_ES1, CTX_DEBUG)
757 test_context_flags(OPENGL_ES1, CTX_ROBUST)
758 test_context_flags(OPENGL_ES1, CTX_LOSE_CONTEXT)
760 test_version(OPENGL_ES1, 10)
761 test_version(OPENGL_ES1, 11)
763 // OPENGL_ES2
765 test_rgb(OPENGL_ES2)
766 test_rgba(OPENGL_ES2)
768 test_context_flags(OPENGL_ES2, CTX_FWDCOMPAT)
769 test_context_flags(OPENGL_ES2, CTX_DEBUG)
770 test_context_flags(OPENGL_ES2, CTX_ROBUST)
771 test_context_flags(OPENGL_ES2, CTX_LOSE_CONTEXT)
773 test_version(OPENGL_ES2, 20)
775 // OPENGL_ES3
777 test_rgb(OPENGL_ES3)
778 test_rgba(OPENGL_ES3)
780 test_context_flags(OPENGL_ES3, CTX_FWDCOMPAT)
781 test_context_flags(OPENGL_ES3, CTX_DEBUG)
782 test_context_flags(OPENGL_ES3, CTX_ROBUST)
783 test_context_flags(OPENGL_ES3, CTX_LOSE_CONTEXT)
785 test_version(OPENGL_ES3, 30)
786 test_version(OPENGL_ES3, 31)
787 test_version(OPENGL_ES3, 32)
790 #ifdef __APPLE__
792 static void
793 removeArg(int index, int *argc, char **argv)
794 // clang-format on
796 --*argc;
797 for (; index < *argc; ++index)
798 argv[index] = argv[index + 1];
801 static void
802 removeXcodeArgs(int *argc, char **argv)
804 // Xcode sometimes adds additional arguments.
805 for (int i = 1; i < *argc;) {
806 if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0 ||
807 strcmp(argv[i], "-ApplePersistenceIgnoreState") == 0) {
808 removeArg(i, argc, argv);
809 removeArg(i, argc, argv);
810 } else
811 ++i;
815 #endif // __APPLE__
817 static const char *usage_message =
818 "Usage:\n"
819 " gl_basic_test <Required Parameter> [Options]\n"
820 "\n"
821 "Description:\n"
822 " Run the basic functionality tests.\n"
823 "\n"
824 "Required Parameter:\n"
825 " -p, --platform\n"
826 " One of: cgl, gbm, glx, wayland, wgl or x11_egl\n"
827 "\n"
828 "Options:\n"
829 " -h, --help\n"
830 " Print gl_basic_test usage information.\n";
832 #if defined(__GNUC__)
833 #define NORETURN __attribute__((noreturn))
834 #elif defined(_MSC_VER)
835 #define NORETURN __declspec(noreturn)
836 #else
837 #define NORETURN
838 #endif
840 #if defined(__clang__)
841 #define PRINTFLIKE(f, a) __attribute__((format(printf, f, a)))
842 #elif defined(__GNUC__)
843 #define PRINTFLIKE(f, a) __attribute__((format(gnu_printf, f, a)))
844 #else
845 #define PRINTFLIKE(f, a)
846 #endif
848 static void NORETURN
849 write_usage_and_exit(FILE *f, int exit_code)
851 fprintf(f, "%s", usage_message);
852 exit(exit_code);
855 enum {
856 OPT_PLATFORM = 'p',
857 OPT_HELP = 'h',
860 static const struct option get_opts[] = {
861 { .name = "platform", .has_arg = required_argument, .val = OPT_PLATFORM },
862 { .name = "help", .has_arg = no_argument, .val = OPT_HELP },
865 static void NORETURN PRINTFLIKE(1, 2)
866 usage_error_printf(const char *fmt, ...)
868 fprintf(stderr, "gl_basic_test usage error: ");
870 if (fmt) {
871 va_list ap;
872 va_start(ap, fmt);
873 vfprintf(stderr, fmt, ap);
874 va_end(ap);
875 fprintf(stderr, " ");
878 fprintf(stderr, "(see gl_basic_test --help)\n");
879 exit(EXIT_FAILURE);
882 struct enum_map {
883 int i;
884 const char *s;
887 static const struct enum_map platform_map[] = {
888 { WAFFLE_PLATFORM_CGL, "cgl" },
889 { WAFFLE_PLATFORM_GBM, "gbm" },
890 { WAFFLE_PLATFORM_GLX, "glx" },
891 { WAFFLE_PLATFORM_WAYLAND, "wayland" },
892 { WAFFLE_PLATFORM_WGL, "wgl" },
893 { WAFFLE_PLATFORM_X11_EGL, "x11_egl" },
894 { WAFFLE_PLATFORM_SURFACELESS_EGL, "surfaceless_egl" },
895 { WAFFLE_PLATFORM_SURFACELESS_EGL, "sl" },
896 { 0, 0 },
899 /// @brief Translate string to `enum waffle_enum`.
901 /// @param self is a list of map items. The last item must be zero-filled.
902 /// @param result is altered only if @a s if found.
903 /// @return true if @a s was found in @a map.
904 static bool
905 enum_map_translate_str(const struct enum_map *self, const char *s, int *result)
907 for (const struct enum_map *i = self; i->i != 0; ++i) {
908 if (!strncmp(s, i->s, strlen(i->s) + 1)) {
909 *result = i->i;
910 return true;
914 return false;
917 /// @return true on success.
918 static void
919 parse_args(int argc, char *argv[])
921 bool loop_get_opt = true;
923 #ifdef __APPLE__
924 removeXcodeArgs(&argc, argv);
925 #endif
927 // prevent getopt_long from printing an error message
928 opterr = 0;
930 while (loop_get_opt) {
931 int opt = getopt_long(argc, argv, "hp:", get_opts, NULL);
932 switch (opt) {
933 case -1:
934 loop_get_opt = false;
935 break;
936 case '?':
937 goto error_unrecognized_arg;
938 case OPT_PLATFORM:
939 if (!enum_map_translate_str(platform_map, optarg,
940 &waffle_platform)) {
941 usage_error_printf("'%s' is not a valid platform", optarg);
943 platform = optarg;
944 break;
945 case OPT_HELP:
946 write_usage_and_exit(stdout, EXIT_SUCCESS);
947 break;
948 default:
949 loop_get_opt = false;
950 break;
954 if (optind < argc) {
955 goto error_unrecognized_arg;
958 if (!waffle_platform) {
959 usage_error_printf("--platform is required");
962 return;
964 error_unrecognized_arg:
965 if (optarg)
966 usage_error_printf("unrecognized option '%s'", optarg);
967 else if (optopt)
968 usage_error_printf("unrecognized option '-%c'", optopt);
969 else
970 usage_error_printf("unrecognized option");
974 main(int argc, char *argv[])
976 parse_args(argc, argv);
978 #define unit_test_make(name) \
979 cmocka_unit_test_setup_teardown(name, gl_basic_init, gl_basic_fini)
981 const struct CMUnitTest tests[] = {
983 // OPENGL, no profile
985 unit_test_make(OPENGL_rgb),
986 unit_test_make(OPENGL_rgba),
988 unit_test_make(OPENGL_CTX_FWDCOMPAT),
989 unit_test_make(OPENGL_CTX_DEBUG),
990 unit_test_make(OPENGL_CTX_ROBUST),
991 unit_test_make(OPENGL_CTX_LOSE_CONTEXT),
993 unit_test_make(OPENGL_fwdcompat_30),
994 unit_test_make(OPENGL_fwdcompat_31),
996 unit_test_make(OPENGL_10),
997 unit_test_make(OPENGL_11),
998 unit_test_make(OPENGL_12),
999 unit_test_make(OPENGL_13),
1000 unit_test_make(OPENGL_14),
1001 unit_test_make(OPENGL_15),
1002 unit_test_make(OPENGL_20),
1003 unit_test_make(OPENGL_21),
1004 unit_test_make(OPENGL_30),
1005 unit_test_make(OPENGL_31),
1007 // OPENGL, CORE profile
1009 unit_test_make(CORE_CTX_FWDCOMPAT),
1010 unit_test_make(CORE_CTX_DEBUG),
1011 unit_test_make(CORE_CTX_ROBUST),
1012 unit_test_make(CORE_CTX_LOSE_CONTEXT),
1014 unit_test_make(CORE_32),
1015 unit_test_make(CORE_33),
1016 unit_test_make(CORE_40),
1017 unit_test_make(CORE_41),
1018 unit_test_make(CORE_42),
1019 unit_test_make(CORE_43),
1020 unit_test_make(CORE_44),
1021 unit_test_make(CORE_45),
1022 unit_test_make(CORE_46),
1024 // OPENGL, COMPATIBILITY profile
1026 unit_test_make(COMPATIBILITY_CTX_FWDCOMPAT),
1027 unit_test_make(COMPATIBILITY_CTX_DEBUG),
1028 unit_test_make(COMPATIBILITY_CTX_ROBUST),
1029 unit_test_make(COMPATIBILITY_CTX_LOSE_CONTEXT),
1031 unit_test_make(COMPATIBILITY_32),
1032 unit_test_make(COMPATIBILITY_33),
1033 unit_test_make(COMPATIBILITY_40),
1034 unit_test_make(COMPATIBILITY_41),
1035 unit_test_make(COMPATIBILITY_42),
1036 unit_test_make(COMPATIBILITY_43),
1037 unit_test_make(COMPATIBILITY_44),
1038 unit_test_make(COMPATIBILITY_45),
1039 unit_test_make(COMPATIBILITY_46),
1041 // OPENGL_ES1
1043 unit_test_make(OPENGL_ES1_rgb),
1044 unit_test_make(OPENGL_ES1_rgba),
1046 unit_test_make(OPENGL_ES1_CTX_FWDCOMPAT),
1047 unit_test_make(OPENGL_ES1_CTX_DEBUG),
1048 unit_test_make(OPENGL_ES1_CTX_ROBUST),
1049 unit_test_make(OPENGL_ES1_CTX_LOSE_CONTEXT),
1051 unit_test_make(OPENGL_ES1_10),
1052 unit_test_make(OPENGL_ES1_11),
1054 // OPENGL_ES2
1056 unit_test_make(OPENGL_ES2_rgb),
1057 unit_test_make(OPENGL_ES2_rgba),
1059 unit_test_make(OPENGL_ES2_CTX_FWDCOMPAT),
1060 unit_test_make(OPENGL_ES2_CTX_DEBUG),
1061 unit_test_make(OPENGL_ES2_CTX_ROBUST),
1062 unit_test_make(OPENGL_ES2_CTX_LOSE_CONTEXT),
1064 unit_test_make(OPENGL_ES2_20),
1066 // OPENGL_ES3
1068 unit_test_make(OPENGL_ES3_rgb),
1069 unit_test_make(OPENGL_ES3_rgba),
1071 unit_test_make(OPENGL_ES3_CTX_FWDCOMPAT),
1072 unit_test_make(OPENGL_ES3_CTX_DEBUG),
1073 unit_test_make(OPENGL_ES3_CTX_ROBUST),
1074 unit_test_make(OPENGL_ES3_CTX_LOSE_CONTEXT),
1076 unit_test_make(OPENGL_ES3_30),
1077 unit_test_make(OPENGL_ES3_31),
1078 unit_test_make(OPENGL_ES3_32),
1081 return cmocka_run_group_tests_name(platform, tests, NULL, NULL);