tree: drop clang-format off for attributes
[mesa-waffle.git] / tests / functional / gl_basic_test.c
blob046188d266e62fec812d095bb301199a30da34f0
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 switch (context_api) {
175 case WAFFLE_CONTEXT_OPENGL:
176 dl = WAFFLE_DL_OPENGL;
177 break;
178 case WAFFLE_CONTEXT_OPENGL_ES1:
179 dl = WAFFLE_DL_OPENGL_ES1;
180 break;
181 case WAFFLE_CONTEXT_OPENGL_ES2:
182 dl = WAFFLE_DL_OPENGL_ES2;
183 break;
184 case WAFFLE_CONTEXT_OPENGL_ES3:
185 dl = WAFFLE_DL_OPENGL_ES3;
186 break;
187 default:
188 assert_true(0);
189 break;
192 if (waffle_dl_can_open(dl)) {
193 sym = waffle_dl_sym(dl, name);
196 if (!sym) {
197 sym = waffle_get_proc_address(name);
200 return sym;
203 static int32_t waffle_platform;
204 static const char *platform;
206 static void
207 error_waffle(void);
209 static int
210 gl_basic_init(void **state)
212 struct test_state_gl_basic *ts;
213 int ret;
215 ret = setup((void **)&ts);
216 if (ret)
217 return -1;
219 const int32_t init_attrib_list[] = {
220 WAFFLE_PLATFORM,
221 waffle_platform,
225 ts->initialized = waffle_init(init_attrib_list);
226 if (!ts->initialized) {
227 error_waffle();
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 enum {
262 TEST_CTX_FWDCOMPAT = 1 << 0,
263 TEST_CTX_DEBUG = 1 << 1,
264 TEST_CTX_ROBUST = 1 << 2,
265 TEST_CTX_LOSE_CONTEXT = 1 << 3,
268 #define gl_basic_draw(state, ...) \
270 gl_basic_draw__( \
271 state, (struct gl_basic_draw_args__){ .api = 0, \
272 .version = WAFFLE_DONT_CARE, \
273 .profile = WAFFLE_DONT_CARE, \
274 .expect_error = WAFFLE_NO_ERROR, \
275 .context_flags = 0, \
276 .alpha = false, \
277 __VA_ARGS__ })
279 struct gl_basic_draw_args__ {
280 int32_t api;
281 int32_t version;
282 int32_t profile;
283 int32_t expect_error;
284 uint32_t context_flags;
285 bool alpha;
288 #define assert_int_equal_print(_a, _b) \
289 if (_a != _b) { \
290 fprintf(stderr, #_a " (%d) != " #_b "(%d)\n", _a, _b); \
291 assert_true(0 && "Integer comparison failed"); \
294 #define assert_int_ge(_a, _b) \
295 if (_a < _b) { \
296 fprintf(stderr, #_a " (%d) < " #_b "(%d)\n", _a, _b); \
297 assert_true(0 && "Integer comparison failed"); \
300 #define assert_in_range_print(_a, _min, _max) \
301 if (_a < _min || _a > _max) { \
302 fprintf(stderr, \
303 #_a " (%d) outside range " #_min "(%d) - " #_max "(%d)\n", _a, \
304 _min, _max); \
305 assert_true(0 && "Integer comparison failed"); \
308 #define assert_string_len_equal(_actual, _expected, _len) \
309 if (strncmp(_actual, _expected, _len) != 0) { \
310 fprintf(stderr, "Expected (" #_expected "): \"%.*s\"\n", (int)_len, \
311 _expected); \
312 fprintf(stderr, "Received (" #_actual "): \"%.*s\"\n", (int)_len, \
313 _actual); \
314 assert_true(0 && "String comparison failed"); \
317 static void
318 error_waffle(void)
320 const struct waffle_error_info *info = waffle_error_get_info();
321 const char *code = waffle_error_to_string(info->code);
323 if (info->message_length > 0)
324 fprintf(stderr, "Waffle error: 0x%x %s: %s\n", info->code, code,
325 info->message);
326 else
327 fprintf(stderr, "Waffle error: 0x%x %s\n", info->code, code);
330 #define assert_true_with_wfl_error(_arg) \
331 if (!(_arg)) { \
332 error_waffle(); \
333 assert_true(0); \
336 static void
337 gl_basic_draw__(void **state, struct gl_basic_draw_args__ args)
339 struct test_state_gl_basic *ts = *state;
340 int32_t waffle_context_api = args.api;
341 int32_t context_version = args.version;
342 int32_t context_profile = args.profile;
343 int32_t expect_error = args.expect_error;
344 bool context_forward_compatible = args.context_flags & TEST_CTX_FWDCOMPAT;
345 bool context_debug = args.context_flags & TEST_CTX_DEBUG;
346 bool context_robust = args.context_flags & TEST_CTX_ROBUST;
347 bool lose_context_on_reset = args.context_flags & TEST_CTX_LOSE_CONTEXT;
348 bool alpha = args.alpha;
349 bool ret;
351 int32_t config_attrib_list[64];
352 int i;
354 const intptr_t window_attrib_list[] = {
355 WAFFLE_WINDOW_WIDTH,
356 WINDOW_WIDTH,
357 WAFFLE_WINDOW_HEIGHT,
358 WINDOW_HEIGHT,
362 i = 0;
363 config_attrib_list[i++] = WAFFLE_CONTEXT_API;
364 config_attrib_list[i++] = waffle_context_api;
365 if (context_version != WAFFLE_DONT_CARE) {
366 config_attrib_list[i++] = WAFFLE_CONTEXT_MAJOR_VERSION;
367 config_attrib_list[i++] = context_version / 10;
368 config_attrib_list[i++] = WAFFLE_CONTEXT_MINOR_VERSION;
369 config_attrib_list[i++] = context_version % 10;
371 if (context_profile != WAFFLE_DONT_CARE) {
372 config_attrib_list[i++] = WAFFLE_CONTEXT_PROFILE;
373 config_attrib_list[i++] = context_profile;
375 if (context_forward_compatible) {
376 config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE;
377 config_attrib_list[i++] = true;
379 if (context_debug) {
380 config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG;
381 config_attrib_list[i++] = true;
383 if (context_robust) {
384 config_attrib_list[i++] = WAFFLE_CONTEXT_ROBUST_ACCESS;
385 config_attrib_list[i++] = true;
387 if (lose_context_on_reset) {
388 config_attrib_list[i++] = WAFFLE_CONTEXT_LOSE_CONTEXT_ON_RESET;
389 config_attrib_list[i++] = true;
391 config_attrib_list[i++] = WAFFLE_RED_SIZE;
392 config_attrib_list[i++] = 8;
393 config_attrib_list[i++] = WAFFLE_GREEN_SIZE;
394 config_attrib_list[i++] = 8;
395 config_attrib_list[i++] = WAFFLE_BLUE_SIZE;
396 config_attrib_list[i++] = 8;
397 config_attrib_list[i++] = WAFFLE_ALPHA_SIZE;
398 config_attrib_list[i++] = alpha;
399 config_attrib_list[i++] = 0;
401 // Create objects.
402 ts->dpy = waffle_display_connect(NULL);
403 assert_true_with_wfl_error(ts->dpy);
405 ts->config = waffle_config_choose(ts->dpy, config_attrib_list);
406 if (expect_error) {
407 assert_true(ts->config == NULL);
408 assert_true((int32_t)waffle_error_get_code() == expect_error);
409 return;
410 } else if (ts->config == NULL) {
411 switch (waffle_error_get_code()) {
412 case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM:
413 // fall-through
414 case WAFFLE_ERROR_UNKNOWN:
415 // Assume that the native platform rejected the requested
416 // config flavor.
417 skip();
418 // XXX: skip() is not annotated as noreturn, leading to compiler
419 // warning about implicit fallthrough
420 break;
421 default:
422 assert_true_with_wfl_error(ts->config);
426 ts->window = waffle_window_create2(ts->config, window_attrib_list);
427 assert_true_with_wfl_error(ts->window);
429 ret = waffle_window_show(ts->window);
430 assert_true_with_wfl_error(ret);
432 ts->ctx = waffle_context_create(ts->config, NULL);
433 if (ts->ctx == NULL) {
434 switch (waffle_error_get_code()) {
435 case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM:
436 // fall-through
437 case WAFFLE_ERROR_UNKNOWN:
438 // Assume that the native platform rejected the requested
439 // context flavor.
440 skip();
441 // XXX: skip() is not annotated as noreturn, leading to compiler
442 // warning about implicit fallthrough
443 break;
444 default:
445 assert_true_with_wfl_error(ts->ctx);
449 // Get OpenGL functions.
450 // clang-format off
451 assert_true(glClear = get_gl_symbol(waffle_context_api, "glClear"));
452 assert_true(glClearColor = get_gl_symbol(waffle_context_api, "glClearColor"));
453 assert_true(glGetError = get_gl_symbol(waffle_context_api, "glGetError"));
454 assert_true(glGetIntegerv = get_gl_symbol(waffle_context_api, "glGetIntegerv"));
455 assert_true(glReadPixels = get_gl_symbol(waffle_context_api, "glReadPixels"));
456 assert_true(glGetString = get_gl_symbol(waffle_context_api, "glGetString"));
457 // clang-format on
459 ret = waffle_make_current(ts->dpy, ts->window, ts->ctx);
460 assert_true_with_wfl_error(ret);
462 assert_true(waffle_get_current_display() == ts->dpy);
463 assert_true(waffle_get_current_window() == ts->window);
464 assert_true(waffle_get_current_context() == ts->ctx);
466 const char *version_str, *expected_version_str;
467 int major, minor, count;
469 ASSERT_GL(version_str = (const char *)glGetString(GL_VERSION));
470 assert_true(version_str != NULL);
472 switch (waffle_context_api) {
473 case WAFFLE_CONTEXT_OPENGL:
474 expected_version_str = "";
475 break;
476 case WAFFLE_CONTEXT_OPENGL_ES1:
477 expected_version_str = "OpenGL ES-CM ";
478 break;
479 case WAFFLE_CONTEXT_OPENGL_ES2:
480 case WAFFLE_CONTEXT_OPENGL_ES3:
481 expected_version_str = "OpenGL ES ";
482 break;
483 default:
484 // Explicitly initialize, to appease GCC
485 expected_version_str = "";
486 assert_true(0);
487 break;
490 const size_t version_str_len = strlen(expected_version_str);
491 assert_string_len_equal(version_str, expected_version_str, version_str_len);
492 version_str += version_str_len;
494 count = sscanf(version_str, "%d.%d", &major, &minor);
495 assert_int_equal_print(count, 2);
496 assert_int_ge(major, 0);
497 assert_in_range_print(minor, 0, 10);
499 if (context_version != WAFFLE_DONT_CARE) {
500 int expected_major = context_version / 10;
501 int expected_minor = context_version % 10;
503 assert_int_ge(major, expected_major);
504 if (major == expected_major)
505 assert_int_ge(minor, expected_minor);
508 const char *profile_suffix = "";
510 if (waffle_context_api == WAFFLE_CONTEXT_OPENGL) {
511 switch (context_profile) {
512 case WAFFLE_CONTEXT_CORE_PROFILE:
513 profile_suffix = " (Core Profile)";
514 #ifdef __APPLE__
515 fprintf(stderr,
516 "MacOS Core contexts, omit the \"%s\" suffix in "
517 "glGetString(GL_VERSION)."
518 "Applying workaround.\n",
519 profile_suffix);
520 profile_suffix = "";
521 #endif
522 break;
523 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
524 // HACK: seems like Mesa 19.3.3 at least will report
525 if (context_forward_compatible)
526 profile_suffix = " (Core Profile)";
527 else
528 profile_suffix = " (Compatibility Profile)";
529 break;
530 case WAFFLE_DONT_CARE:
531 break;
532 default:
533 assert_true(0);
534 break;
538 char profile_str[30]; // 30 should be enough ;-)
539 sprintf(profile_str, "%d.%d%s", major, minor, profile_suffix);
541 const size_t profile_str_len = strlen(profile_str);
542 assert_string_len_equal(version_str, profile_str, profile_str_len);
544 int version_10x = 10 * major + minor;
546 // Another profile check
547 if (waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 32) {
548 GLint profile_mask = 0;
549 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask);
551 switch (context_profile) {
552 case WAFFLE_CONTEXT_CORE_PROFILE:
553 assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
554 break;
555 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
556 // HACK: seems like Mesa 19.3.3 at least will report
557 if (context_forward_compatible)
558 assert_true(profile_mask & GL_CONTEXT_CORE_PROFILE_BIT);
559 else
560 assert_true(profile_mask &
561 GL_CONTEXT_COMPATIBILITY_PROFILE_BIT);
562 break;
563 case WAFFLE_DONT_CARE:
564 break;
565 default:
566 assert_true(0);
567 break;
571 if ((waffle_context_api == WAFFLE_CONTEXT_OPENGL && version_10x >= 30) ||
572 (waffle_context_api != WAFFLE_CONTEXT_OPENGL && version_10x >= 32)) {
573 GLint context_flags = 0;
574 if (context_forward_compatible || context_debug) {
575 glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
578 if (context_forward_compatible) {
579 assert_true(context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
582 if (context_debug) {
583 assert_true(context_flags & GL_CONTEXT_FLAG_DEBUG_BIT);
587 // GL_ROBUST_ACCESS comes with the following extensions
588 // GL_ARB_robustness
589 // GL_EXT_robustness
590 // GL_KHR_robustness
592 // To keep it simple, assume the correct extension is there if
593 // glGetError is happy ;-)
594 if (context_robust) {
595 GLint robust_flag = 0;
596 glGetIntegerv(GL_CONTEXT_ROBUST_ACCESS, &robust_flag);
598 if (glGetError() == GL_NO_ERROR)
599 assert_true(robust_flag);
602 // Draw.
603 ASSERT_GL(glClearColor(RED_F, GREEN_F, BLUE_F, ALPHA_F));
604 ASSERT_GL(glClear(GL_COLOR_BUFFER_BIT));
605 ASSERT_GL(glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGBA,
606 GL_UNSIGNED_BYTE, ts->actual_pixels));
607 ret = waffle_window_swap_buffers(ts->window);
608 assert_true_with_wfl_error(ret);
610 assert_memory_equal(&ts->actual_pixels, &ts->expect_pixels,
611 sizeof(ts->expect_pixels));
615 // List of tests common to all platforms.
618 // clang-format off
620 #define test_rgb(waffle_api) \
621 static void waffle_api##_rgb(void **state) \
623 gl_basic_draw(state, \
624 .api=WAFFLE_CONTEXT_##waffle_api); \
627 #define test_rgba(waffle_api) \
628 static void waffle_api##_rgba(void **state) \
630 gl_basic_draw(state, \
631 .api=WAFFLE_CONTEXT_##waffle_api, \
632 .alpha=true); \
635 #define test_context_flags(waffle_api, waffle_flags) \
636 static void waffle_api##_##waffle_flags(void **state) \
638 int32_t expect_error = TEST_##waffle_flags & TEST_CTX_FWDCOMPAT ? \
639 WAFFLE_ERROR_BAD_ATTRIBUTE : WAFFLE_NO_ERROR; \
640 gl_basic_draw(state, \
641 .api=WAFFLE_CONTEXT_##waffle_api, \
642 .context_flags=TEST_##waffle_flags, \
643 .expect_error=expect_error); \
646 #define test_version(waffle_api, waffle_version) \
647 static void waffle_api##_##waffle_version(void **state) \
649 gl_basic_draw(state, \
650 .api=WAFFLE_CONTEXT_##waffle_api, \
651 .version=waffle_version); \
654 #define test_version_fwdcompat(waffle_api, waffle_version) \
655 static void waffle_api##_fwdcompat_##waffle_version(void **state) \
657 gl_basic_draw(state, \
658 .api=WAFFLE_CONTEXT_##waffle_api, \
659 .version=waffle_version, \
660 .context_flags=TEST_CTX_FWDCOMPAT); \
663 #define test_profile_version(waffle_profile, waffle_version) \
664 static void waffle_profile##_##waffle_version(void **state) \
666 gl_basic_draw(state, \
667 .api=WAFFLE_CONTEXT_OPENGL, \
668 .version=waffle_version, \
669 .profile=WAFFLE_CONTEXT_##waffle_profile##_PROFILE); \
672 #define test_profile_context_flags(waffle_profile, waffle_flags) \
673 static void waffle_profile##_##waffle_flags(void **state) \
675 gl_basic_draw(state, \
676 .api=WAFFLE_CONTEXT_OPENGL, \
677 .version=32, \
678 .profile=WAFFLE_CONTEXT_##waffle_profile##_PROFILE, \
679 .context_flags=TEST_##waffle_flags); \
684 // Most of the following tests will return ERROR_UNSUPPORTED_ON_PLATFORM
685 // on Apple/CGL, where NO_ERROR is expected.
686 // This is safe, as the test is skipped when the said error occurs.
688 // As BAD_ATTRIBUTE (core validation) takes greater precedence over
689 // UNSUPPORTED_ON_PLATFORM (platform specific one).
690 // Thus we're safe to use the former here, eventhough CGL has support
691 // for neither GLES* nor fwdcompa "CGL and everyone else".
695 // Quick notes which combinations we test and why
696 // - w/o version, for each API/profile combination check variations of
697 // - visual - make sure we can draw fine, duh
698 // - flags - flags selection machinery is funky
699 // - fwdcompat was introduced with OpenGL 3.0, check it and 3.1
700 // - specific version
701 // - all known versions
702 // - no permutation
706 // OPENGL, no profile
708 test_rgb(OPENGL)
709 test_rgba(OPENGL)
711 test_context_flags(OPENGL, CTX_FWDCOMPAT)
712 test_context_flags(OPENGL, CTX_DEBUG)
713 test_context_flags(OPENGL, CTX_ROBUST)
714 test_context_flags(OPENGL, CTX_LOSE_CONTEXT)
716 test_version_fwdcompat(OPENGL, 30)
717 test_version_fwdcompat(OPENGL, 31)
719 test_version(OPENGL, 10)
720 test_version(OPENGL, 11)
721 test_version(OPENGL, 12)
722 test_version(OPENGL, 13)
723 test_version(OPENGL, 14)
724 test_version(OPENGL, 15)
725 test_version(OPENGL, 20)
726 test_version(OPENGL, 21)
727 test_version(OPENGL, 30)
728 test_version(OPENGL, 31)
730 // OPENGL, CORE profile
732 test_profile_context_flags(CORE, CTX_FWDCOMPAT)
733 test_profile_context_flags(CORE, CTX_DEBUG)
734 test_profile_context_flags(CORE, CTX_ROBUST)
735 test_profile_context_flags(CORE, CTX_LOSE_CONTEXT)
737 test_profile_version(CORE, 32)
738 test_profile_version(CORE, 33)
739 test_profile_version(CORE, 40)
740 test_profile_version(CORE, 41)
741 test_profile_version(CORE, 42)
742 test_profile_version(CORE, 43)
743 test_profile_version(CORE, 44)
744 test_profile_version(CORE, 45)
745 test_profile_version(CORE, 46)
747 // OPENGL, COMPATIBILITY profile
749 test_profile_context_flags(COMPATIBILITY, CTX_FWDCOMPAT)
750 test_profile_context_flags(COMPATIBILITY, CTX_DEBUG)
751 test_profile_context_flags(COMPATIBILITY, CTX_ROBUST)
752 test_profile_context_flags(COMPATIBILITY, CTX_LOSE_CONTEXT)
754 test_profile_version(COMPATIBILITY, 32)
755 test_profile_version(COMPATIBILITY, 33)
756 test_profile_version(COMPATIBILITY, 40)
757 test_profile_version(COMPATIBILITY, 41)
758 test_profile_version(COMPATIBILITY, 42)
759 test_profile_version(COMPATIBILITY, 43)
760 test_profile_version(COMPATIBILITY, 44)
761 test_profile_version(COMPATIBILITY, 45)
762 test_profile_version(COMPATIBILITY, 46)
764 // OPENGL_ES1
766 test_rgb(OPENGL_ES1)
767 test_rgba(OPENGL_ES1)
769 test_context_flags(OPENGL_ES1, CTX_FWDCOMPAT)
770 test_context_flags(OPENGL_ES1, CTX_DEBUG)
771 test_context_flags(OPENGL_ES1, CTX_ROBUST)
772 test_context_flags(OPENGL_ES1, CTX_LOSE_CONTEXT)
774 test_version(OPENGL_ES1, 10)
775 test_version(OPENGL_ES1, 11)
777 // OPENGL_ES2
779 test_rgb(OPENGL_ES2)
780 test_rgba(OPENGL_ES2)
782 test_context_flags(OPENGL_ES2, CTX_FWDCOMPAT)
783 test_context_flags(OPENGL_ES2, CTX_DEBUG)
784 test_context_flags(OPENGL_ES2, CTX_ROBUST)
785 test_context_flags(OPENGL_ES2, CTX_LOSE_CONTEXT)
787 test_version(OPENGL_ES2, 20)
789 // OPENGL_ES3
791 test_rgb(OPENGL_ES3)
792 test_rgba(OPENGL_ES3)
794 test_context_flags(OPENGL_ES3, CTX_FWDCOMPAT)
795 test_context_flags(OPENGL_ES3, CTX_DEBUG)
796 test_context_flags(OPENGL_ES3, CTX_ROBUST)
797 test_context_flags(OPENGL_ES3, CTX_LOSE_CONTEXT)
799 test_version(OPENGL_ES3, 30)
800 test_version(OPENGL_ES3, 31)
801 test_version(OPENGL_ES3, 32)
804 #ifdef __APPLE__
806 static void
807 removeArg(int index, int *argc, char **argv)
808 // clang-format on
810 --*argc;
811 for (; index < *argc; ++index)
812 argv[index] = argv[index + 1];
815 static void
816 removeXcodeArgs(int *argc, char **argv)
818 // Xcode sometimes adds additional arguments.
819 for (int i = 1; i < *argc;) {
820 if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0 ||
821 strcmp(argv[i], "-ApplePersistenceIgnoreState") == 0) {
822 removeArg(i, argc, argv);
823 removeArg(i, argc, argv);
824 } else
825 ++i;
829 #endif // __APPLE__
831 static const char *usage_message =
832 "Usage:\n"
833 " gl_basic_test <Required Parameter> [Options]\n"
834 "\n"
835 "Description:\n"
836 " Run the basic functionality tests.\n"
837 "\n"
838 "Required Parameter:\n"
839 " -p, --platform\n"
840 " One of: cgl, gbm, glx, wayland, wgl or x11_egl\n"
841 "\n"
842 "Options:\n"
843 " -h, --help\n"
844 " Print gl_basic_test usage information.\n";
846 #if defined(__GNUC__)
847 #define NORETURN __attribute__((noreturn))
848 #elif defined(_MSC_VER)
849 #define NORETURN __declspec(noreturn)
850 #else
851 #define NORETURN
852 #endif
854 #if defined(__clang__)
855 #define PRINTFLIKE(f, a) __attribute__((format(printf, f, a)))
856 #elif defined(__GNUC__)
857 #define PRINTFLIKE(f, a) __attribute__((format(gnu_printf, f, a)))
858 #else
859 #define PRINTFLIKE(f, a)
860 #endif
862 static void NORETURN
863 write_usage_and_exit(FILE *f, int exit_code)
865 fprintf(f, "%s", usage_message);
866 exit(exit_code);
869 enum {
870 OPT_PLATFORM = 'p',
871 OPT_HELP = 'h',
874 static const struct option get_opts[] = {
875 { .name = "platform", .has_arg = required_argument, .val = OPT_PLATFORM },
876 { .name = "help", .has_arg = no_argument, .val = OPT_HELP },
879 static void NORETURN PRINTFLIKE(1, 2)
880 usage_error_printf(const char *fmt, ...)
882 fprintf(stderr, "gl_basic_test usage error: ");
884 if (fmt) {
885 va_list ap;
886 va_start(ap, fmt);
887 vfprintf(stderr, fmt, ap);
888 va_end(ap);
889 fprintf(stderr, " ");
892 fprintf(stderr, "(see gl_basic_test --help)\n");
893 exit(EXIT_FAILURE);
896 struct enum_map {
897 int i;
898 const char *s;
901 static const struct enum_map platform_map[] = {
902 { WAFFLE_PLATFORM_CGL, "cgl" },
903 { WAFFLE_PLATFORM_GBM, "gbm" },
904 { WAFFLE_PLATFORM_GLX, "glx" },
905 { WAFFLE_PLATFORM_WAYLAND, "wayland" },
906 { WAFFLE_PLATFORM_WGL, "wgl" },
907 { WAFFLE_PLATFORM_X11_EGL, "x11_egl" },
908 { WAFFLE_PLATFORM_SURFACELESS_EGL, "surfaceless_egl" },
909 { WAFFLE_PLATFORM_SURFACELESS_EGL, "sl" },
910 { 0, 0 },
913 /// @brief Translate string to `enum waffle_enum`.
915 /// @param self is a list of map items. The last item must be zero-filled.
916 /// @param result is altered only if @a s if found.
917 /// @return true if @a s was found in @a map.
918 static bool
919 enum_map_translate_str(const struct enum_map *self, const char *s, int *result)
921 for (const struct enum_map *i = self; i->i != 0; ++i) {
922 if (!strncmp(s, i->s, strlen(i->s) + 1)) {
923 *result = i->i;
924 return true;
928 return false;
931 /// @return true on success.
932 static void
933 parse_args(int argc, char *argv[])
935 bool loop_get_opt = true;
937 #ifdef __APPLE__
938 removeXcodeArgs(&argc, argv);
939 #endif
941 // prevent getopt_long from printing an error message
942 opterr = 0;
944 while (loop_get_opt) {
945 int opt = getopt_long(argc, argv, "hp:", get_opts, NULL);
946 switch (opt) {
947 case -1:
948 loop_get_opt = false;
949 break;
950 case '?':
951 goto error_unrecognized_arg;
952 case OPT_PLATFORM:
953 if (!enum_map_translate_str(platform_map, optarg,
954 &waffle_platform)) {
955 usage_error_printf("'%s' is not a valid platform", optarg);
957 platform = optarg;
958 break;
959 case OPT_HELP:
960 write_usage_and_exit(stdout, EXIT_SUCCESS);
961 break;
962 default:
963 loop_get_opt = false;
964 break;
968 if (optind < argc) {
969 goto error_unrecognized_arg;
972 if (!waffle_platform) {
973 usage_error_printf("--platform is required");
976 return;
978 error_unrecognized_arg:
979 if (optarg)
980 usage_error_printf("unrecognized option '%s'", optarg);
981 else if (optopt)
982 usage_error_printf("unrecognized option '-%c'", optopt);
983 else
984 usage_error_printf("unrecognized option");
988 main(int argc, char *argv[])
990 parse_args(argc, argv);
992 #define unit_test_make(name) \
993 cmocka_unit_test_setup_teardown(name, gl_basic_init, gl_basic_fini)
995 const struct CMUnitTest tests[] = {
997 // OPENGL, no profile
999 unit_test_make(OPENGL_rgb),
1000 unit_test_make(OPENGL_rgba),
1002 unit_test_make(OPENGL_CTX_FWDCOMPAT),
1003 unit_test_make(OPENGL_CTX_DEBUG),
1004 unit_test_make(OPENGL_CTX_ROBUST),
1005 unit_test_make(OPENGL_CTX_LOSE_CONTEXT),
1007 unit_test_make(OPENGL_fwdcompat_30),
1008 unit_test_make(OPENGL_fwdcompat_31),
1010 unit_test_make(OPENGL_10),
1011 unit_test_make(OPENGL_11),
1012 unit_test_make(OPENGL_12),
1013 unit_test_make(OPENGL_13),
1014 unit_test_make(OPENGL_14),
1015 unit_test_make(OPENGL_15),
1016 unit_test_make(OPENGL_20),
1017 unit_test_make(OPENGL_21),
1018 unit_test_make(OPENGL_30),
1019 unit_test_make(OPENGL_31),
1021 // OPENGL, CORE profile
1023 unit_test_make(CORE_CTX_FWDCOMPAT),
1024 unit_test_make(CORE_CTX_DEBUG),
1025 unit_test_make(CORE_CTX_ROBUST),
1026 unit_test_make(CORE_CTX_LOSE_CONTEXT),
1028 unit_test_make(CORE_32),
1029 unit_test_make(CORE_33),
1030 unit_test_make(CORE_40),
1031 unit_test_make(CORE_41),
1032 unit_test_make(CORE_42),
1033 unit_test_make(CORE_43),
1034 unit_test_make(CORE_44),
1035 unit_test_make(CORE_45),
1036 unit_test_make(CORE_46),
1038 // OPENGL, COMPATIBILITY profile
1040 unit_test_make(COMPATIBILITY_CTX_FWDCOMPAT),
1041 unit_test_make(COMPATIBILITY_CTX_DEBUG),
1042 unit_test_make(COMPATIBILITY_CTX_ROBUST),
1043 unit_test_make(COMPATIBILITY_CTX_LOSE_CONTEXT),
1045 unit_test_make(COMPATIBILITY_32),
1046 unit_test_make(COMPATIBILITY_33),
1047 unit_test_make(COMPATIBILITY_40),
1048 unit_test_make(COMPATIBILITY_41),
1049 unit_test_make(COMPATIBILITY_42),
1050 unit_test_make(COMPATIBILITY_43),
1051 unit_test_make(COMPATIBILITY_44),
1052 unit_test_make(COMPATIBILITY_45),
1053 unit_test_make(COMPATIBILITY_46),
1055 // OPENGL_ES1
1057 unit_test_make(OPENGL_ES1_rgb),
1058 unit_test_make(OPENGL_ES1_rgba),
1060 unit_test_make(OPENGL_ES1_CTX_FWDCOMPAT),
1061 unit_test_make(OPENGL_ES1_CTX_DEBUG),
1062 unit_test_make(OPENGL_ES1_CTX_ROBUST),
1063 unit_test_make(OPENGL_ES1_CTX_LOSE_CONTEXT),
1065 unit_test_make(OPENGL_ES1_10),
1066 unit_test_make(OPENGL_ES1_11),
1068 // OPENGL_ES2
1070 unit_test_make(OPENGL_ES2_rgb),
1071 unit_test_make(OPENGL_ES2_rgba),
1073 unit_test_make(OPENGL_ES2_CTX_FWDCOMPAT),
1074 unit_test_make(OPENGL_ES2_CTX_DEBUG),
1075 unit_test_make(OPENGL_ES2_CTX_ROBUST),
1076 unit_test_make(OPENGL_ES2_CTX_LOSE_CONTEXT),
1078 unit_test_make(OPENGL_ES2_20),
1080 // OPENGL_ES3
1082 unit_test_make(OPENGL_ES3_rgb),
1083 unit_test_make(OPENGL_ES3_rgba),
1085 unit_test_make(OPENGL_ES3_CTX_FWDCOMPAT),
1086 unit_test_make(OPENGL_ES3_CTX_DEBUG),
1087 unit_test_make(OPENGL_ES3_CTX_ROBUST),
1088 unit_test_make(OPENGL_ES3_CTX_LOSE_CONTEXT),
1090 unit_test_make(OPENGL_ES3_30),
1091 unit_test_make(OPENGL_ES3_31),
1092 unit_test_make(OPENGL_ES3_32),
1095 return cmocka_run_group_tests_name(platform, tests, NULL, NULL);