Workaround for NVIDIA bug in glXSwapIntervalEXT.
authorSam Lantinga <slouken@libsdl.org>
Mon, 11 Feb 2013 17:02:13 -0800
changeset 6846 97eb26e2dee0
parent 6845 e14535915e3e
child 6847 c0fa29d3fade
Workaround for NVIDIA bug in glXSwapIntervalEXT. This works around a bug in NVIDIA's implementation of glXSwapIntervalEXT, where it ignores updates to what it *thinks* is the current value, even though glXQueryDrawable returns a different value. Bug reported to NVIDIA and will hopefully be a part of 319.xx. Also a fix for invalidly treating glXSwapIntervalEXT as having an int return value (it's void).
build-scripts/ltmain.sh
src/video/x11/SDL_x11opengl.c
src/video/x11/SDL_x11opengl.h
--- a/src/video/x11/SDL_x11opengl.c	Mon Feb 11 16:51:00 2013 -0800
+++ b/src/video/x11/SDL_x11opengl.c	Mon Feb 11 17:02:13 2013 -0800
@@ -332,7 +332,7 @@
     _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
     if (HasExtension("GLX_EXT_swap_control", extensions)) {
         _this->gl_data->glXSwapIntervalEXT =
-            (int (*)(Display*,GLXDrawable,int))
+            (void (*)(Display*,GLXDrawable,int))
                 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
         if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
             _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
@@ -667,13 +667,23 @@
         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
         const SDL_WindowData *windowdata = (SDL_WindowData *)
             _this->current_glwin->driverdata;
+
         Window drawable = windowdata->xwindow;
-        status = _this->gl_data->glXSwapIntervalEXT(display,drawable,interval);
-        if (status != 0) {
-            SDL_SetError("glxSwapIntervalEXT failed");
-        } else {
-            swapinterval = interval;
-        }
+
+        /*
+         * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
+         * and will be fixed in a future release (probably 319.xx).
+         *
+         * There's a bug where glXSetSwapIntervalEXT ignores updates because
+         * it has the wrong value cached. To work around it, we just run a no-op
+         * update to the current value.
+         */
+        int currentInterval = _this, X11_GL_GetSwapInterval(_this);
+        _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
+        _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
+
+        status = 0;
+        swapinterval = interval;
     } else if (_this->gl_data->glXSwapIntervalMESA) {
         status = _this->gl_data->glXSwapIntervalMESA(interval);
         if (status != 0) {
--- a/src/video/x11/SDL_x11opengl.h	Mon Feb 11 16:51:00 2013 -0800
+++ b/src/video/x11/SDL_x11opengl.h	Mon Feb 11 17:02:13 2013 -0800
@@ -40,7 +40,7 @@
     Bool(*glXMakeCurrent) (Display*,GLXDrawable,GLXContext);
     void (*glXSwapBuffers) (Display*, GLXDrawable);
     void (*glXQueryDrawable) (Display*,GLXDrawable,int,unsigned int*);
-    int (*glXSwapIntervalEXT) (Display*,GLXDrawable,int);
+    void (*glXSwapIntervalEXT) (Display*,GLXDrawable,int);
     int (*glXSwapIntervalSGI) (int);
     int (*glXSwapIntervalMESA) (int);
     int (*glXGetSwapIntervalMESA) (void);