1 // SPDX-FileCopyrightText: Copyright 2012 Intel Corporation
2 // SPDX-License-Identifier: BSD-2-Clause
5 /// @brief Test basic OpenGL rendering with all platform/gl_api combinations.
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.
17 #include <setjmp.h> // for cmocka.h
18 #include <stdarg.h> // for va_start, va_end
23 #include <sys/types.h>
32 #include "gl_basic_cocoa.h"
38 // Choosing a smaller window would shorten the execution time of pixel
39 // validation, but Windows 7 enforces a minimum size.
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
{
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) \
68 assert_false(glGetError()); \
71 typedef unsigned int GLenum
;
72 typedef unsigned char GLboolean
;
73 typedef unsigned int GLbitfield
;
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
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
109 #define APIENTRY __stdcall
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
,
120 static void(APIENTRY
*glClear
)(GLbitfield mask
);
121 static void(APIENTRY
*glReadPixels
)(GLint x
,
132 struct test_state_gl_basic
*ts
;
134 ts
= calloc(1, sizeof(*ts
));
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
)];
147 // Fill actual_pixels with canaries.
148 memset(&ts
->actual_pixels
, 0x99, sizeof(ts
->actual_pixels
));
155 teardown(void **state
)
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
169 get_gl_symbol(enum waffle_enum context_api
, const char *name
)
172 enum waffle_enum dl
= 0;
174 switch (context_api
) {
175 case WAFFLE_CONTEXT_OPENGL
:
176 dl
= WAFFLE_DL_OPENGL
;
178 case WAFFLE_CONTEXT_OPENGL_ES1
:
179 dl
= WAFFLE_DL_OPENGL_ES1
;
181 case WAFFLE_CONTEXT_OPENGL_ES2
:
182 dl
= WAFFLE_DL_OPENGL_ES2
;
184 case WAFFLE_CONTEXT_OPENGL_ES3
:
185 dl
= WAFFLE_DL_OPENGL_ES3
;
192 if (waffle_dl_can_open(dl
)) {
193 sym
= waffle_dl_sym(dl
, name
);
197 sym
= waffle_get_proc_address(name
);
203 static int32_t waffle_platform
;
204 static const char *platform
;
210 gl_basic_init(void **state
)
212 struct test_state_gl_basic
*ts
;
215 ret
= setup((void **)&ts
);
219 const int32_t init_attrib_list
[] = {
225 ts
->initialized
= waffle_init(init_attrib_list
);
226 if (!ts
->initialized
) {
237 gl_basic_fini(void **state
)
239 struct test_state_gl_basic
*ts
= *state
;
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
);
246 ret
= waffle_window_destroy(ts
->window
);
248 ret
= waffle_context_destroy(ts
->ctx
);
250 ret
= waffle_config_destroy(ts
->config
);
252 ret
= waffle_display_disconnect(ts
->dpy
);
255 ret
= waffle_teardown();
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, ...) \
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, \
279 struct gl_basic_draw_args__
{
283 int32_t expect_error
;
284 uint32_t context_flags
;
288 #define assert_int_equal_print(_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) \
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) { \
303 #_a " (%d) outside range " #_min "(%d) - " #_max "(%d)\n", _a, \
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, \
312 fprintf(stderr, "Received (" #_actual "): \"%.*s\"\n", (int)_len, \
314 assert_true(0 && "String comparison failed"); \
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
,
327 fprintf(stderr
, "Waffle error: 0x%x %s\n", info
->code
, code
);
330 #define assert_true_with_wfl_error(_arg) \
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
;
351 int32_t config_attrib_list
[64];
354 const intptr_t window_attrib_list
[] = {
357 WAFFLE_WINDOW_HEIGHT
,
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;
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;
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
);
407 assert_true(ts
->config
== NULL
);
408 assert_true((int32_t)waffle_error_get_code() == expect_error
);
410 } else if (ts
->config
== NULL
) {
411 switch (waffle_error_get_code()) {
412 case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM
:
414 case WAFFLE_ERROR_UNKNOWN
:
415 // Assume that the native platform rejected the requested
418 // XXX: skip() is not annotated as noreturn, leading to compiler
419 // warning about implicit fallthrough
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
:
437 case WAFFLE_ERROR_UNKNOWN
:
438 // Assume that the native platform rejected the requested
441 // XXX: skip() is not annotated as noreturn, leading to compiler
442 // warning about implicit fallthrough
445 assert_true_with_wfl_error(ts
->ctx
);
449 // Get OpenGL functions.
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"));
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
= "";
476 case WAFFLE_CONTEXT_OPENGL_ES1
:
477 expected_version_str
= "OpenGL ES-CM ";
479 case WAFFLE_CONTEXT_OPENGL_ES2
:
480 case WAFFLE_CONTEXT_OPENGL_ES3
:
481 expected_version_str
= "OpenGL ES ";
484 // Explicitly initialize, to appease GCC
485 expected_version_str
= "";
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)";
516 "MacOS Core contexts, omit the \"%s\" suffix in "
517 "glGetString(GL_VERSION)."
518 "Applying workaround.\n",
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)";
528 profile_suffix
= " (Compatibility Profile)";
530 case WAFFLE_DONT_CARE
:
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
);
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
);
560 assert_true(profile_mask
&
561 GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
);
563 case WAFFLE_DONT_CARE
:
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
);
583 assert_true(context_flags
& GL_CONTEXT_FLAG_DEBUG_BIT
);
587 // GL_ROBUST_ACCESS comes with the following extensions
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
);
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.
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, \
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, \
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
706 // OPENGL, no profile
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)
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)
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)
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)
807 removeArg(int index
, int *argc
, char **argv
)
811 for (; index
< *argc
; ++index
)
812 argv
[index
] = argv
[index
+ 1];
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
);
831 static const char *usage_message
=
833 " gl_basic_test <Required Parameter> [Options]\n"
836 " Run the basic functionality tests.\n"
838 "Required Parameter:\n"
840 " One of: cgl, gbm, glx, wayland, wgl or x11_egl\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)
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)))
859 #define PRINTFLIKE(f, a)
863 write_usage_and_exit(FILE *f
, int exit_code
)
865 fprintf(f
, "%s", usage_message
);
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: ");
887 vfprintf(stderr
, fmt
, ap
);
889 fprintf(stderr
, " ");
892 fprintf(stderr
, "(see gl_basic_test --help)\n");
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" },
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.
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)) {
931 /// @return true on success.
933 parse_args(int argc
, char *argv
[])
935 bool loop_get_opt
= true;
938 removeXcodeArgs(&argc
, argv
);
941 // prevent getopt_long from printing an error message
944 while (loop_get_opt
) {
945 int opt
= getopt_long(argc
, argv
, "hp:", get_opts
, NULL
);
948 loop_get_opt
= false;
951 goto error_unrecognized_arg
;
953 if (!enum_map_translate_str(platform_map
, optarg
,
955 usage_error_printf("'%s' is not a valid platform", optarg
);
960 write_usage_and_exit(stdout
, EXIT_SUCCESS
);
963 loop_get_opt
= false;
969 goto error_unrecognized_arg
;
972 if (!waffle_platform
) {
973 usage_error_printf("--platform is required");
978 error_unrecognized_arg
:
980 usage_error_printf("unrecognized option '%s'", optarg
);
982 usage_error_printf("unrecognized option '-%c'", optopt
);
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
),
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
),
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
),
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
);