2 * Copyright 2012 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29 #include "piglit_glut_framework.h"
30 #include "piglit-util-gl.h"
32 struct piglit_glut_framework
{
33 struct piglit_gl_framework gl_fw
;
35 enum piglit_result result
;
40 * This global variable exists because GLUT's API requires that data be passed
41 * to the display function via a global. Ugh, GLUT is such an awful API.
43 static struct piglit_glut_framework glut_fw
;
46 destroy(struct piglit_gl_framework
*gl_fw
)
48 piglit_gl_framework_teardown(gl_fw
);
57 /* Catch any exceptions and abort immediately.
59 * At least with certain implementations of GLUT (namely
60 * freeglut-2.8.1), the glutDisplayFunc()'s callback called inside a
61 * WindowProc callback function.
63 * And on certain cases (depending on the Windows version and 32 vs 64
64 * bits processes) uncaught exceptions inside WindowProc callbacks are
65 * silently ignored! (See Remarks section of
66 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms633573.aspx
67 * page.) The end result is that automatic tests end up blocking
68 * waiting for user input when an uncaught exceptionhappens, as control
69 * flow is interrupted before it reaches piglit_report_result(), and
70 * the process never aborts.
72 * By installing our own exception handler we can ensure that uncaught
73 * exceptions will never be silently ignored.
75 * NOTE: SetUnhandledExceptionFilter does not work here, as some Windows
76 * versions never call the unhandled exception filter. We must use MSVC
77 * __try/__except statements, or in MinGW, the __try1/__except1 macros.
80 exception_filter(PEXCEPTION_POINTERS pExceptionInfo
)
82 PEXCEPTION_RECORD pExceptionRecord
= pExceptionInfo
->ExceptionRecord
;
85 fprintf(stderr
, "error: caught unhandled exception 0x%08lx\n", pExceptionRecord
->ExceptionCode
);
88 _exit(pExceptionRecord
->ExceptionCode
);
93 // http://www.programmingunlimited.net/siteexec/content.cgi?page=mingw-seh
94 // http://www.microsoft.com/msj/0197/exception/exception.aspx
96 exception_handler(struct _EXCEPTION_RECORD
*ExceptionRecord
, void *EstablisherFrame
, struct _CONTEXT
*ContextRecord
, void *DispatcherContext
)
98 EXCEPTION_POINTERS ExceptionInfo
= {ExceptionRecord
, ContextRecord
};
99 switch (exception_filter(&ExceptionInfo
)) {
100 case EXCEPTION_EXECUTE_HANDLER
:
101 return ExceptionExecuteHandler
;
102 case EXCEPTION_CONTINUE_SEARCH
:
103 return ExceptionContinueSearch
;
104 case EXCEPTION_CONTINUE_EXECUTION
:
105 return ExceptionContinueExecution
;
107 return ExceptionContinueSearch
;
111 # define TRY __try1(exception_handler);
112 # define CATCH_ALL __except1;
117 # define CATCH_ALL } __except(exception_filter(GetExceptionInformation())) {}
132 const struct piglit_gl_test_config
*test_config
= glut_fw
.gl_fw
.test_config
;
136 if (test_config
->display
)
137 glut_fw
.result
= test_config
->display();
141 if (piglit_automatic
) {
142 glutDestroyWindow(glut_fw
.window
);
144 /* Tell GLUT to clean up and exit, so that we can
145 * reasonably valgrind our testcases for memory
148 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE
,
149 GLUT_ACTION_GLUTMAINLOOP_RETURNS
);
152 piglit_report_result(glut_fw
.result
);
158 default_reshape_func(int w
, int h
)
160 if (piglit_automatic
&&
161 (w
!= piglit_width
||
162 h
!= piglit_height
)) {
163 printf("Got spurious window resize in automatic run "
164 "(%d,%d to %d,%d)\n", piglit_width
, piglit_height
, w
, h
);
165 piglit_report_result(PIGLIT_WARN
);
171 glViewport(0, 0, w
, h
);
175 error_func(const char *fmt
, va_list ap
)
177 vfprintf(stderr
, fmt
, ap
);
178 fprintf(stderr
, "\n");
179 piglit_report_result(PIGLIT_SKIP
);
185 const struct piglit_gl_test_config
*test_config
= glut_fw
.gl_fw
.test_config
;
186 char *argv
[] = {"piglit"};
188 unsigned flags
= GLUT_RGB
;
190 if (test_config
->window_visual
& PIGLIT_GL_VISUAL_RGBA
)
192 if (test_config
->window_visual
& PIGLIT_GL_VISUAL_DEPTH
)
194 if (test_config
->window_visual
& PIGLIT_GL_VISUAL_STENCIL
)
195 flags
|= GLUT_STENCIL
;
196 if (test_config
->window_visual
& PIGLIT_GL_VISUAL_ACCUM
)
199 if (test_config
->window_visual
& PIGLIT_GL_VISUAL_DOUBLE
)
200 flags
|= GLUT_DOUBLE
;
202 flags
|= GLUT_SINGLE
;
207 * This will request a core profile. It will always return the highest
211 * /System/Library/Frameworks/GLUT.framework/Headers/glut.h
212 * https://developer.apple.com/opengl/capabilities/
214 #if GLUT_MACOSX_IMPLEMENTATION >= 4
215 if (test_config
->supports_gl_core_version
>= 31) {
216 flags
|= GLUT_3_2_CORE_PROFILE
;
220 glutInit(&argc
, argv
);
221 glutInitWindowPosition(0, 0);
222 glutInitWindowSize(test_config
->window_width
,
223 test_config
->window_height
);
224 glutInitDisplayMode(flags
);
229 #ifdef PIGLIT_USE_GLUT_INIT_ERROR_FUNC
230 glutInitErrorFunc(error_func
);
234 #ifdef GLUT_CORE_PROFILE
235 if (test_config
->supports_gl_core_version
) {
236 glutInitContextVersion(test_config
->supports_gl_core_version
/ 10,
237 test_config
->supports_gl_core_version
% 10);
238 if (test_config
->supports_gl_core_version
>= 32) {
239 glutInitContextProfile(GLUT_CORE_PROFILE
);
242 glutInitContextVersion(test_config
->supports_gl_compat_version
/ 10,
243 test_config
->supports_gl_compat_version
% 10);
244 if (test_config
->supports_gl_compat_version
>= 32) {
245 glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE
);
249 int context_flags
= 0;
250 /* There are no 3.1 core profiles -- the closest is 3.1 context without
251 * ARB_compatibility or a 3.2 core context --, and setting
252 * forward-compatible flag should ensure we don't get a 3.1 context w/
255 if (test_config
->require_forward_compatible_context
||
256 test_config
->supports_gl_core_version
== 31) {
257 context_flags
|= GLUT_FORWARD_COMPATIBLE
;
259 if (test_config
->require_debug_context
) {
260 context_flags
|= GLUT_DEBUG
;
263 glutInitContextFlags(context_flags
);
267 glut_fw
.window
= glutCreateWindow("Piglit");
269 glutDisplayFunc(display
);
270 glutReshapeFunc(default_reshape_func
);
271 glutKeyboardFunc(piglit_escape_exit_key
);
273 #ifdef PIGLIT_USE_OPENGL
274 piglit_dispatch_default_init(PIGLIT_DISPATCH_GL
);
279 run_test(struct piglit_gl_framework
*gl_fw
,
280 int argc
, char *argv
[])
282 const struct piglit_gl_test_config
*test_config
= glut_fw
.gl_fw
.test_config
;
284 if (test_config
->init
)
285 test_config
->init(argc
, argv
);
288 piglit_report_result(glut_fw
.result
);
292 swap_buffers(struct piglit_gl_framework
*gl_fw
)
298 post_redisplay(struct piglit_gl_framework
*gl_fw
)
304 set_keyboard_func(struct piglit_gl_framework
*gl_fw
,
305 void (*func
)(unsigned char key
, int x
, int y
))
307 glutKeyboardFunc(func
);
311 set_reshape_func(struct piglit_gl_framework
*gl_fw
,
312 void (*func
)(int w
, int h
))
314 glutReshapeFunc(func
);
318 * Check that the context's actual version is no less than the
322 check_gl_version(const struct piglit_gl_test_config
*test_config
)
324 int actual_version
= piglit_get_gl_version();
326 if (test_config
->supports_gl_core_version
) {
327 if (actual_version
< test_config
->supports_gl_core_version
) {
328 printf("Test requires GL version %d.%d, but actual version is "
330 test_config
->supports_gl_core_version
/ 10,
331 test_config
->supports_gl_core_version
% 10,
333 actual_version
% 10);
339 if (actual_version
< test_config
->supports_gl_compat_version
) {
340 printf("Test requires GL version %d.%d, but actual version is "
342 test_config
->supports_gl_compat_version
/ 10,
343 test_config
->supports_gl_compat_version
% 10,
345 actual_version
% 10);
349 if (piglit_is_core_profile
&&
350 test_config
->supports_gl_core_version
== 0) {
351 /* We have a core profile context but the test needs a
352 * compat profile. We can't run the test.
354 printf("Test requires compat version %d.%d or later but "
355 "context is core profile %d.%d.\n",
356 test_config
->supports_gl_compat_version
/ 10,
357 test_config
->supports_gl_compat_version
% 10,
359 actual_version
% 10);
366 struct piglit_gl_framework
*
367 piglit_glut_framework_create(const struct piglit_gl_test_config
*test_config
)
371 #if !defined(GLUT_CORE_PROFILE) && \
372 (!defined(GLUT_MACOSX_IMPLEMENTATION) || GLUT_MACOSX_IMPLEMENTATION < 4)
373 if (!test_config
->supports_gl_compat_version
) {
374 printf("GLUT can create only GL compatibility contexts, "
375 "which the test does not support running under.\n");
376 piglit_report_result(PIGLIT_SKIP
);
380 if (test_config
->window_samples
> 1) {
381 printf("GLUT doesn't support MSAA visuals.\n");
382 piglit_report_result(PIGLIT_SKIP
);
385 ok
= piglit_gl_framework_init(&glut_fw
.gl_fw
, test_config
);
391 /* Check if we actually have a core profile */
393 int actual_version
= piglit_get_gl_version();
395 piglit_is_core_profile
=
396 actual_version
>= 31 &&
397 !piglit_is_extension_supported("GL_ARB_compatibility");
400 if (!check_gl_version(test_config
))
401 piglit_report_result(PIGLIT_SKIP
);
403 glut_fw
.gl_fw
.swap_buffers
= swap_buffers
;
404 glut_fw
.gl_fw
.run_test
= run_test
;
405 glut_fw
.gl_fw
.post_redisplay
= post_redisplay
;
406 glut_fw
.gl_fw
.set_keyboard_func
= set_keyboard_func
;
407 glut_fw
.gl_fw
.set_reshape_func
= set_reshape_func
;
408 glut_fw
.gl_fw
.destroy
= destroy
;
410 return &glut_fw
.gl_fw
;