1 // Copyright 2012 Intel Corporation
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
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.
27 /// @brief Test basic OpenGL rendering with all platform/gl_api combinations.
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
44 #include <sys/types.h>
55 #include "gl_basic_cocoa.h"
58 // Choosing a smaller window would shorten the execution time of pixel
59 // validation, but Windows 7 enforces a minimum size.
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
{
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) \
88 assert_false(glGetError()); \
91 typedef unsigned int GLenum
;
92 typedef unsigned char GLboolean
;
93 typedef unsigned int GLbitfield
;
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
129 #define APIENTRY __stdcall
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
,
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
,
149 struct test_state_gl_basic
*ts
;
151 ts
= calloc(1, sizeof(*ts
));
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
)];
164 // Fill actual_pixels with canaries.
165 memset(&ts
->actual_pixels
, 0x99, sizeof(ts
->actual_pixels
));
172 teardown(void **state
)
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
186 get_gl_symbol(enum waffle_enum context_api
, const char *name
)
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
);
204 sym
= waffle_get_proc_address(name
);
211 gl_basic_init(void **state
, int32_t waffle_platform
)
213 struct test_state_gl_basic
*ts
;
216 ret
= setup((void **)&ts
);
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 ?
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();
261 #define gl_basic_draw(state, ...) \
263 gl_basic_draw__(state, (struct gl_basic_draw_args__) { \
265 .version = WAFFLE_DONT_CARE, \
266 .profile = WAFFLE_DONT_CARE, \
267 .forward_compatible = false, \
271 .expect_error = WAFFLE_NO_ERROR, \
275 struct gl_basic_draw_args__
{
279 int32_t expect_error
;
280 bool forward_compatible
;
286 #define assert_int_equal_print(_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) \
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", \
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"); \
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
);
321 fprintf(stderr
, "Waffle error: 0x%x %s\n", info
->code
, code
);
324 #define assert_true_with_wfl_error(_arg) \
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
;
344 int32_t config_attrib_list
[64];
347 const intptr_t window_attrib_list
[] = {
348 WAFFLE_WINDOW_WIDTH
, WINDOW_WIDTH
,
349 WAFFLE_WINDOW_HEIGHT
, WINDOW_HEIGHT
,
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;
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;
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
);
394 assert_true(ts
->config
== NULL
);
395 assert_true((int32_t)waffle_error_get_code() == expect_error
);
397 } else if (ts
->config
== NULL
) {
398 switch (waffle_error_get_code()) {
399 case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM
:
401 case WAFFLE_ERROR_UNKNOWN
:
402 // Assume that the native platform rejected the requested
405 // XXX: skip() is not annotated as noreturn, leading to compiler
406 // warning about implicit fallthrough
409 assert_true_with_wfl_error(ts
->config
);
413 ts
->window
= waffle_window_create2(ts
->config
, window_attrib_list
);
414 assert_true_with_wfl_error(ts
->window
);
416 ret
= waffle_window_show(ts
->window
);
417 assert_true_with_wfl_error(ret
);
419 ts
->ctx
= waffle_context_create(ts
->config
, NULL
);
420 if (ts
->ctx
== NULL
) {
421 switch (waffle_error_get_code()) {
422 case WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM
:
424 case WAFFLE_ERROR_UNKNOWN
:
425 // Assume that the native platform rejected the requested
428 // XXX: skip() is not annotated as noreturn, leading to compiler
429 // warning about implicit fallthrough
432 assert_true_with_wfl_error(ts
->ctx
);
436 // Get OpenGL functions.
437 assert_true(glClear
= get_gl_symbol(waffle_context_api
, "glClear"));
438 assert_true(glClearColor
= get_gl_symbol(waffle_context_api
, "glClearColor"));
439 assert_true(glGetError
= get_gl_symbol(waffle_context_api
, "glGetError"));
440 assert_true(glGetIntegerv
= get_gl_symbol(waffle_context_api
, "glGetIntegerv"));
441 assert_true(glReadPixels
= get_gl_symbol(waffle_context_api
, "glReadPixels"));
442 assert_true(glGetString
= get_gl_symbol(waffle_context_api
, "glGetString"));
444 ret
= waffle_make_current(ts
->dpy
, ts
->window
, ts
->ctx
);
445 assert_true_with_wfl_error(ret
);
447 assert_true(waffle_get_current_display() == ts
->dpy
);
448 assert_true(waffle_get_current_window() == ts
->window
);
449 assert_true(waffle_get_current_context() == ts
->ctx
);
451 const char *version_str
, *expected_version_str
;
452 int major
, minor
, count
;
454 ASSERT_GL(version_str
= (const char *) glGetString(GL_VERSION
));
455 assert_true(version_str
!= NULL
);
457 switch (waffle_context_api
) {
458 case WAFFLE_CONTEXT_OPENGL
:
459 expected_version_str
= "";
461 case WAFFLE_CONTEXT_OPENGL_ES1
:
462 expected_version_str
= "OpenGL ES-CM ";
464 case WAFFLE_CONTEXT_OPENGL_ES2
:
465 case WAFFLE_CONTEXT_OPENGL_ES3
:
466 expected_version_str
= "OpenGL ES ";
469 // Explicitly initialize, to appease GCC
470 expected_version_str
= "";
475 const size_t version_str_len
= strlen(expected_version_str
);
476 assert_string_len_equal(version_str
, expected_version_str
, version_str_len
);
477 version_str
+= version_str_len
;
479 count
= sscanf(version_str
, "%d.%d", &major
, &minor
);
480 assert_int_equal_print(count
, 2);
481 assert_int_ge(major
, 0);
482 assert_in_range_print(minor
, 0, 10);
484 if (context_version
!= WAFFLE_DONT_CARE
) {
485 int expected_major
= context_version
/ 10;
486 int expected_minor
= context_version
% 10;
488 assert_int_ge(major
, expected_major
);
489 if (major
== expected_major
)
490 assert_int_ge(minor
, expected_minor
);
493 const char *profile_suffix
= "";
495 if (waffle_context_api
== WAFFLE_CONTEXT_OPENGL
) {
496 switch (context_profile
) {
497 case WAFFLE_CONTEXT_CORE_PROFILE
:
498 profile_suffix
= " (Core Profile)";
500 fprintf(stderr
, "MacOS Core contexts, omit the \"%s\" suffix in glGetString(GL_VERSION)."
501 "Applying workaround.\n", profile_suffix
);
505 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE
:
506 // HACK: seems like Mesa 19.3.3 at least will report
507 if (context_forward_compatible
)
508 profile_suffix
= " (Core Profile)";
510 profile_suffix
= " (Compatibility Profile)";
512 case WAFFLE_DONT_CARE
:
520 char profile_str
[30]; // 30 should be enough ;-)
521 sprintf(profile_str
, "%d.%d%s", major
, minor
, profile_suffix
);
523 const size_t profile_str_len
= strlen(profile_str
);
524 assert_string_len_equal(version_str
, profile_str
, profile_str_len
);
526 int version_10x
= 10 * major
+ minor
;
528 // Another profile check
529 if (waffle_context_api
== WAFFLE_CONTEXT_OPENGL
&& version_10x
>= 32) {
530 GLint profile_mask
= 0;
531 glGetIntegerv(GL_CONTEXT_PROFILE_MASK
, &profile_mask
);
533 switch (context_profile
) {
534 case WAFFLE_CONTEXT_CORE_PROFILE
:
535 assert_true(profile_mask
& GL_CONTEXT_CORE_PROFILE_BIT
);
537 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE
:
538 // HACK: seems like Mesa 19.3.3 at least will report
539 if (context_forward_compatible
)
540 assert_true(profile_mask
& GL_CONTEXT_CORE_PROFILE_BIT
);
542 assert_true(profile_mask
& GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
);
544 case WAFFLE_DONT_CARE
:
552 if ((waffle_context_api
== WAFFLE_CONTEXT_OPENGL
&& version_10x
>= 30) ||
553 (waffle_context_api
!= WAFFLE_CONTEXT_OPENGL
&& version_10x
>= 32)) {
554 GLint context_flags
= 0;
555 if (context_forward_compatible
|| context_debug
) {
556 glGetIntegerv(GL_CONTEXT_FLAGS
, &context_flags
);
559 if (context_forward_compatible
) {
560 assert_true(context_flags
& GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
);
564 assert_true(context_flags
& GL_CONTEXT_FLAG_DEBUG_BIT
);
568 // GL_ROBUST_ACCESS comes with the following extensions
573 // To keep it simple, assume the correct extension is there if
574 // glGetError is happy ;-)
575 if (context_robust
) {
576 GLint robust_flag
= 0;
577 glGetIntegerv(GL_CONTEXT_ROBUST_ACCESS
, &robust_flag
);
579 if (glGetError() == GL_NO_ERROR
)
580 assert_true(robust_flag
);
584 ASSERT_GL(glClearColor(RED_F
, GREEN_F
, BLUE_F
, ALPHA_F
));
585 ASSERT_GL(glClear(GL_COLOR_BUFFER_BIT
));
586 ASSERT_GL(glReadPixels(0, 0, WINDOW_WIDTH
, WINDOW_HEIGHT
,
587 GL_RGBA
, GL_UNSIGNED_BYTE
,
589 ret
= waffle_window_swap_buffers(ts
->window
);
590 assert_true_with_wfl_error(ret
);
592 assert_memory_equal(&ts
->actual_pixels
, &ts
->expect_pixels
,
593 sizeof(ts
->expect_pixels
));
597 // List of tests common to all platforms.
600 #define test_XX_rgb(context_api, waffle_api, error) \
601 static void test_gl_basic_##context_api##_rgb(void **state) \
603 gl_basic_draw(state, \
604 .api=WAFFLE_CONTEXT_##waffle_api, \
605 .expect_error=WAFFLE_##error); \
608 #define test_XX_rgba(context_api, waffle_api, error) \
609 static void test_gl_basic_##context_api##_rgba(void **state) \
611 gl_basic_draw(state, \
612 .api=WAFFLE_CONTEXT_##waffle_api, \
614 .expect_error=WAFFLE_##error); \
617 #define test_XX_fwdcompat(context_api, waffle_api, error) \
618 static void test_gl_basic_##context_api##_fwdcompat(void **state) \
620 gl_basic_draw(state, \
621 .api=WAFFLE_CONTEXT_##waffle_api, \
622 .forward_compatible=true, \
623 .expect_error=WAFFLE_##error); \
626 #define test_XX_debug(context_api, waffle_api, error) \
627 static void test_gl_basic_##context_api##_debug(void **state) \
629 gl_basic_draw(state, \
630 .api=WAFFLE_CONTEXT_##waffle_api, \
632 .expect_error=WAFFLE_##error); \
635 #define test_XX_robust(context_api, waffle_api, error) \
636 static void test_gl_basic_##context_api##_robust(void **state) \
638 gl_basic_draw(state, \
639 .api=WAFFLE_CONTEXT_##waffle_api, \
641 .expect_error=WAFFLE_##error); \
644 #define test_glXX(waffle_version, error) \
645 static void test_gl_basic_gl##waffle_version(void **state) \
647 gl_basic_draw(state, \
648 .api=WAFFLE_CONTEXT_OPENGL, \
649 .version=waffle_version, \
650 .expect_error=WAFFLE_##error); \
653 #define test_glXX_fwdcompat(waffle_version, error) \
654 static void test_gl_basic_gl##waffle_version##_fwdcompat(void **state) \
656 gl_basic_draw(state, \
657 .api=WAFFLE_CONTEXT_OPENGL, \
658 .version=waffle_version, \
659 .forward_compatible=true, \
660 .expect_error=WAFFLE_##error); \
663 #define test_glXX_core(waffle_version, error) \
664 static void test_gl_basic_gl##waffle_version##_core(void **state) \
666 gl_basic_draw(state, \
667 .api=WAFFLE_CONTEXT_OPENGL, \
668 .version=waffle_version, \
669 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
670 .expect_error=WAFFLE_##error); \
673 #define test_glXX_core_fwdcompat(waffle_version, error) \
674 static void test_gl_basic_gl##waffle_version##_core_fwdcompat(void **state) \
676 gl_basic_draw(state, \
677 .api=WAFFLE_CONTEXT_OPENGL, \
678 .version=waffle_version, \
679 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
680 .forward_compatible=true, \
681 .expect_error=WAFFLE_##error); \
684 #define test_glXX_core_debug(waffle_version, error) \
685 static void test_gl_basic_gl##waffle_version##_core_debug(void **state) \
687 gl_basic_draw(state, \
688 .api=WAFFLE_CONTEXT_OPENGL, \
689 .version=waffle_version, \
690 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
692 .expect_error=WAFFLE_##error); \
695 #define test_glXX_core_robust(waffle_version, error) \
696 static void test_gl_basic_gl##waffle_version##_core_robust(void **state) \
698 gl_basic_draw(state, \
699 .api=WAFFLE_CONTEXT_OPENGL, \
700 .version=waffle_version, \
701 .profile=WAFFLE_CONTEXT_CORE_PROFILE, \
703 .expect_error=WAFFLE_##error); \
706 #define test_glXX_compat(waffle_version, error) \
707 static void test_gl_basic_gl##waffle_version##_compat(void **state) \
709 gl_basic_draw(state, \
710 .api=WAFFLE_CONTEXT_OPENGL, \
711 .version=waffle_version, \
712 .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, \
713 .expect_error=WAFFLE_##error); \
716 #define test_glXX_compat_fwdcompat(waffle_version, error) \
717 static void test_gl_basic_gl##waffle_version##_compat_fwdcompat(void **state) \
719 gl_basic_draw(state, \
720 .api=WAFFLE_CONTEXT_OPENGL, \
721 .version=waffle_version, \
722 .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, \
723 .forward_compatible=true, \
724 .expect_error=WAFFLE_##error); \
727 #define test_glXX_compat_debug(waffle_version, error) \
728 static void test_gl_basic_gl##waffle_version##_compat_debug(void **state) \
730 gl_basic_draw(state, \
731 .api=WAFFLE_CONTEXT_OPENGL, \
732 .version=waffle_version, \
733 .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, \
735 .expect_error=WAFFLE_##error); \
738 #define test_glXX_compat_robust(waffle_version, error) \
739 static void test_gl_basic_gl##waffle_version##_compat_robust(void **state) \
741 gl_basic_draw(state, \
742 .api=WAFFLE_CONTEXT_OPENGL, \
743 .version=waffle_version, \
744 .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, \
746 .expect_error=WAFFLE_##error); \
749 #define test_glesXX(api_version, waffle_version, error) \
750 static void test_gl_basic_gles##waffle_version(void **state) \
752 gl_basic_draw(state, \
753 .api=WAFFLE_CONTEXT_OPENGL_ES##api_version, \
754 .version=waffle_version, \
755 .expect_error=WAFFLE_##error); \
759 #define CREATE_TESTSUITE(waffle_platform, platform) \
762 setup_##platform(void **state) \
764 return gl_basic_init(state, waffle_platform); \
768 testsuite_##platform(void) \
770 const struct CMUnitTest tests[] = { \
772 unit_test_make(test_gl_basic_gl_rgb), \
773 unit_test_make(test_gl_basic_gl_rgba), \
774 unit_test_make(test_gl_basic_gl_fwdcompat), \
775 unit_test_make(test_gl_basic_gl_debug), \
776 unit_test_make(test_gl_basic_gl_robust), \
778 unit_test_make(test_gl_basic_gl10), \
779 unit_test_make(test_gl_basic_gl11), \
780 unit_test_make(test_gl_basic_gl12), \
781 unit_test_make(test_gl_basic_gl13), \
782 unit_test_make(test_gl_basic_gl14), \
783 unit_test_make(test_gl_basic_gl15), \
784 unit_test_make(test_gl_basic_gl20), \
785 unit_test_make(test_gl_basic_gl21), \
787 unit_test_make(test_gl_basic_gl30), \
788 unit_test_make(test_gl_basic_gl30_fwdcompat), \
789 unit_test_make(test_gl_basic_gl31), \
790 unit_test_make(test_gl_basic_gl31_fwdcompat), \
792 unit_test_make(test_gl_basic_gl32_core), \
793 unit_test_make(test_gl_basic_gl32_core_fwdcompat), \
794 unit_test_make(test_gl_basic_gl32_core_debug), \
795 unit_test_make(test_gl_basic_gl32_core_robust), \
796 unit_test_make(test_gl_basic_gl33_core), \
797 unit_test_make(test_gl_basic_gl40_core), \
798 unit_test_make(test_gl_basic_gl41_core), \
799 unit_test_make(test_gl_basic_gl42_core), \
800 unit_test_make(test_gl_basic_gl43_core), \
801 unit_test_make(test_gl_basic_gl44_core), \
802 unit_test_make(test_gl_basic_gl45_core), \
803 unit_test_make(test_gl_basic_gl46_core), \
805 unit_test_make(test_gl_basic_gl32_compat), \
806 unit_test_make(test_gl_basic_gl32_compat_fwdcompat), \
807 unit_test_make(test_gl_basic_gl32_compat_debug), \
808 unit_test_make(test_gl_basic_gl32_compat_robust), \
809 unit_test_make(test_gl_basic_gl33_compat), \
810 unit_test_make(test_gl_basic_gl40_compat), \
811 unit_test_make(test_gl_basic_gl41_compat), \
812 unit_test_make(test_gl_basic_gl42_compat), \
813 unit_test_make(test_gl_basic_gl43_compat), \
814 unit_test_make(test_gl_basic_gl44_compat), \
815 unit_test_make(test_gl_basic_gl45_compat), \
816 unit_test_make(test_gl_basic_gl46_compat), \
818 unit_test_make(test_gl_basic_gles1_rgb), \
819 unit_test_make(test_gl_basic_gles1_rgba), \
820 unit_test_make(test_gl_basic_gles1_fwdcompat), \
821 unit_test_make(test_gl_basic_gles1_robust), \
822 unit_test_make(test_gl_basic_gles1_debug), \
823 unit_test_make(test_gl_basic_gles10), \
824 unit_test_make(test_gl_basic_gles11), \
826 unit_test_make(test_gl_basic_gles2_rgb), \
827 unit_test_make(test_gl_basic_gles2_rgba), \
828 unit_test_make(test_gl_basic_gles2_fwdcompat), \
829 unit_test_make(test_gl_basic_gles2_debug), \
830 unit_test_make(test_gl_basic_gles2_robust), \
831 unit_test_make(test_gl_basic_gles20), \
833 unit_test_make(test_gl_basic_gles3_rgb), \
834 unit_test_make(test_gl_basic_gles3_rgba), \
835 unit_test_make(test_gl_basic_gles3_fwdcompat), \
836 unit_test_make(test_gl_basic_gles3_debug), \
837 unit_test_make(test_gl_basic_gles3_robust), \
838 unit_test_make(test_gl_basic_gles30), \
839 unit_test_make(test_gl_basic_gles31), \
840 unit_test_make(test_gl_basic_gles32), \
844 return cmocka_run_group_tests_name(#platform, tests, NULL, NULL); \
848 // Most of the following tests will return ERROR_UNSUPPORTED_ON_PLATFORM
849 // on Apple/CGL, where NO_ERROR is expected.
850 // This is safe, as the test is skipped when the said error occurs.
852 // As BAD_ATTRIBUTE (core validation) takes greater precedence over
853 // UNSUPPORTED_ON_PLATFORM (platform specific one).
854 // Thus we're safe to use the former here, eventhough CGL has support
855 // for neither GLES* nor fwdcompa "CGL and everyone else".
859 // Quick notes which combinations we test and why
860 // - w/o version, for each API/profile combination check variations of
861 // - visual - make sure we can draw fine, duh
862 // - flags - flags selection machinery is funky
863 // - fwdcompat was introduced with OpenGL 3.0, check it and 3.1
864 // - specific version
865 // - all known versions
868 test_XX_rgb(gl
, OPENGL
, NO_ERROR
)
869 test_XX_rgba(gl
, OPENGL
, NO_ERROR
)
870 test_XX_fwdcompat(gl
, OPENGL
, ERROR_BAD_ATTRIBUTE
)
871 test_XX_debug(gl
, OPENGL
, NO_ERROR
)
872 test_XX_robust(gl
, OPENGL
, NO_ERROR
)
874 test_glXX(10, NO_ERROR
)
875 test_glXX(11, NO_ERROR
)
876 test_glXX(12, NO_ERROR
)
877 test_glXX(13, NO_ERROR
)
878 test_glXX(14, NO_ERROR
)
879 test_glXX(15, NO_ERROR
)
880 test_glXX(20, NO_ERROR
)
881 test_glXX(21, NO_ERROR
)
882 test_glXX(30, NO_ERROR
)
883 test_glXX_fwdcompat(30, NO_ERROR
)
884 test_glXX(31, NO_ERROR
)
885 test_glXX_fwdcompat(31, NO_ERROR
)
887 test_glXX_core(32, NO_ERROR
)
888 test_glXX_core_fwdcompat(32, NO_ERROR
)
889 test_glXX_core_debug(32, NO_ERROR
)
890 test_glXX_core_robust(32, NO_ERROR
)
891 test_glXX_core(33, NO_ERROR
)
892 test_glXX_core(40, NO_ERROR
)
893 test_glXX_core(41, NO_ERROR
)
894 test_glXX_core(42, NO_ERROR
)
895 test_glXX_core(43, NO_ERROR
)
896 test_glXX_core(44, NO_ERROR
)
897 test_glXX_core(45, NO_ERROR
)
898 test_glXX_core(46, NO_ERROR
)
900 test_glXX_compat(32, NO_ERROR
)
901 test_glXX_compat_fwdcompat(32, NO_ERROR
)
902 test_glXX_compat_debug(32, NO_ERROR
)
903 test_glXX_compat_robust(32, NO_ERROR
)
904 test_glXX_compat(33, NO_ERROR
)
905 test_glXX_compat(40, NO_ERROR
)
906 test_glXX_compat(41, NO_ERROR
)
907 test_glXX_compat(42, NO_ERROR
)
908 test_glXX_compat(43, NO_ERROR
)
909 test_glXX_compat(44, NO_ERROR
)
910 test_glXX_compat(45, NO_ERROR
)
911 test_glXX_compat(46, NO_ERROR
)
913 test_XX_rgb(gles1
, OPENGL_ES1
, NO_ERROR
)
914 test_XX_rgba(gles1
, OPENGL_ES1
, NO_ERROR
)
915 test_XX_fwdcompat(gles1
, OPENGL_ES1
, ERROR_BAD_ATTRIBUTE
)
916 test_XX_debug(gles1
, OPENGL_ES1
, NO_ERROR
)
917 test_XX_robust(gles1
, OPENGL_ES1
, NO_ERROR
)
918 test_glesXX(1, 10, NO_ERROR
)
919 test_glesXX(1, 11, NO_ERROR
)
921 test_XX_rgb(gles2
, OPENGL_ES2
, NO_ERROR
)
922 test_XX_rgba(gles2
, OPENGL_ES2
, NO_ERROR
)
923 test_XX_fwdcompat(gles2
, OPENGL_ES2
, ERROR_BAD_ATTRIBUTE
)
924 test_XX_debug(gles2
, OPENGL_ES2
, NO_ERROR
)
925 test_XX_robust(gles2
, OPENGL_ES2
, NO_ERROR
)
926 test_glesXX(2, 20, NO_ERROR
)
928 test_XX_rgb(gles3
, OPENGL_ES3
, NO_ERROR
)
929 test_XX_rgba(gles3
, OPENGL_ES3
, NO_ERROR
)
930 test_XX_fwdcompat(gles3
, OPENGL_ES3
, ERROR_BAD_ATTRIBUTE
)
931 test_XX_debug(gles3
, OPENGL_ES3
, NO_ERROR
)
932 test_XX_robust(gles3
, OPENGL_ES3
, NO_ERROR
)
933 test_glesXX(3, 30, NO_ERROR
)
934 test_glesXX(3, 31, NO_ERROR
)
935 test_glesXX(3, 32, NO_ERROR
)
938 #ifdef WAFFLE_HAS_CGL
940 #define unit_test_make(name) \
941 cmocka_unit_test_setup_teardown(name, setup_cgl, gl_basic_fini)
943 CREATE_TESTSUITE(WAFFLE_PLATFORM_CGL
, cgl
)
945 #undef unit_test_make
947 #endif // WAFFLE_HAS_CGL
949 #ifdef WAFFLE_HAS_GBM
951 #define unit_test_make(name) \
952 cmocka_unit_test_setup_teardown(name, setup_gbm, gl_basic_fini)
954 CREATE_TESTSUITE(WAFFLE_PLATFORM_GBM
, gbm
)
956 #undef unit_test_make
958 #endif // WAFFLE_HAS_GBM
960 #ifdef WAFFLE_HAS_GLX
962 #define unit_test_make(name) \
963 cmocka_unit_test_setup_teardown(name, setup_glx, gl_basic_fini)
965 CREATE_TESTSUITE(WAFFLE_PLATFORM_GLX
, glx
)
967 #undef unit_test_make
969 #endif // WAFFLE_HAS_GLX
971 #ifdef WAFFLE_HAS_SURFACELESS_EGL
973 #define unit_test_make(name) \
974 cmocka_unit_test_setup_teardown(name, setup_surfaceless_egl, gl_basic_fini)
976 CREATE_TESTSUITE(WAFFLE_PLATFORM_SURFACELESS_EGL
, surfaceless_egl
)
978 #undef unit_test_make
980 #endif // WAFFLE_HAS_SURFACELESS_EGL
982 #ifdef WAFFLE_HAS_WAYLAND
984 #define unit_test_make(name) \
985 cmocka_unit_test_setup_teardown(name, setup_wayland, gl_basic_fini)
987 CREATE_TESTSUITE(WAFFLE_PLATFORM_WAYLAND
, wayland
)
989 #undef unit_test_make
991 #endif // WAFFLE_HAS_WAYLAND
993 #ifdef WAFFLE_HAS_X11_EGL
995 #define unit_test_make(name) \
996 cmocka_unit_test_setup_teardown(name, setup_x11_egl, gl_basic_fini)
998 CREATE_TESTSUITE(WAFFLE_PLATFORM_X11_EGL
, x11_egl
)
1000 #undef unit_test_make
1002 #endif // WAFFLE_HAS_X11_EGL
1004 #ifdef WAFFLE_HAS_WGL
1006 #define unit_test_make(name) \
1007 cmocka_unit_test_setup_teardown(name, setup_wgl, gl_basic_fini)
1009 CREATE_TESTSUITE(WAFFLE_PLATFORM_WGL
, wgl
)
1011 #undef unit_test_make
1013 #endif // WAFFLE_HAS_WGL
1017 #undef test_glXX_compat_robust
1018 #undef test_glXX_compat_debug
1019 #undef test_glXX_compat_fwdcompat
1020 #undef test_glXX_compat
1021 #undef test_glXX_core_robust
1022 #undef test_glXX_core_debug
1023 #undef test_glXX_core_fwdcompat
1024 #undef test_glXX_core
1025 #undef test_glXX_fwdcompat
1028 #undef test_XX_robust
1029 #undef test_XX_debug
1030 #undef test_XX_fwdcompat
1037 removeArg(int index
, int *argc
, char **argv
)
1040 for (; index
< *argc
; ++index
)
1041 argv
[index
] = argv
[index
+ 1];
1045 removeXcodeArgs(int *argc
, char **argv
)
1047 // Xcode sometimes adds additional arguments.
1048 for (int i
= 1; i
< *argc
; )
1050 if (strcmp(argv
[i
], "-NSDocumentRevisionsDebugMode") == 0 ||
1051 strcmp(argv
[i
], "-ApplePersistenceIgnoreState" ) == 0)
1053 removeArg(i
, argc
, argv
);
1054 removeArg(i
, argc
, argv
);
1062 static const char *usage_message
=
1064 " gl_basic_test <Required Parameter> [Options]\n"
1067 " Run the basic functionality tests.\n"
1069 "Required Parameter:\n"
1071 " One of: cgl, gbm, glx, wayland, wgl or x11_egl\n"
1075 " Print gl_basic_test usage information.\n"
1078 #if defined(__GNUC__)
1079 #define NORETURN __attribute__((noreturn))
1080 #elif defined(_MSC_VER)
1081 #define NORETURN __declspec(noreturn)
1086 #if defined(__GNUC__)
1087 #define PRINTFLIKE(f, a) __attribute__((format(gnu_printf, f, a)))
1089 #define PRINTFLIKE(f, a)
1092 static void NORETURN
1093 write_usage_and_exit(FILE *f
, int exit_code
)
1095 fprintf(f
, "%s", usage_message
);
1104 static const struct option get_opts
[] = {
1105 { .name
= "platform", .has_arg
= required_argument
, .val
= OPT_PLATFORM
},
1106 { .name
= "help", .has_arg
= no_argument
, .val
= OPT_HELP
},
1110 static void NORETURN
PRINTFLIKE(1, 2)
1111 usage_error_printf(const char *fmt
, ...)
1114 fprintf(stderr
, "gl_basic_test usage error: ");
1119 vfprintf(stderr
, fmt
, ap
);
1121 fprintf(stderr
, " ");
1124 fprintf(stderr
, "(see gl_basic_test --help)\n");
1133 static const struct enum_map platform_map
[] = {
1134 {WAFFLE_PLATFORM_CGL
, "cgl", },
1135 {WAFFLE_PLATFORM_GBM
, "gbm" },
1136 {WAFFLE_PLATFORM_GLX
, "glx" },
1137 {WAFFLE_PLATFORM_WAYLAND
, "wayland" },
1138 {WAFFLE_PLATFORM_WGL
, "wgl" },
1139 {WAFFLE_PLATFORM_X11_EGL
, "x11_egl" },
1140 {WAFFLE_PLATFORM_SURFACELESS_EGL
, "surfaceless_egl" },
1141 {WAFFLE_PLATFORM_SURFACELESS_EGL
, "sl" },
1145 /// @brief Translate string to `enum waffle_enum`.
1147 /// @param self is a list of map items. The last item must be zero-filled.
1148 /// @param result is altered only if @a s if found.
1149 /// @return true if @a s was found in @a map.
1151 enum_map_translate_str(
1152 const struct enum_map
*self
,
1156 for (const struct enum_map
*i
= self
; i
->i
!= 0; ++i
) {
1157 if (!strncmp(s
, i
->s
, strlen(i
->s
) + 1)) {
1166 /// @return true on success.
1168 parse_args(int argc
, char *argv
[], int *out_platform
)
1171 bool loop_get_opt
= true;
1175 removeXcodeArgs(&argc
, argv
);
1178 // prevent getopt_long from printing an error message
1181 while (loop_get_opt
) {
1182 int opt
= getopt_long(argc
, argv
, "hp:", get_opts
, NULL
);
1185 loop_get_opt
= false;
1188 goto error_unrecognized_arg
;
1190 ok
= enum_map_translate_str(platform_map
, optarg
, &platform
);
1192 usage_error_printf("'%s' is not a valid platform",
1197 write_usage_and_exit(stdout
, EXIT_SUCCESS
);
1200 loop_get_opt
= false;
1205 if (optind
< argc
) {
1206 goto error_unrecognized_arg
;
1210 usage_error_printf("--platform is required");
1213 *out_platform
= platform
;
1216 error_unrecognized_arg
:
1218 usage_error_printf("unrecognized option '%s'", optarg
);
1220 usage_error_printf("unrecognized option '-%c'", optopt
);
1222 usage_error_printf("unrecognized option");
1226 main(int argc
, char *argv
[])
1231 ok
= parse_args(argc
, argv
, &platform
);
1236 #ifdef WAFFLE_HAS_CGL
1237 case WAFFLE_PLATFORM_CGL
:
1238 return testsuite_cgl();
1240 #ifdef WAFFLE_HAS_GBM
1241 case WAFFLE_PLATFORM_GBM
:
1242 return testsuite_gbm();
1244 #ifdef WAFFLE_HAS_GLX
1245 case WAFFLE_PLATFORM_GLX
:
1246 return testsuite_glx();
1248 #ifdef WAFFLE_HAS_SURFACELESS_EGL
1249 case WAFFLE_PLATFORM_SURFACELESS_EGL
:
1250 return testsuite_surfaceless_egl();
1252 #ifdef WAFFLE_HAS_WAYLAND
1253 case WAFFLE_PLATFORM_WAYLAND
:
1254 return testsuite_wayland();
1256 #ifdef WAFFLE_HAS_WGL
1257 case WAFFLE_PLATFORM_WGL
:
1258 return testsuite_wgl();
1260 #ifdef WAFFLE_HAS_X11_EGL
1261 case WAFFLE_PLATFORM_X11_EGL
:
1262 return testsuite_x11_egl();