Fix crash starting game engine on linux

Issue was caused by bug in mesa #54080 which makes
glXQueryDrawable fail with GLXBadDrawable for any
request with direct context.

Worked around by temporary overriding X error handling
when getting old interval value and disablingintervals
extension if this query fails.

Also added check for glXSwapIntervalEXT which is
apparently NULL here with GLX_EXT_swap_control=1.
This commit is contained in:
Sergey Sharybin 2013-10-03 13:15:53 +00:00
parent 9b1be7ce93
commit 94fdaa5d41

@ -65,6 +65,14 @@ typedef struct {
long input_mode; long input_mode;
} MotifWmHints; } MotifWmHints;
// Workaround for MESA bug #54080
// https://bugs.freedesktop.org/show_bug.cgi?id=54080()
#define SWAP_INTERVALS_WORKAROUND
#ifdef SWAP_INTERVALS_WORKAROUND
static bool g_swap_interwal_disabled = false;
#endif // SWAP_INTERVALS_WORKAROUND
#define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_DECORATIONS (1L << 1)
@ -1519,18 +1527,67 @@ endFullScreen() const
GHOST_TSuccess GHOST_TSuccess
GHOST_WindowX11:: GHOST_WindowX11::
setSwapInterval(int interval) { setSwapInterval(int interval) {
if (!GLX_EXT_swap_control) if (!GLX_EXT_swap_control || !glXSwapIntervalEXT
#ifdef SWAP_INTERVALS_WORKAROUND
|| g_swap_interwal_disabled
#endif // SWAP_INTERVALS_WORKAROUND
)
{
return GHOST_kFailure; return GHOST_kFailure;
}
glXSwapIntervalEXT(m_display, m_window, interval); glXSwapIntervalEXT(m_display, m_window, interval);
return GHOST_kSuccess; return GHOST_kSuccess;
} }
#ifdef SWAP_INTERVALS_WORKAROUND
static int QueryDrawable_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
{
fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n",
theEvent->error_code, theEvent->request_code);
if (!g_swap_interwal_disabled) {
fprintf(stderr, "Disabling SWAP INTERVALS extension\n");
g_swap_interwal_disabled = true;
}
return 0;
}
static int QueryDrawable_ApplicationIOErrorHandler(Display *display)
{
fprintf(stderr, "Ignoring Xlib error: error IO\n");
if (!g_swap_interwal_disabled) {
fprintf(stderr, "Disabling SWAP INTERVALS extension\n");
g_swap_interwal_disabled = true;
}
return 0;
}
#endif // SWAP_INTERVALS_WORKAROUND
int int
GHOST_WindowX11:: GHOST_WindowX11::
getSwapInterval() { getSwapInterval() {
if (GLX_EXT_swap_control) { if (GLX_EXT_swap_control) {
unsigned int value; #ifdef SWAP_INTERVALS_WORKAROUND
/* XXX: Current MESA driver will give GLXBadDrawable for all
* the glXQueryDrawable requests with direct contexts.
*
* To prevent crashes and unexpected behaviors, we will
* disable swap interwals extension if query fails here.
* (because if we will override interval without having
* old value we couldn't restore it properly).
*/
XErrorHandler old_handler = XSetErrorHandler(QueryDrawable_ApplicationErrorHandler);
XIOErrorHandler old_handler_io = XSetIOErrorHandler(QueryDrawable_ApplicationIOErrorHandler);
#endif // SWAP_INTERVALS_WORKAROUND
unsigned int value = 0;
glXQueryDrawable(m_display, m_window, GLX_SWAP_INTERVAL_EXT, &value); glXQueryDrawable(m_display, m_window, GLX_SWAP_INTERVAL_EXT, &value);
#ifdef SWAP_INTERVALS_WORKAROUND
/* Restore handler */
(void) XSetErrorHandler(old_handler);
(void) XSetIOErrorHandler(old_handler_io);
#endif // SWAP_INTERVALS_WORKAROUND
return (int)value; return (int)value;
} }
return 0; return 0;