Fix crash starting game engine on linux
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 3 Oct 2013 13:15:53 +0000 (13:15 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 3 Oct 2013 13:15:53 +0000 (13:15 +0000)
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.

intern/ghost/intern/GHOST_WindowX11.cpp

index 25c74a0a6cb401d09df7db56c7a0d6ddaf3e7860..3e6e1cd1a94a7c1998f063ef2c319e592490e2e1 100644 (file)
@@ -65,6 +65,14 @@ typedef struct {
        long input_mode;
 } 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)
 
 
@@ -1519,18 +1527,67 @@ endFullScreen() const
 GHOST_TSuccess
 GHOST_WindowX11::
 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;
+       }
        glXSwapIntervalEXT(m_display, m_window, interval);
        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
 GHOST_WindowX11::
 getSwapInterval() {
        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);
+
+#ifdef SWAP_INTERVALS_WORKAROUND
+               /* Restore handler */
+               (void) XSetErrorHandler(old_handler);
+               (void) XSetIOErrorHandler(old_handler_io);
+#endif  // SWAP_INTERVALS_WORKAROUND
+
                return (int)value;
        }
        return 0;