2 * Copyright © 2009 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
24 * Eric Anholt <eric@anholt.net>
28 #include "piglit-util-gl.h"
29 #include "piglit-glx-util.h"
32 __attribute__((weak
)) int piglit_width
= 100;
33 __attribute__((weak
)) int piglit_height
= 100;
37 piglit_get_glx_display()
41 dpy
= XOpenDisplay(NULL
);
43 fprintf(stderr
, "couldn't open display\n");
44 piglit_report_result(PIGLIT_FAIL
);
51 piglit_get_glx_visual(Display
*dpy
)
64 int screen
= DefaultScreen(dpy
);
66 visinfo
= glXChooseVisual(dpy
, screen
, attrib
);
67 if (visinfo
== NULL
) {
69 "Couldn't get an RGBA, double-buffered visual\n");
70 piglit_report_result(PIGLIT_FAIL
);
77 piglit_get_glx_context(Display
*dpy
, XVisualInfo
*visinfo
)
79 return piglit_get_glx_context_share(dpy
, visinfo
, NULL
);
83 piglit_get_glx_context_share(Display
*dpy
, XVisualInfo
*visinfo
, GLXContext share
)
87 ctx
= glXCreateContext(dpy
, visinfo
, share
, True
);
89 fprintf(stderr
, "glXCreateContext failed\n");
90 piglit_report_result(PIGLIT_FAIL
);
97 _piglit_get_glx_window(Display
*dpy
, XVisualInfo
*visinfo
, bool map
, bool fullscreen
)
99 XSetWindowAttributes window_attr
;
101 int screen
= DefaultScreen(dpy
);
102 Window root_win
= RootWindow(dpy
, screen
);
105 window_attr
.background_pixel
= 0;
106 window_attr
.border_pixel
= 0;
107 window_attr
.colormap
= XCreateColormap(dpy
, root_win
,
108 visinfo
->visual
, AllocNone
);
109 window_attr
.event_mask
= StructureNotifyMask
| ExposureMask
|
111 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
114 window_attr
.override_redirect
= True
;
115 mask
|= CWOverrideRedirect
;
116 piglit_width
= DisplayWidth(dpy
, screen
);
117 piglit_height
= DisplayHeight(dpy
, screen
);
120 win
= XCreateWindow(dpy
, root_win
, 0, 0,
121 piglit_width
, piglit_height
,
122 0, visinfo
->depth
, InputOutput
,
123 visinfo
->visual
, mask
, &window_attr
);
125 if (piglit_automatic
)
126 piglit_glx_window_set_no_input(dpy
, win
);
129 XMapWindow(dpy
, win
);
135 piglit_get_glx_window_unmapped(Display
*dpy
, XVisualInfo
*visinfo
)
137 return _piglit_get_glx_window(dpy
, visinfo
, false, false);
141 piglit_get_glx_window_fullscreen(Display
*dpy
, XVisualInfo
*visinfo
)
143 return _piglit_get_glx_window(dpy
, visinfo
, true, true);
147 piglit_get_glx_window(Display
*dpy
, XVisualInfo
*visinfo
)
149 return _piglit_get_glx_window(dpy
, visinfo
, true, false);
153 piglit_is_glx_extension_supported(Display
*dpy
, const char *name
)
155 int screen
= DefaultScreen(dpy
);
156 const char *const glx_extension_list
=
157 glXQueryExtensionsString(dpy
, screen
);
159 return piglit_is_extension_in_string(glx_extension_list
, name
);
163 piglit_require_glx_extension(Display
*dpy
, const char *name
)
165 if (!piglit_is_glx_extension_supported(dpy
, name
)) {
166 fprintf(stderr
, "Test requires %s\n", name
);
167 piglit_report_result(PIGLIT_SKIP
);
173 piglit_require_glx_version(Display
*dpy
, int major
, int minor
)
178 if (! glXQueryVersion(dpy
, & glxMajor
, & glxMinor
)) {
179 fprintf(stderr
, "Could not query GLX version!\n");
180 piglit_report_result(PIGLIT_FAIL
);
183 if (glxMajor
!= major
|| glxMinor
< minor
) {
184 fprintf(stderr
, "Test requires GLX %d.%d. Got %d.%d.\n",
185 major
, minor
, glxMajor
, glxMinor
);
186 piglit_report_result(PIGLIT_SKIP
);
192 piglit_glx_event_loop(Display
*dpy
, enum piglit_result (*draw
)(Display
*dpy
))
196 XNextEvent (dpy
, &event
);
198 if (event
.type
== KeyPress
) {
199 int keysyms_per_keycode_return
;
200 KeySym
*sym
= XGetKeyboardMapping (dpy
,
203 &keysyms_per_keycode_return
);
205 if (sym
[0] == XK_Escape
|| sym
[0] == XK_q
|| sym
[0] == XK_Q
)
209 } else if (event
.type
== Expose
) {
210 enum piglit_result result
= draw(dpy
);
212 if (piglit_automatic
) {
214 * Rerun if we have failed and have a
215 * pending expose event, which might be an
216 * indication of invalid front buffer
219 if (result
== PIGLIT_FAIL
&&
220 XCheckTypedEvent(dpy
, Expose
, &event
)) {
222 "Pending expose event- "
224 XPutBackEvent(dpy
, &event
);
228 piglit_report_result(result
);
236 static enum piglit_result
237 piglit_iterate_visuals_event_loop(Display
*dpy
,
238 enum piglit_result (*draw
)(Display
*dpy
,
244 XNextEvent (dpy
, &event
);
246 if (event
.type
== Expose
) {
247 return draw(dpy
, config
);
253 piglit_glx_window_set_no_input(Display
*dpy
, GLXDrawable win
)
256 hints
= XAllocWMHints();
257 hints
->flags
|= InputHint
;
258 hints
->input
= False
;
260 XSetWMHints(dpy
, win
, hints
);
266 piglit_glx_set_no_input(void)
271 d
= glXGetCurrentDisplay();
272 win
= glXGetCurrentDrawable();
274 piglit_glx_window_set_no_input(d
, win
);
278 piglit_glx_iterate_pixmap_fbconfigs(enum piglit_result (*draw
)(Display
*dpy
,
282 GLXFBConfig
*configs
;
285 bool any_fail
= false;
286 bool any_pass
= false;
288 int *depths
, n_depths
;
290 Display
*dpy
= XOpenDisplay(NULL
);
292 fprintf(stderr
, "couldn't open display\n");
293 piglit_report_result(PIGLIT_FAIL
);
295 screen
= DefaultScreen(dpy
);
296 root_win
= RootWindow(dpy
, screen
);
297 depths
= XListDepths(dpy
, screen
, &n_depths
);
299 configs
= glXGetFBConfigs(dpy
, screen
, &n_configs
);
301 fprintf(stderr
, "No GLX FB configs\n");
302 piglit_report_result(PIGLIT_SKIP
);
305 for (i
= 0; i
< n_configs
; i
++) {
306 GLXFBConfig config
= configs
[i
];
307 enum piglit_result result
;
314 glXGetFBConfigAttrib(dpy
, config
, GLX_DRAWABLE_TYPE
,
317 if (!(draw_types
& GLX_PIXMAP_BIT
))
320 glXGetFBConfigAttrib(dpy
, config
, GLX_BUFFER_SIZE
,
323 /* Ensure XCreatePixmap will succeed */
324 for (j
= 0; j
< n_depths
; j
++)
325 if (depths
[j
] == depth
)
329 glXGetFBConfigAttrib(dpy
, config
, GLX_FBCONFIG_ID
, &id
);
330 fprintf(stderr
, "fbconfig %d has GLX_PIXMAP_BIT but there "
331 "is no pixmap format for depth %d, this "
332 "is a server bug\n", id
, depth
);
337 ctx
= glXCreateNewContext(dpy
, config
, GLX_RGBA_TYPE
,
339 pix
= XCreatePixmap(dpy
, root_win
,
340 piglit_width
, piglit_height
, depth
);
341 glx_pix
= glXCreatePixmap(dpy
, config
, pix
, NULL
);
342 glXMakeCurrent(dpy
, glx_pix
, ctx
);
344 result
= draw(dpy
, config
);
346 if (result
== PIGLIT_FAIL
)
348 else if (result
== PIGLIT_PASS
)
351 XFreePixmap(dpy
, pix
);
352 glXDestroyContext(dpy
, ctx
);
367 piglit_glx_iterate_visuals(enum piglit_result (*draw
)(Display
*dpy
,
371 GLXFBConfig
*configs
;
374 bool any_fail
= false;
375 bool any_pass
= false;
377 Display
*dpy
= XOpenDisplay(NULL
);
379 fprintf(stderr
, "couldn't open display\n");
380 piglit_report_result(PIGLIT_FAIL
);
382 screen
= DefaultScreen(dpy
);
384 configs
= glXGetFBConfigs(dpy
, screen
, &n_configs
);
386 fprintf(stderr
, "No GLX FB configs\n");
387 piglit_report_result(PIGLIT_SKIP
);
390 for (i
= 0; i
< n_configs
; i
++) {
391 enum piglit_result result
;
392 XVisualInfo
*visinfo
;
396 visinfo
= glXGetVisualFromFBConfig(dpy
, configs
[i
]);
400 ctx
= piglit_get_glx_context(dpy
, visinfo
);
401 d
= piglit_get_glx_window(dpy
, visinfo
);
402 glXMakeCurrent(dpy
, d
, ctx
);
405 result
= piglit_iterate_visuals_event_loop(dpy
, draw
,
407 if (result
== PIGLIT_FAIL
)
409 else if (result
== PIGLIT_PASS
)
412 XDestroyWindow(dpy
, d
);
413 glXDestroyContext(dpy
, ctx
);
427 piglit_glx_get_fbconfig_for_visinfo(Display
*dpy
, XVisualInfo
*visinfo
)
430 GLXFBConfig ret
= None
, *configs
;
432 configs
= glXGetFBConfigs(dpy
, visinfo
->screen
, &nconfigs
);
436 for (i
= 0; i
< nconfigs
; i
++) {
439 if (glXGetFBConfigAttrib(dpy
, configs
[i
], GLX_VISUAL_ID
, &v
))
442 if (v
== visinfo
->visualid
) {
453 * If you use this in an X error handler - and you will - pre-call it as:
454 * piglit_glx_get_error(dpy, NULL);
455 * outside the error handler to cache errbase. Otherwise this will
456 * generate protocol, and you'll deadlock.
458 * Returns -1 if the error is not a GLX error, otherwise returns the
462 piglit_glx_get_error(Display
*dpy
, XErrorEvent
*err
)
464 static int errbase
, evbase
;
467 glXQueryExtension(dpy
, &errbase
, &evbase
);
472 if (err
->error_code
< errbase
||
473 err
->error_code
> errbase
+ GLXBadProfileARB
)
476 return err
->error_code
- errbase
;
480 * Convert a GLX error code to a printable string
482 * \sa piglit_glx_get_error
485 piglit_glx_error_string(int err
)
487 static const char *const error_table
[] = {
489 "GLXBadContextState",
493 "GLXBadCurrentWindow",
494 "GLXBadRenderRequest",
495 "GLXBadLargeRequest",
496 "GLXUnsupportedPrivateRequest",
499 "GLXBadCurrentDrawable",
505 return "non-GLX error";
506 } else if (err
>= ARRAY_SIZE(error_table
)) {
507 return "unknown GLX error";
509 return error_table
[err
];
514 * Get the procedure addresses for a group of function names
517 * If any call to \c glXGetProcAddress fails, this function will call
518 * \c piglit_report_result with \c PIGLIT_FAIL.
521 piglit_glx_get_all_proc_addresses(const struct piglit_glx_proc_reference
*procedures
,
526 for (i
= 0; i
< num
; i
++) {
527 *procedures
[i
].procedure
=
528 glXGetProcAddress((const GLubyte
*) procedures
[i
].name
);
529 if (*procedures
[i
].procedure
== NULL
) {
531 "Failed to get function pointer for %s.\n",
533 piglit_report_result(PIGLIT_FAIL
);